/// 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
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; }
/// \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
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),
// 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
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:
// -- 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;
// 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?
}
}
// 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;
}
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.
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).
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;
}
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++];
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);
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; };
union NonPODUnion { int i; Derives n; };
struct DerivesHasCons : HasCons {};
struct DerivesHasCopyAssign : HasCopyAssign {};
+struct DerivesHasMoveAssign : HasMoveAssign {};
struct DerivesHasDest : HasDest {};
struct DerivesHasPriv : HasPriv {};
struct DerivesHasProt : HasProt {};
{ 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))]; }
{ 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))]; }
{ 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))]; }
HasCopy(HasCopy& cp);
};
+struct HasMove {
+ HasMove(HasMove&& cp); // expected-warning {{rvalue references}}
+};
+
struct HasTemplateCons {
HasVirt Annoying;
{ 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))]; }
{ 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))]; }
{ 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))]; }
{ 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))]; }
{ 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))]; }
{ 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))]; }
{ 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))]; }
{ 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))]; }
{ 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))]; }