forked from OSchip/llvm-project
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. llvm-svn: 130076
This commit is contained in:
parent
78ef0957d4
commit
ad7d404732
|
@ -319,28 +319,63 @@ class CXXRecordDecl : public RecordDecl {
|
||||||
/// HasTrivialCopyConstructor - True when this class has a trivial copy
|
/// HasTrivialCopyConstructor - True when this class has a trivial copy
|
||||||
/// constructor.
|
/// constructor.
|
||||||
///
|
///
|
||||||
/// C++ [class.copy]p6. A copy constructor for class X is trivial
|
/// C++0x [class.copy]p13:
|
||||||
/// if it is implicitly declared and if
|
/// A copy/move constructor for class X is trivial if it is neither
|
||||||
/// * class X has no virtual functions and no virtual base classes, and
|
/// user-provided nor deleted and if
|
||||||
/// * each direct base class of X has a trivial copy constructor, and
|
/// -- class X has no virtual functions and no virtual base classes, and
|
||||||
/// * for all the nonstatic data members of X that are of class type (or
|
/// -- the constructor selected to copy/move each direct base class
|
||||||
/// array thereof), each such class type has a trivial copy constructor;
|
/// subobject is trivial, and
|
||||||
/// otherwise the copy constructor is non-trivial.
|
/// -- 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;
|
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
|
/// HasTrivialCopyAssignment - True when this class has a trivial copy
|
||||||
/// assignment operator.
|
/// assignment operator.
|
||||||
///
|
///
|
||||||
/// C++ [class.copy]p11. A copy assignment operator for class X is
|
/// C++0x [class.copy]p27:
|
||||||
/// trivial if it is implicitly declared and if
|
/// A copy/move assignment operator for class X is trivial if it is
|
||||||
/// * class X has no virtual functions and no virtual base classes, and
|
/// neither user-provided nor deleted and if
|
||||||
/// * each direct base class of X has a trivial copy assignment operator, and
|
/// -- class X has no virtual functions and no virtual base classes, and
|
||||||
/// * for all the nonstatic data members of X that are of class type (or
|
/// -- the assignment operator selected to copy/move each direct base
|
||||||
/// array thereof), each such class type has a trivial copy assignment
|
/// class subobject is trivial, and
|
||||||
/// operator;
|
/// -- for each non-static data member of X that is of class type (or an
|
||||||
/// otherwise the copy assignment operator is non-trivial.
|
/// 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;
|
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.
|
/// HasTrivialDestructor - True when this class has a trivial destructor.
|
||||||
///
|
///
|
||||||
/// C++ [class.dtor]p3. A destructor is trivial if it is an
|
/// C++ [class.dtor]p3. A destructor is trivial if it is an
|
||||||
|
@ -726,17 +761,29 @@ public:
|
||||||
bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
|
bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
|
||||||
|
|
||||||
// hasTrivialCopyConstructor - Whether this class has a trivial copy
|
// 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 {
|
bool hasTrivialCopyConstructor() const {
|
||||||
return data().HasTrivialCopyConstructor;
|
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
|
// 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 {
|
bool hasTrivialCopyAssignment() const {
|
||||||
return data().HasTrivialCopyAssignment;
|
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
|
// hasTrivialDestructor - Whether this class has a trivial destructor
|
||||||
// (C++ [class.dtor]p3)
|
// (C++ [class.dtor]p3)
|
||||||
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
|
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
|
||||||
|
@ -1541,8 +1588,11 @@ public:
|
||||||
|
|
||||||
/// \brief Determine whether this constructor is a move constructor
|
/// \brief Determine whether this constructor is a move constructor
|
||||||
/// (C++0x [class.copy]p3), which can be used to move values of the class.
|
/// (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.
|
/// \brief Determine whether this is a copy or move constructor.
|
||||||
///
|
///
|
||||||
/// \param TypeQuals Will be set to the type qualifiers on the reference
|
/// \param TypeQuals Will be set to the type qualifiers on the reference
|
||||||
|
|
|
@ -32,7 +32,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
||||||
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
||||||
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
||||||
Abstract(false), HasTrivialConstructor(true),
|
Abstract(false), HasTrivialConstructor(true),
|
||||||
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
|
HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
|
||||||
|
HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
|
||||||
HasTrivialDestructor(true), ComputedVisibleConversions(false),
|
HasTrivialDestructor(true), ComputedVisibleConversions(false),
|
||||||
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
|
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
|
||||||
DeclaredCopyAssignment(false), DeclaredDestructor(false),
|
DeclaredCopyAssignment(false), DeclaredDestructor(false),
|
||||||
|
@ -139,16 +140,20 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||||
// C++ [class.ctor]p5:
|
// C++ [class.ctor]p5:
|
||||||
// A constructor is trivial if its class has no virtual base classes.
|
// A constructor is trivial if its class has no virtual base classes.
|
||||||
data().HasTrivialConstructor = false;
|
data().HasTrivialConstructor = false;
|
||||||
|
|
||||||
// C++ [class.copy]p6:
|
// C++0x [class.copy]p13:
|
||||||
// A copy constructor is trivial if its class has no virtual base
|
// A copy/move constructor for class X is trivial if it is neither
|
||||||
// classes.
|
// user-provided nor deleted and if
|
||||||
|
// -- class X has no virtual functions and no virtual base classes, and
|
||||||
data().HasTrivialCopyConstructor = false;
|
data().HasTrivialCopyConstructor = false;
|
||||||
|
data().HasTrivialMoveConstructor = false;
|
||||||
// C++ [class.copy]p11:
|
|
||||||
// A copy assignment operator is trivial if its class has no virtual
|
// C++0x [class.copy]p27:
|
||||||
// base classes.
|
// 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().HasTrivialCopyAssignment = false;
|
||||||
|
data().HasTrivialMoveAssignment = false;
|
||||||
} else {
|
} else {
|
||||||
// C++ [class.ctor]p5:
|
// C++ [class.ctor]p5:
|
||||||
// A constructor is trivial if all the direct base classes of its
|
// 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())
|
if (!BaseClassDecl->hasTrivialConstructor())
|
||||||
data().HasTrivialConstructor = false;
|
data().HasTrivialConstructor = false;
|
||||||
|
|
||||||
// C++ [class.copy]p6:
|
// C++0x [class.copy]p13:
|
||||||
// A copy constructor is trivial if all the direct base classes of its
|
// A copy/move constructor for class X is trivial if [...]
|
||||||
// class have trivial copy constructors.
|
// [...]
|
||||||
|
// -- 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())
|
if (!BaseClassDecl->hasTrivialCopyConstructor())
|
||||||
data().HasTrivialCopyConstructor = false;
|
data().HasTrivialCopyConstructor = false;
|
||||||
|
if (!BaseClassDecl->hasTrivialMoveConstructor())
|
||||||
// C++ [class.copy]p11:
|
data().HasTrivialMoveConstructor = false;
|
||||||
// A copy assignment operator is trivial if all the direct base classes
|
|
||||||
// of its class have trivial copy assignment operators.
|
// 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())
|
if (!BaseClassDecl->hasTrivialCopyAssignment())
|
||||||
data().HasTrivialCopyAssignment = false;
|
data().HasTrivialCopyAssignment = false;
|
||||||
|
if (!BaseClassDecl->hasTrivialMoveAssignment())
|
||||||
|
data().HasTrivialMoveAssignment = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++ [class.ctor]p3:
|
// C++ [class.ctor]p3:
|
||||||
|
@ -223,11 +240,11 @@ bool CXXRecordDecl::isTriviallyCopyable() const {
|
||||||
// -- has no non-trivial copy constructors,
|
// -- has no non-trivial copy constructors,
|
||||||
if (!hasTrivialCopyConstructor()) return false;
|
if (!hasTrivialCopyConstructor()) return false;
|
||||||
// -- has no non-trivial move constructors,
|
// -- 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,
|
// -- has no non-trivial copy assignment operators,
|
||||||
if (!hasTrivialCopyAssignment()) return false;
|
if (!hasTrivialCopyAssignment()) return false;
|
||||||
// -- has no non-trivial move assignment operators, and
|
// -- 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.
|
// -- has a trivial destructor.
|
||||||
if (!hasTrivialDestructor()) return false;
|
if (!hasTrivialDestructor()) return false;
|
||||||
|
|
||||||
|
@ -374,8 +391,18 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||||
|
|
||||||
// None of the special member functions are trivial.
|
// None of the special member functions are trivial.
|
||||||
data().HasTrivialConstructor = false;
|
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().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().HasTrivialCopyAssignment = false;
|
||||||
|
data().HasTrivialMoveAssignment = false;
|
||||||
// FIXME: Destructor?
|
// FIXME: Destructor?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -439,18 +466,27 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||||
// FIXME: C++0x: don't do this for "= default" default constructors.
|
// FIXME: C++0x: don't do this for "= default" default constructors.
|
||||||
data().HasTrivialConstructor = false;
|
data().HasTrivialConstructor = false;
|
||||||
|
|
||||||
// Note when we have a user-declared copy constructor, which will
|
// Note when we have a user-declared copy or move constructor, which will
|
||||||
// suppress the implicit declaration of a copy constructor.
|
// suppress the implicit declaration of those constructors.
|
||||||
if (!FunTmpl && Constructor->isCopyConstructor()) {
|
if (!FunTmpl) {
|
||||||
data().UserDeclaredCopyConstructor = true;
|
if (Constructor->isCopyConstructor()) {
|
||||||
data().DeclaredCopyConstructor = true;
|
data().UserDeclaredCopyConstructor = true;
|
||||||
|
data().DeclaredCopyConstructor = true;
|
||||||
// C++ [class.copy]p6:
|
|
||||||
// A copy constructor is trivial if it is implicitly declared.
|
// C++0x [class.copy]p13:
|
||||||
// FIXME: C++0x: don't do this for "= default" copy constructors.
|
// A copy/move constructor for class X is trivial if it is neither
|
||||||
data().HasTrivialCopyConstructor = false;
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,35 +524,53 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ASTContext &Context = getASTContext();
|
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(
|
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
|
||||||
const_cast<CXXRecordDecl*>(this)));
|
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))
|
if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
|
||||||
return;
|
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:
|
// C++ [class]p4:
|
||||||
// A POD-struct is an aggregate class that [...] has no user-defined copy
|
// A POD-struct is an aggregate class that [...] has no user-defined
|
||||||
// assignment operator [...].
|
// 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;
|
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.
|
// Keep the list of conversion functions up-to-date.
|
||||||
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
|
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
|
||||||
// We don't record specializations.
|
// We don't record specializations.
|
||||||
|
@ -556,7 +610,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||||
data().PlainOldData = false;
|
data().PlainOldData = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++ [class]p9:
|
// C++0x [class]p9:
|
||||||
// A POD struct is a class that is both a trivial class and a
|
// 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
|
// standard-layout class, and has no non-static data members of type
|
||||||
// non-POD struct, non-POD union (or array of such types).
|
// 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->getDefinition()) {
|
||||||
if (!FieldRec->hasTrivialConstructor())
|
if (!FieldRec->hasTrivialConstructor())
|
||||||
data().HasTrivialConstructor = false;
|
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())
|
if (!FieldRec->hasTrivialCopyConstructor())
|
||||||
data().HasTrivialCopyConstructor = false;
|
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())
|
if (!FieldRec->hasTrivialCopyAssignment())
|
||||||
data().HasTrivialCopyAssignment = false;
|
data().HasTrivialCopyAssignment = false;
|
||||||
|
if (!FieldRec->hasTrivialMoveAssignment())
|
||||||
|
data().HasTrivialMoveAssignment = false;
|
||||||
|
|
||||||
if (!FieldRec->hasTrivialDestructor())
|
if (!FieldRec->hasTrivialDestructor())
|
||||||
data().HasTrivialDestructor = false;
|
data().HasTrivialDestructor = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -843,7 +843,9 @@ void ASTDeclReader::ReadCXXDefinitionData(
|
||||||
Data.Abstract = Record[Idx++];
|
Data.Abstract = Record[Idx++];
|
||||||
Data.HasTrivialConstructor = Record[Idx++];
|
Data.HasTrivialConstructor = Record[Idx++];
|
||||||
Data.HasTrivialCopyConstructor = Record[Idx++];
|
Data.HasTrivialCopyConstructor = Record[Idx++];
|
||||||
|
Data.HasTrivialMoveConstructor = Record[Idx++];
|
||||||
Data.HasTrivialCopyAssignment = Record[Idx++];
|
Data.HasTrivialCopyAssignment = Record[Idx++];
|
||||||
|
Data.HasTrivialMoveAssignment = Record[Idx++];
|
||||||
Data.HasTrivialDestructor = Record[Idx++];
|
Data.HasTrivialDestructor = Record[Idx++];
|
||||||
Data.ComputedVisibleConversions = Record[Idx++];
|
Data.ComputedVisibleConversions = Record[Idx++];
|
||||||
Data.DeclaredDefaultConstructor = Record[Idx++];
|
Data.DeclaredDefaultConstructor = Record[Idx++];
|
||||||
|
|
|
@ -3795,7 +3795,9 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
|
||||||
Record.push_back(Data.Abstract);
|
Record.push_back(Data.Abstract);
|
||||||
Record.push_back(Data.HasTrivialConstructor);
|
Record.push_back(Data.HasTrivialConstructor);
|
||||||
Record.push_back(Data.HasTrivialCopyConstructor);
|
Record.push_back(Data.HasTrivialCopyConstructor);
|
||||||
|
Record.push_back(Data.HasTrivialMoveConstructor);
|
||||||
Record.push_back(Data.HasTrivialCopyAssignment);
|
Record.push_back(Data.HasTrivialCopyAssignment);
|
||||||
|
Record.push_back(Data.HasTrivialMoveAssignment);
|
||||||
Record.push_back(Data.HasTrivialDestructor);
|
Record.push_back(Data.HasTrivialDestructor);
|
||||||
Record.push_back(Data.ComputedVisibleConversions);
|
Record.push_back(Data.ComputedVisibleConversions);
|
||||||
Record.push_back(Data.DeclaredDefaultConstructor);
|
Record.push_back(Data.DeclaredDefaultConstructor);
|
||||||
|
|
|
@ -35,6 +35,8 @@ typedef Derives DerivesArNB[];
|
||||||
struct DerivesEmpty : Empty {};
|
struct DerivesEmpty : Empty {};
|
||||||
struct HasCons { HasCons(int); };
|
struct HasCons { HasCons(int); };
|
||||||
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
|
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
|
||||||
|
struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; // \
|
||||||
|
// expected-warning {{rvalue references}}
|
||||||
struct HasDest { ~HasDest(); };
|
struct HasDest { ~HasDest(); };
|
||||||
class HasPriv { int priv; };
|
class HasPriv { int priv; };
|
||||||
class HasProt { protected: int prot; };
|
class HasProt { protected: int prot; };
|
||||||
|
@ -47,6 +49,7 @@ typedef NonPOD NonPODArNB[];
|
||||||
union NonPODUnion { int i; Derives n; };
|
union NonPODUnion { int i; Derives n; };
|
||||||
struct DerivesHasCons : HasCons {};
|
struct DerivesHasCons : HasCons {};
|
||||||
struct DerivesHasCopyAssign : HasCopyAssign {};
|
struct DerivesHasCopyAssign : HasCopyAssign {};
|
||||||
|
struct DerivesHasMoveAssign : HasMoveAssign {};
|
||||||
struct DerivesHasDest : HasDest {};
|
struct DerivesHasDest : HasDest {};
|
||||||
struct DerivesHasPriv : HasPriv {};
|
struct DerivesHasPriv : HasPriv {};
|
||||||
struct DerivesHasProt : HasProt {};
|
struct DerivesHasProt : HasProt {};
|
||||||
|
@ -108,6 +111,7 @@ void is_pod()
|
||||||
{ int arr[F(__is_pod(DerivesEmpty))]; }
|
{ int arr[F(__is_pod(DerivesEmpty))]; }
|
||||||
{ int arr[F(__is_pod(HasCons))]; }
|
{ int arr[F(__is_pod(HasCons))]; }
|
||||||
{ int arr[F(__is_pod(HasCopyAssign))]; }
|
{ int arr[F(__is_pod(HasCopyAssign))]; }
|
||||||
|
{ int arr[F(__is_pod(HasMoveAssign))]; }
|
||||||
{ int arr[F(__is_pod(HasDest))]; }
|
{ int arr[F(__is_pod(HasDest))]; }
|
||||||
{ int arr[F(__is_pod(HasPriv))]; }
|
{ int arr[F(__is_pod(HasPriv))]; }
|
||||||
{ int arr[F(__is_pod(HasProt))]; }
|
{ int arr[F(__is_pod(HasProt))]; }
|
||||||
|
@ -115,6 +119,7 @@ void is_pod()
|
||||||
{ int arr[F(__is_pod(HasVirt))]; }
|
{ int arr[F(__is_pod(HasVirt))]; }
|
||||||
{ int arr[F(__is_pod(DerivesHasCons))]; }
|
{ int arr[F(__is_pod(DerivesHasCons))]; }
|
||||||
{ int arr[F(__is_pod(DerivesHasCopyAssign))]; }
|
{ int arr[F(__is_pod(DerivesHasCopyAssign))]; }
|
||||||
|
{ int arr[F(__is_pod(DerivesHasMoveAssign))]; }
|
||||||
{ int arr[F(__is_pod(DerivesHasDest))]; }
|
{ int arr[F(__is_pod(DerivesHasDest))]; }
|
||||||
{ int arr[F(__is_pod(DerivesHasPriv))]; }
|
{ int arr[F(__is_pod(DerivesHasPriv))]; }
|
||||||
{ int arr[F(__is_pod(DerivesHasProt))]; }
|
{ int arr[F(__is_pod(DerivesHasProt))]; }
|
||||||
|
@ -141,6 +146,7 @@ void is_empty()
|
||||||
{ int arr[T(__is_empty(DerivesEmpty))]; }
|
{ int arr[T(__is_empty(DerivesEmpty))]; }
|
||||||
{ int arr[T(__is_empty(HasCons))]; }
|
{ int arr[T(__is_empty(HasCons))]; }
|
||||||
{ int arr[T(__is_empty(HasCopyAssign))]; }
|
{ int arr[T(__is_empty(HasCopyAssign))]; }
|
||||||
|
{ int arr[T(__is_empty(HasMoveAssign))]; }
|
||||||
{ int arr[T(__is_empty(HasDest))]; }
|
{ int arr[T(__is_empty(HasDest))]; }
|
||||||
{ int arr[T(__is_empty(HasFunc))]; }
|
{ int arr[T(__is_empty(HasFunc))]; }
|
||||||
{ int arr[T(__is_empty(HasOp))]; }
|
{ int arr[T(__is_empty(HasOp))]; }
|
||||||
|
@ -246,6 +252,10 @@ struct HasCopy {
|
||||||
HasCopy(HasCopy& cp);
|
HasCopy(HasCopy& cp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HasMove {
|
||||||
|
HasMove(HasMove&& cp); // expected-warning {{rvalue references}}
|
||||||
|
};
|
||||||
|
|
||||||
struct HasTemplateCons {
|
struct HasTemplateCons {
|
||||||
HasVirt Annoying;
|
HasVirt Annoying;
|
||||||
|
|
||||||
|
@ -266,6 +276,7 @@ void has_trivial_default_constructor() {
|
||||||
{ int arr[T(__has_trivial_constructor(HasDest))]; }
|
{ int arr[T(__has_trivial_constructor(HasDest))]; }
|
||||||
{ int arr[T(__has_trivial_constructor(HasPriv))]; }
|
{ int arr[T(__has_trivial_constructor(HasPriv))]; }
|
||||||
{ int arr[T(__has_trivial_constructor(HasCopyAssign))]; }
|
{ int arr[T(__has_trivial_constructor(HasCopyAssign))]; }
|
||||||
|
{ int arr[T(__has_trivial_constructor(HasMoveAssign))]; }
|
||||||
{ int arr[T(__has_trivial_constructor(const Int))]; }
|
{ int arr[T(__has_trivial_constructor(const Int))]; }
|
||||||
|
|
||||||
{ int arr[F(__has_trivial_constructor(HasCons))]; }
|
{ 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(HasPriv))]; }
|
||||||
{ int arr[T(__has_trivial_copy(HasCons))]; }
|
{ int arr[T(__has_trivial_copy(HasCons))]; }
|
||||||
{ int arr[T(__has_trivial_copy(HasRef))]; }
|
{ 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(IntRef))]; }
|
||||||
{ int arr[T(__has_trivial_copy(HasCopyAssign))]; }
|
{ int arr[T(__has_trivial_copy(HasCopyAssign))]; }
|
||||||
|
{ int arr[T(__has_trivial_copy(HasMoveAssign))]; }
|
||||||
{ int arr[T(__has_trivial_copy(const Int))]; }
|
{ int arr[T(__has_trivial_copy(const Int))]; }
|
||||||
|
|
||||||
{ int arr[F(__has_trivial_copy(HasCopy))]; }
|
{ 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(HasCons))]; }
|
||||||
{ int arr[T(__has_trivial_assign(HasRef))]; }
|
{ int arr[T(__has_trivial_assign(HasRef))]; }
|
||||||
{ int arr[T(__has_trivial_assign(HasCopy))]; }
|
{ 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(IntRef))]; }
|
||||||
{ int arr[F(__has_trivial_assign(HasCopyAssign))]; }
|
{ 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(HasCons))]; }
|
||||||
{ int arr[T(__has_trivial_destructor(HasRef))]; }
|
{ int arr[T(__has_trivial_destructor(HasRef))]; }
|
||||||
{ int arr[T(__has_trivial_destructor(HasCopy))]; }
|
{ 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(IntRef))]; }
|
||||||
{ int arr[T(__has_trivial_destructor(HasCopyAssign))]; }
|
{ 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(const Int))]; }
|
||||||
{ int arr[T(__has_trivial_destructor(DerivesAr))]; }
|
{ int arr[T(__has_trivial_destructor(DerivesAr))]; }
|
||||||
{ int arr[T(__has_trivial_destructor(VirtAr))]; }
|
{ 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(HasCons))]; }
|
||||||
{ int arr[T(__has_nothrow_assign(HasRef))]; }
|
{ int arr[T(__has_nothrow_assign(HasRef))]; }
|
||||||
{ int arr[T(__has_nothrow_assign(HasCopy))]; }
|
{ 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(HasNoThrowCopyAssign))]; }
|
||||||
{ int arr[T(__has_nothrow_assign(HasMultipleNoThrowCopyAssign))]; }
|
{ int arr[T(__has_nothrow_assign(HasMultipleNoThrowCopyAssign))]; }
|
||||||
{ int arr[T(__has_nothrow_assign(HasVirtDest))]; }
|
{ 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(HasPriv))]; }
|
||||||
{ int arr[T(__has_nothrow_copy(HasCons))]; }
|
{ int arr[T(__has_nothrow_copy(HasCons))]; }
|
||||||
{ int arr[T(__has_nothrow_copy(HasRef))]; }
|
{ 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(HasCopyAssign))]; }
|
||||||
|
{ int arr[T(__has_nothrow_copy(HasMoveAssign))]; }
|
||||||
{ int arr[T(__has_nothrow_copy(HasNoThrowCopy))]; }
|
{ int arr[T(__has_nothrow_copy(HasNoThrowCopy))]; }
|
||||||
{ int arr[T(__has_nothrow_copy(HasMultipleNoThrowCopy))]; }
|
{ int arr[T(__has_nothrow_copy(HasMultipleNoThrowCopy))]; }
|
||||||
{ int arr[T(__has_nothrow_copy(HasVirtDest))]; }
|
{ 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(HasCons))]; }
|
||||||
{ int arr[F(__has_nothrow_constructor(HasRef))]; }
|
{ int arr[F(__has_nothrow_constructor(HasRef))]; }
|
||||||
{ int arr[F(__has_nothrow_constructor(HasCopy))]; }
|
{ 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(HasNoThrowConstructorWithArgs))]; }
|
||||||
{ int arr[F(__has_nothrow_constructor(IntRef))]; }
|
{ int arr[F(__has_nothrow_constructor(IntRef))]; }
|
||||||
{ int arr[F(__has_nothrow_constructor(void))]; }
|
{ 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(HasCons))]; }
|
||||||
{ int arr[F(__has_virtual_destructor(HasRef))]; }
|
{ int arr[F(__has_virtual_destructor(HasRef))]; }
|
||||||
{ int arr[F(__has_virtual_destructor(HasCopy))]; }
|
{ 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(HasCopyAssign))]; }
|
||||||
|
{ int arr[F(__has_virtual_destructor(HasMoveAssign))]; }
|
||||||
{ int arr[F(__has_virtual_destructor(IntRef))]; }
|
{ int arr[F(__has_virtual_destructor(IntRef))]; }
|
||||||
{ int arr[F(__has_virtual_destructor(VirtAr))]; }
|
{ 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(HasCons))]; }
|
||||||
{ int arr[F(__is_trivial(HasCopyAssign))]; }
|
{ int arr[F(__is_trivial(HasCopyAssign))]; }
|
||||||
|
{ int arr[F(__is_trivial(HasMoveAssign))]; }
|
||||||
{ int arr[F(__is_trivial(HasDest))]; }
|
{ int arr[F(__is_trivial(HasDest))]; }
|
||||||
{ int arr[F(__is_trivial(HasRef))]; }
|
{ int arr[F(__is_trivial(HasRef))]; }
|
||||||
{ int arr[F(__is_trivial(HasNonPOD))]; }
|
{ int arr[F(__is_trivial(HasNonPOD))]; }
|
||||||
{ int arr[F(__is_trivial(HasVirt))]; }
|
{ int arr[F(__is_trivial(HasVirt))]; }
|
||||||
{ int arr[F(__is_trivial(DerivesHasCons))]; }
|
{ int arr[F(__is_trivial(DerivesHasCons))]; }
|
||||||
{ int arr[F(__is_trivial(DerivesHasCopyAssign))]; }
|
{ int arr[F(__is_trivial(DerivesHasCopyAssign))]; }
|
||||||
|
{ int arr[F(__is_trivial(DerivesHasMoveAssign))]; }
|
||||||
{ int arr[F(__is_trivial(DerivesHasDest))]; }
|
{ int arr[F(__is_trivial(DerivesHasDest))]; }
|
||||||
{ int arr[F(__is_trivial(DerivesHasRef))]; }
|
{ int arr[F(__is_trivial(DerivesHasRef))]; }
|
||||||
{ int arr[F(__is_trivial(DerivesHasVirt))]; }
|
{ int arr[F(__is_trivial(DerivesHasVirt))]; }
|
||||||
|
|
Loading…
Reference in New Issue