]> granicus.if.org Git - clang/commitdiff
Begin tracking trivialness of move constructors and move assignment
authorChandler Carruth <chandlerc@gmail.com>
Sat, 23 Apr 2011 23:10:33 +0000 (23:10 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sat, 23 Apr 2011 23:10:33 +0000 (23:10 +0000)
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

include/clang/AST/DeclCXX.h
lib/AST/DeclCXX.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
test/SemaCXX/type-traits.cpp

index dfd3bd6e262243519ab982342f568ea1cbfb583b..946f3a30006baf2be1a6bc690fe9be350337be1c 100644 (file)
@@ -319,28 +319,63 @@ class CXXRecordDecl : public RecordDecl {
     /// HasTrivialCopyConstructor - True when this class has a trivial copy
     /// constructor.
     ///
-    /// C++ [class.copy]p6.  A copy constructor for class X is trivial
-    /// if it is implicitly declared and if
-    /// * class X has no virtual functions and no virtual base classes, and
-    /// * each direct base class of X has a trivial copy constructor, and
-    /// * for all the nonstatic data members of X that are of class type (or
-    ///   array thereof), each such class type has a trivial copy constructor;
-    /// otherwise the copy constructor is non-trivial.
+    /// 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
+    ///    -- 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 an
+    ///       array thereof), the constructor selected to copy/move that member
+    ///       is trivial;
+    ///   otherwise the copy/move constructor is non-trivial.
     bool HasTrivialCopyConstructor : 1;
 
+    /// HasTrivialMoveConstructor - True when this class has a trivial move
+    /// constructor.
+    ///
+    /// 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
+    ///    -- 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 an
+    ///       array thereof), the constructor selected to copy/move that member
+    ///       is trivial;
+    ///   otherwise the copy/move constructor is non-trivial.
+    bool HasTrivialMoveConstructor : 1;
+
     /// HasTrivialCopyAssignment - True when this class has a trivial copy
     /// assignment operator.
     ///
-    /// C++ [class.copy]p11.  A copy assignment operator for class X is
-    /// trivial if it is implicitly declared and if
-    /// * class X has no virtual functions and no virtual base classes, and
-    /// * each direct base class of X has a trivial copy assignment operator, and
-    /// * for all the nonstatic data members of X that are of class type (or
-    ///   array thereof), each such class type has a trivial copy assignment
-    ///   operator;
-    /// otherwise the copy assignment operator is non-trivial.
+    /// 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
+    ///    -- 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 an
+    ///       array thereof), the assignment operator selected to copy/move
+    ///       that member is trivial;
+    ///   otherwise the copy/move assignment operator is non-trivial.
     bool HasTrivialCopyAssignment : 1;
 
+    /// HasTrivialMoveAssignment - True when this class has a trivial 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 and if
+    ///    -- class X has no virtual functions and no virtual base classes, 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 an
+    ///       array thereof), the assignment operator selected to copy/move
+    ///       that member is trivial;
+    ///   otherwise the copy/move assignment operator is non-trivial.
+    bool HasTrivialMoveAssignment : 1;
+
     /// HasTrivialDestructor - True when this class has a trivial destructor.
     ///
     /// C++ [class.dtor]p3.  A destructor is trivial if it is an
@@ -726,17 +761,29 @@ public:
   bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
 
   // hasTrivialCopyConstructor - Whether this class has a trivial copy
-  // constructor (C++ [class.copy]p6)
+  // constructor (C++ [class.copy]p6, C++0x [class.copy]p13)
   bool hasTrivialCopyConstructor() const {
     return data().HasTrivialCopyConstructor;
   }
 
+  // hasTrivialMoveConstructor - Whether this class has a trivial move
+  // constructor (C++0x [class.copy]p13)
+  bool hasTrivialMoveConstructor() const {
+    return data().HasTrivialMoveConstructor;
+  }
+
   // hasTrivialCopyAssignment - Whether this class has a trivial copy
-  // assignment operator (C++ [class.copy]p11)
+  // assignment operator (C++ [class.copy]p11, C++0x [class.copy]p27)
   bool hasTrivialCopyAssignment() const {
     return data().HasTrivialCopyAssignment;
   }
 
+  // hasTrivialMoveAssignment - Whether this class has a trivial move
+  // assignment operator (C++0x [class.copy]p27)
+  bool hasTrivialMoveAssignment() const {
+    return data().HasTrivialMoveAssignment;
+  }
+
   // hasTrivialDestructor - Whether this class has a trivial destructor
   // (C++ [class.dtor]p3)
   bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
@@ -1541,8 +1588,11 @@ public:
 
   /// \brief Determine whether this constructor is a move constructor
   /// (C++0x [class.copy]p3), which can be used to move values of the class.
-  bool isMoveConstructor() const;
-  
+  bool isMoveConstructor() const {
+    unsigned TypeQuals = 0;
+    return isMoveConstructor(TypeQuals);
+  }
+
   /// \brief Determine whether this is a copy or move constructor.
   ///
   /// \param TypeQuals Will be set to the type qualifiers on the reference
index 015b49aed6fdb883cd3c776ddfa8d0f89abc21ab..af796d54c4d2644416cc1cfeaf4388426bff8bd8 100644 (file)
@@ -32,7 +32,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
     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 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
       // 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 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
       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 @@ bool CXXRecordDecl::isTriviallyCopyable() const {
   //   -- 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 @@ void CXXRecordDecl::addedMember(Decl *D) {
       
       // 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 @@ void CXXRecordDecl::addedMember(Decl *D) {
     // 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 @@ void CXXRecordDecl::addedMember(Decl *D) {
         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 @@ void CXXRecordDecl::addedMember(Decl *D) {
       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 @@ void CXXRecordDecl::addedMember(Decl *D) {
       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;
       }
index 889ef7324c839e9198882c8367b779aed0849b3a..a85099d5ef796c0e00f8f8e76701b702ef8a6f4c 100644 (file)
@@ -843,7 +843,9 @@ void ASTDeclReader::ReadCXXDefinitionData(
   Data.Abstract = Record[Idx++];
   Data.HasTrivialConstructor = Record[Idx++];
   Data.HasTrivialCopyConstructor = Record[Idx++];
+  Data.HasTrivialMoveConstructor = Record[Idx++];
   Data.HasTrivialCopyAssignment = Record[Idx++];
+  Data.HasTrivialMoveAssignment = Record[Idx++];
   Data.HasTrivialDestructor = Record[Idx++];
   Data.ComputedVisibleConversions = Record[Idx++];
   Data.DeclaredDefaultConstructor = Record[Idx++];
index 05078cc012069c8384116c07e027c539c7bf2815..24a9c66755fca403ad95c3926b2eb7f64ebaca8e 100644 (file)
@@ -3795,7 +3795,9 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
   Record.push_back(Data.Abstract);
   Record.push_back(Data.HasTrivialConstructor);
   Record.push_back(Data.HasTrivialCopyConstructor);
+  Record.push_back(Data.HasTrivialMoveConstructor);
   Record.push_back(Data.HasTrivialCopyAssignment);
+  Record.push_back(Data.HasTrivialMoveAssignment);
   Record.push_back(Data.HasTrivialDestructor);
   Record.push_back(Data.ComputedVisibleConversions);
   Record.push_back(Data.DeclaredDefaultConstructor);
index 70aec32b088a6091d1187ff4e4704c2b14fa60da..fe5be639616e0897324a4fe37cac701b912a03a5 100644 (file)
@@ -35,6 +35,8 @@ typedef Derives DerivesArNB[];
 struct DerivesEmpty : Empty {};
 struct HasCons { HasCons(int); };
 struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
+struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; // \
+    // expected-warning {{rvalue references}}
 struct HasDest { ~HasDest(); };
 class  HasPriv { int priv; };
 class  HasProt { protected: int prot; };
@@ -47,6 +49,7 @@ typedef NonPOD NonPODArNB[];
 union NonPODUnion { int i; Derives n; };
 struct DerivesHasCons : HasCons {};
 struct DerivesHasCopyAssign : HasCopyAssign {};
+struct DerivesHasMoveAssign : HasMoveAssign {};
 struct DerivesHasDest : HasDest {};
 struct DerivesHasPriv : HasPriv {};
 struct DerivesHasProt : HasProt {};
@@ -108,6 +111,7 @@ void is_pod()
   { int arr[F(__is_pod(DerivesEmpty))]; }
   { int arr[F(__is_pod(HasCons))]; }
   { int arr[F(__is_pod(HasCopyAssign))]; }
+  { int arr[F(__is_pod(HasMoveAssign))]; }
   { int arr[F(__is_pod(HasDest))]; }
   { int arr[F(__is_pod(HasPriv))]; }
   { int arr[F(__is_pod(HasProt))]; }
@@ -115,6 +119,7 @@ void is_pod()
   { int arr[F(__is_pod(HasVirt))]; }
   { int arr[F(__is_pod(DerivesHasCons))]; }
   { int arr[F(__is_pod(DerivesHasCopyAssign))]; }
+  { int arr[F(__is_pod(DerivesHasMoveAssign))]; }
   { int arr[F(__is_pod(DerivesHasDest))]; }
   { int arr[F(__is_pod(DerivesHasPriv))]; }
   { int arr[F(__is_pod(DerivesHasProt))]; }
@@ -141,6 +146,7 @@ void is_empty()
   { int arr[T(__is_empty(DerivesEmpty))]; }
   { int arr[T(__is_empty(HasCons))]; }
   { int arr[T(__is_empty(HasCopyAssign))]; }
+  { int arr[T(__is_empty(HasMoveAssign))]; }
   { int arr[T(__is_empty(HasDest))]; }
   { int arr[T(__is_empty(HasFunc))]; }
   { int arr[T(__is_empty(HasOp))]; }
@@ -246,6 +252,10 @@ struct HasCopy {
   HasCopy(HasCopy& cp);
 };
 
+struct HasMove {
+  HasMove(HasMove&& cp); // expected-warning {{rvalue references}}
+};
+
 struct HasTemplateCons {
   HasVirt Annoying;
 
@@ -266,6 +276,7 @@ void has_trivial_default_constructor() {
   { int arr[T(__has_trivial_constructor(HasDest))]; }
   { int arr[T(__has_trivial_constructor(HasPriv))]; }
   { int arr[T(__has_trivial_constructor(HasCopyAssign))]; }
+  { int arr[T(__has_trivial_constructor(HasMoveAssign))]; }
   { int arr[T(__has_trivial_constructor(const Int))]; }
 
   { int arr[F(__has_trivial_constructor(HasCons))]; }
@@ -291,8 +302,10 @@ void has_trivial_copy_constructor() {
   { int arr[T(__has_trivial_copy(HasPriv))]; }
   { int arr[T(__has_trivial_copy(HasCons))]; }
   { int arr[T(__has_trivial_copy(HasRef))]; }
+  { int arr[T(__has_trivial_copy(HasMove))]; }
   { int arr[T(__has_trivial_copy(IntRef))]; }
   { int arr[T(__has_trivial_copy(HasCopyAssign))]; }
+  { int arr[T(__has_trivial_copy(HasMoveAssign))]; }
   { int arr[T(__has_trivial_copy(const Int))]; }
 
   { int arr[F(__has_trivial_copy(HasCopy))]; }
@@ -315,6 +328,8 @@ void has_trivial_copy_assignment() {
   { int arr[T(__has_trivial_assign(HasCons))]; }
   { int arr[T(__has_trivial_assign(HasRef))]; }
   { int arr[T(__has_trivial_assign(HasCopy))]; }
+  { int arr[T(__has_trivial_assign(HasMove))]; }
+  { int arr[T(__has_trivial_assign(HasMoveAssign))]; }
 
   { int arr[F(__has_trivial_assign(IntRef))]; }
   { int arr[F(__has_trivial_assign(HasCopyAssign))]; }
@@ -340,8 +355,10 @@ void has_trivial_destructor() {
   { int arr[T(__has_trivial_destructor(HasCons))]; }
   { int arr[T(__has_trivial_destructor(HasRef))]; }
   { int arr[T(__has_trivial_destructor(HasCopy))]; }
+  { int arr[T(__has_trivial_destructor(HasMove))]; }
   { int arr[T(__has_trivial_destructor(IntRef))]; }
   { int arr[T(__has_trivial_destructor(HasCopyAssign))]; }
+  { int arr[T(__has_trivial_destructor(HasMoveAssign))]; }
   { int arr[T(__has_trivial_destructor(const Int))]; }
   { int arr[T(__has_trivial_destructor(DerivesAr))]; }
   { int arr[T(__has_trivial_destructor(VirtAr))]; }
@@ -371,6 +388,8 @@ void has_nothrow_assign() {
   { int arr[T(__has_nothrow_assign(HasCons))]; }
   { int arr[T(__has_nothrow_assign(HasRef))]; }
   { int arr[T(__has_nothrow_assign(HasCopy))]; }
+  { int arr[T(__has_nothrow_assign(HasMove))]; }
+  { int arr[T(__has_nothrow_assign(HasMoveAssign))]; }
   { int arr[T(__has_nothrow_assign(HasNoThrowCopyAssign))]; }
   { int arr[T(__has_nothrow_assign(HasMultipleNoThrowCopyAssign))]; }
   { int arr[T(__has_nothrow_assign(HasVirtDest))]; }
@@ -402,7 +421,9 @@ void has_nothrow_copy() {
   { int arr[T(__has_nothrow_copy(HasPriv))]; }
   { int arr[T(__has_nothrow_copy(HasCons))]; }
   { int arr[T(__has_nothrow_copy(HasRef))]; }
+  { int arr[T(__has_nothrow_copy(HasMove))]; }
   { int arr[T(__has_nothrow_copy(HasCopyAssign))]; }
+  { int arr[T(__has_nothrow_copy(HasMoveAssign))]; }
   { int arr[T(__has_nothrow_copy(HasNoThrowCopy))]; }
   { int arr[T(__has_nothrow_copy(HasMultipleNoThrowCopy))]; }
   { int arr[T(__has_nothrow_copy(HasVirtDest))]; }
@@ -437,6 +458,7 @@ void has_nothrow_constructor() {
   { int arr[F(__has_nothrow_constructor(HasCons))]; }
   { int arr[F(__has_nothrow_constructor(HasRef))]; }
   { int arr[F(__has_nothrow_constructor(HasCopy))]; }
+  { int arr[F(__has_nothrow_constructor(HasMove))]; }
   { int arr[F(__has_nothrow_constructor(HasNoThrowConstructorWithArgs))]; }
   { int arr[F(__has_nothrow_constructor(IntRef))]; }
   { int arr[F(__has_nothrow_constructor(void))]; }
@@ -460,7 +482,9 @@ void has_virtual_destructor() {
   { int arr[F(__has_virtual_destructor(HasCons))]; }
   { int arr[F(__has_virtual_destructor(HasRef))]; }
   { int arr[F(__has_virtual_destructor(HasCopy))]; }
+  { int arr[F(__has_virtual_destructor(HasMove))]; }
   { int arr[F(__has_virtual_destructor(HasCopyAssign))]; }
+  { int arr[F(__has_virtual_destructor(HasMoveAssign))]; }
   { int arr[F(__has_virtual_destructor(IntRef))]; }
   { int arr[F(__has_virtual_destructor(VirtAr))]; }
 
@@ -599,12 +623,14 @@ void is_trivial()
 
   { int arr[F(__is_trivial(HasCons))]; }
   { int arr[F(__is_trivial(HasCopyAssign))]; }
+  { int arr[F(__is_trivial(HasMoveAssign))]; }
   { int arr[F(__is_trivial(HasDest))]; }
   { int arr[F(__is_trivial(HasRef))]; }
   { int arr[F(__is_trivial(HasNonPOD))]; }
   { int arr[F(__is_trivial(HasVirt))]; }
   { int arr[F(__is_trivial(DerivesHasCons))]; }
   { int arr[F(__is_trivial(DerivesHasCopyAssign))]; }
+  { int arr[F(__is_trivial(DerivesHasMoveAssign))]; }
   { int arr[F(__is_trivial(DerivesHasDest))]; }
   { int arr[F(__is_trivial(DerivesHasRef))]; }
   { int arr[F(__is_trivial(DerivesHasVirt))]; }