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:
Chandler Carruth 2011-04-23 23:10:33 +00:00
parent 78ef0957d4
commit ad7d404732
5 changed files with 226 additions and 71 deletions

View 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

View 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;
}

View 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++];

View 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);

View 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))]; }