/// is illegal in C++98 even if the class has a trivial default constructor.
bool HasUninitializedReferenceMember : 1;
+ /// \brief These flags are \c true if a defaulted corresponding special
+ /// member can't be fully analyzed without performing overload resolution.
+ /// @{
+ bool NeedOverloadResolutionForMoveConstructor : 1;
+ bool NeedOverloadResolutionForMoveAssignment : 1;
+ bool NeedOverloadResolutionForDestructor : 1;
+ /// @}
+
+ /// \brief These flags are \c true if an implicit defaulted corresponding
+ /// special member would be defined as deleted.
+ /// @{
+ bool DefaultedMoveConstructorIsDeleted : 1;
+ bool DefaultedMoveAssignmentIsDeleted : 1;
+ bool DefaultedDestructorIsDeleted : 1;
+ /// @}
+
/// \brief The trivial special members which this class has, per
/// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25,
/// C++11 [class.dtor]p5, or would have if the member were not suppressed.
friend class DeclContext;
friend class LambdaExpr;
+ /// \brief Called from setBases and addedMember to notify the class that a
+ /// direct or virtual base class or a member of class type has been added.
+ void addedClassSubobject(CXXRecordDecl *Base);
+
/// \brief Notify the class that member has been added.
///
/// This routine helps maintain information about the class based on which
return data().FirstFriend != 0;
}
+ /// \brief \c true if we know for sure that this class has a single,
+ /// accessible, unambiguous move constructor that is not deleted.
+ bool hasSimpleMoveConstructor() const {
+ return !hasUserDeclaredMoveConstructor() && hasMoveConstructor();
+ }
+ /// \brief \c true if we know for sure that this class has a single,
+ /// accessible, unambiguous move assignment operator that is not deleted.
+ bool hasSimpleMoveAssignment() const {
+ return !hasUserDeclaredMoveAssignment() && hasMoveAssignment();
+ }
+ /// \brief \c true if we know for sure that this class has an accessible
+ /// destructor that is not deleted.
+ bool hasSimpleDestructor() const {
+ return !hasUserDeclaredDestructor() &&
+ !data().DefaultedDestructorIsDeleted;
+ }
+
/// \brief Determine whether this class has any default constructors.
bool hasDefaultConstructor() const {
return (data().DeclaredSpecialMembers & SMF_DefaultConstructor) ||
return !(data().DeclaredSpecialMembers & SMF_CopyConstructor);
}
+ /// \brief Determine whether we need to eagerly declare a defaulted copy
+ /// constructor for this class.
+ bool needsOverloadResolutionForCopyConstructor() const {
+ return data().HasMutableFields;
+ }
+
/// \brief Determine whether an implicit copy constructor for this type
/// would have a parameter with a const-qualified reference type.
bool implicitCopyConstructorHasConstParam() const {
}
/// \brief Determine whether this class has a move constructor.
- /// FIXME: This can be wrong if the implicit move constructor would be
- /// deleted.
bool hasMoveConstructor() const {
return (data().DeclaredSpecialMembers & SMF_MoveConstructor) ||
needsImplicitMoveConstructor();
/// \brief Determine whether this class should get an implicit move
/// constructor or if any existing special member function inhibits this.
- ///
- /// Covers all bullets of C++0x [class.copy]p9 except the last, that the
- /// constructor wouldn't be deleted, which is only looked up from a cached
- /// result.
bool needsImplicitMoveConstructor() const {
return !hasFailedImplicitMoveConstructor() &&
!(data().DeclaredSpecialMembers & SMF_MoveConstructor) &&
!hasUserDeclaredCopyConstructor() &&
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveAssignment() &&
- !hasUserDeclaredDestructor();
+ !hasUserDeclaredDestructor() &&
+ !data().DefaultedMoveConstructorIsDeleted;
+ }
+
+ /// \brief Determine whether we need to eagerly declare a defaulted move
+ /// constructor for this class.
+ bool needsOverloadResolutionForMoveConstructor() const {
+ return data().NeedOverloadResolutionForMoveConstructor;
}
/// hasUserDeclaredCopyAssignment - Whether this class has a
return !(data().DeclaredSpecialMembers & SMF_CopyAssignment);
}
+ /// \brief Determine whether we need to eagerly declare a defaulted copy
+ /// assignment operator for this class.
+ bool needsOverloadResolutionForCopyAssignment() const {
+ return data().HasMutableFields;
+ }
+
/// \brief Determine whether an implicit copy assignment operator for this
/// type would have a parameter with a const-qualified reference type.
bool implicitCopyAssignmentHasConstParam() const {
}
/// \brief Determine whether this class has a move assignment operator.
- /// FIXME: This can be wrong if the implicit move assignment would be deleted.
bool hasMoveAssignment() const {
return (data().DeclaredSpecialMembers & SMF_MoveAssignment) ||
needsImplicitMoveAssignment();
/// \brief Determine whether this class should get an implicit move
/// assignment operator or if any existing special member function inhibits
/// this.
- ///
- /// Covers all bullets of C++0x [class.copy]p20 except the last, that the
- /// constructor wouldn't be deleted.
bool needsImplicitMoveAssignment() const {
return !hasFailedImplicitMoveAssignment() &&
!(data().DeclaredSpecialMembers & SMF_MoveAssignment) &&
!hasUserDeclaredCopyConstructor() &&
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveConstructor() &&
- !hasUserDeclaredDestructor();
+ !hasUserDeclaredDestructor() &&
+ !data().DefaultedMoveAssignmentIsDeleted;
+ }
+
+ /// \brief Determine whether we need to eagerly declare a move assignment
+ /// operator for this class.
+ bool needsOverloadResolutionForMoveAssignment() const {
+ return data().NeedOverloadResolutionForMoveAssignment;
}
/// hasUserDeclaredDestructor - Whether this class has a
return !(data().DeclaredSpecialMembers & SMF_Destructor);
}
+ /// \brief Determine whether we need to eagerly declare a destructor for this
+ /// class.
+ bool needsOverloadResolutionForDestructor() const {
+ return data().NeedOverloadResolutionForDestructor;
+ }
+
/// \brief Determine whether this class describes a lambda function object.
bool isLambda() const { return hasDefinition() && data().IsLambda; }
-
+
/// \brief For a closure type, retrieve the mapping from captured
/// variables and this to the non-static data members that store the
/// values or references of the captures.
/// \brief Determine whether this class has a trivial move constructor
/// (C++11 [class.copy]p12)
- /// FIXME: This can be wrong if the implicit move constructor would be
- /// deleted.
bool hasTrivialMoveConstructor() const {
return hasMoveConstructor() &&
(data().HasTrivialSpecialMembers & SMF_MoveConstructor);
/// \brief Determine whether this class has a non-trivial move constructor
/// (C++11 [class.copy]p12)
- /// FIXME: This can be wrong if the implicit move constructor would be
- /// deleted.
bool hasNonTrivialMoveConstructor() const {
return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) ||
(needsImplicitMoveConstructor() &&
/// \brief Determine whether this class has a trivial move assignment operator
/// (C++11 [class.copy]p25)
- /// FIXME: This can be wrong if the implicit move assignment would be deleted.
bool hasTrivialMoveAssignment() const {
return hasMoveAssignment() &&
(data().HasTrivialSpecialMembers & SMF_MoveAssignment);
/// \brief Determine whether this class has a non-trivial move assignment
/// operator (C++11 [class.copy]p25)
- /// FIXME: This can be wrong if the implicit move assignment would be deleted.
bool hasNonTrivialMoveAssignment() const {
return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveAssignment) ||
(needsImplicitMoveAssignment() &&
ToData.HasInClassInitializer = FromData.HasInClassInitializer;
ToData.HasUninitializedReferenceMember
= FromData.HasUninitializedReferenceMember;
+ ToData.NeedOverloadResolutionForMoveConstructor
+ = FromData.NeedOverloadResolutionForMoveConstructor;
+ ToData.NeedOverloadResolutionForMoveAssignment
+ = FromData.NeedOverloadResolutionForMoveAssignment;
+ ToData.NeedOverloadResolutionForDestructor
+ = FromData.NeedOverloadResolutionForDestructor;
+ ToData.DefaultedMoveConstructorIsDeleted
+ = FromData.DefaultedMoveConstructorIsDeleted;
+ ToData.DefaultedMoveAssignmentIsDeleted
+ = FromData.DefaultedMoveAssignmentIsDeleted;
+ ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted;
ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers;
ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
ToData.HasConstexprNonCopyMoveConstructor
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
HasMutableFields(false), HasOnlyCMembers(true),
HasInClassInitializer(false), HasUninitializedReferenceMember(false),
+ NeedOverloadResolutionForMoveConstructor(false),
+ NeedOverloadResolutionForMoveAssignment(false),
+ NeedOverloadResolutionForDestructor(false),
+ DefaultedMoveConstructorIsDeleted(false),
+ DefaultedMoveAssignmentIsDeleted(false),
+ DefaultedDestructorIsDeleted(false),
HasTrivialSpecialMembers(SMF_All),
DeclaredNonTrivialSpecialMembers(0),
HasIrrelevantDestructor(true),
// [...]
// -- 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. For now, we treat a move constructor as being
- // non-trivial if it calls anything other than a trivial move constructor.
if (!BaseClassDecl->hasTrivialCopyConstructor())
data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+ // If the base class doesn't have a simple move constructor, we'll eagerly
+ // declare it and perform overload resolution to determine which function
+ // it actually calls. If it does have a simple move constructor, this
+ // check is correct.
if (!BaseClassDecl->hasTrivialMoveConstructor())
data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
// [...]
// -- 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().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
+ // If the base class doesn't have a simple move assignment, we'll eagerly
+ // declare it and perform overload resolution to determine which function
+ // it actually calls. If it does have a simple move assignment, this
+ // check is correct.
if (!BaseClassDecl->hasTrivialMoveAssignment())
data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
if (BaseClassDecl->hasUninitializedReferenceMember())
data().HasUninitializedReferenceMember = true;
+
+ addedClassSubobject(BaseClassDecl);
}
if (VBases.empty())
// Create base specifier for any direct or indirect virtual bases.
data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
data().NumVBases = VBases.size();
- for (int I = 0, E = VBases.size(); I != E; ++I)
+ for (int I = 0, E = VBases.size(); I != E; ++I) {
+ QualType Type = VBases[I]->getType();
+ if (!Type->isDependentType())
+ addedClassSubobject(Type->getAsCXXRecordDecl());
data().getVBases()[I] = *VBases[I];
+ }
+}
+
+void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
+ // C++11 [class.copy]p11:
+ // A defaulted copy/move constructor for a class X is defined as
+ // deleted if X has:
+ // -- a direct or virtual base class B that cannot be copied/moved [...]
+ // -- a non-static data member of class type M (or array thereof)
+ // that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleMoveConstructor())
+ data().NeedOverloadResolutionForMoveConstructor = true;
+
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined as
+ // deleted if X has:
+ // -- a direct or virtual base class B that cannot be copied/moved [...]
+ // -- a non-static data member of class type M (or array thereof)
+ // that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleMoveAssignment())
+ data().NeedOverloadResolutionForMoveAssignment = true;
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5:
+ // A defaulted [ctor or dtor] for a class X is defined as
+ // deleted if X has:
+ // -- any direct or virtual base class [...] has a type with a destructor
+ // that is deleted or inaccessible from the defaulted [ctor or dtor].
+ // -- any non-static data member has a type with a destructor
+ // that is deleted or inaccessible from the defaulted [ctor or dtor].
+ if (!Subobj->hasSimpleDestructor()) {
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForDestructor = true;
+ }
}
/// Callback function for CXXRecordDecl::forallBases that acknowledges
data().PlainOldData = false;
}
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined
+ // as deleted if X has:
+ // -- a non-static data member of reference type
+ if (T->isReferenceType())
+ data().DefaultedMoveAssignmentIsDeleted = true;
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
+ addedClassSubobject(FieldRec);
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11:
+ // A defaulted [special member] for a class X is defined as
+ // deleted if:
+ // -- X is a union-like class that has a variant member with a
+ // non-trivial [corresponding special member]
+ if (isUnion()) {
+ if (FieldRec->hasNonTrivialMoveConstructor())
+ data().DefaultedMoveConstructorIsDeleted = true;
+ if (FieldRec->hasNonTrivialMoveAssignment())
+ data().DefaultedMoveAssignmentIsDeleted = true;
+ if (FieldRec->hasNonTrivialDestructor())
+ data().DefaultedDestructorIsDeleted = true;
+ }
+
// C++0x [class.ctor]p5:
// A default constructor is trivial [...] if:
// -- for all the non-static data members of its class that are of
// -- 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().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+ // If the field doesn't have a simple move constructor, we'll eagerly
+ // declare the move constructor for this class and we'll decide whether
+ // it's trivial then.
if (!FieldRec->hasTrivialMoveConstructor())
data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
// -- 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().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
+ // If the field doesn't have a simple move assignment, we'll eagerly
+ // declare the move assignment for this class and we'll decide whether
+ // it's trivial then.
if (!FieldRec->hasTrivialMoveAssignment())
data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
if (!T->isLiteralType() ||
(!Field->hasInClassInitializer() && !isUnion()))
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined
+ // as deleted if X has:
+ // -- a non-static data member of const non-class type (or array
+ // thereof)
+ if (T.isConstQualified())
+ data().DefaultedMoveAssignmentIsDeleted = true;
}
// C++0x [class]p7:
/// C++11 [class.copy]p25, and C++11 [class.dtor]p5.
bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
bool Diagnose) {
- // Note that we can't work out CSM for ourselves. Consider this:
- //
- // struct S { S(int); S(const S&=0) = delete; };
- //
- // The same function is a trivial copy constructor but a non-trivial default
- // constructor.
assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough");
CXXRecordDecl *RD = MD->getParent();
if (!ClassDecl->hasUserDeclaredConstructor())
++ASTContext::NumImplicitDefaultConstructors;
- if (!ClassDecl->hasUserDeclaredCopyConstructor())
+ if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
++ASTContext::NumImplicitCopyConstructors;
- if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor())
+ // If the properties or semantics of the copy constructor couldn't be
+ // determined while the class was being declared, force a declaration
+ // of it now.
+ if (ClassDecl->needsOverloadResolutionForCopyConstructor())
+ DeclareImplicitCopyConstructor(ClassDecl);
+ }
+
+ if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor()) {
++ASTContext::NumImplicitMoveConstructors;
+ if (ClassDecl->needsOverloadResolutionForMoveConstructor())
+ DeclareImplicitMoveConstructor(ClassDecl);
+ }
+
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
-
- // If we have a dynamic class, then the copy assignment operator may be
+
+ // If we have a dynamic class, then the copy assignment operator may be
// virtual, so we have to declare it immediately. This ensures that, e.g.,
- // it shows up in the right place in the vtable and that we diagnose
- // problems with the implicit exception specification.
- if (ClassDecl->isDynamicClass())
+ // it shows up in the right place in the vtable and that we diagnose
+ // problems with the implicit exception specification.
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForCopyAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
}
++ASTContext::NumImplicitMoveAssignmentOperators;
// Likewise for the move assignment operator.
- if (ClassDecl->isDynamicClass())
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForMoveAssignment())
DeclareImplicitMoveAssignment(ClassDecl);
}
if (!ClassDecl->hasUserDeclaredDestructor()) {
++ASTContext::NumImplicitDestructors;
-
- // If we have a dynamic class, then the destructor may be virtual, so we
+
+ // If we have a dynamic class, then the destructor may be virtual, so we
// have to declare the destructor immediately. This ensures that, e.g., it
// shows up in the right place in the vtable and that we diagnose problems
// with the implicit exception specification.
- if (ClassDecl->isDynamicClass())
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForDestructor())
DeclareImplicitDestructor(ClassDecl);
}
}
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
DefaultCon->setImplicit();
- DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
// Build an exception specification pointing back at this constructor.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecDecl = DefaultCon;
DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ // We don't need to use SpecialMemberIsTrivial here; triviality for default
+ // constructors is easy to compute.
+ DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
+
+ if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
+ DefaultCon->setDeletedAsWritten();
+
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
-
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
- if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
- DefaultCon->setDeletedAsWritten();
-
return DefaultCon;
}
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
Destructor->setImplicit();
- Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
// Build an exception specification pointing back at this destructor.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecDecl = Destructor;
Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ AddOverriddenMethods(ClassDecl, Destructor);
+
+ // We don't need to use SpecialMemberIsTrivial here; triviality for
+ // destructors is easy to compute.
+ Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
+
+ if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
+ Destructor->setDeletedAsWritten();
+
// Note that we have declared this destructor.
++ASTContext::NumImplicitDestructorsDeclared;
PushOnScopeChains(Destructor, S, false);
ClassDecl->addDecl(Destructor);
- AddOverriddenMethods(ClassDecl, Destructor);
-
- if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
- Destructor->setDeletedAsWritten();
-
return Destructor;
}
CopyAssignment->setAccess(AS_public);
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
- CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
SC_None,
SC_None, 0);
CopyAssignment->setParams(FromParam);
-
- // Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
- PushOnScopeChains(CopyAssignment, S, false);
- ClassDecl->addDecl(CopyAssignment);
-
+ AddOverriddenMethods(ClassDecl, CopyAssignment);
+
+ CopyAssignment->setTrivial(
+ ClassDecl->needsOverloadResolutionForCopyAssignment()
+ ? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
+ : ClassDecl->hasTrivialCopyAssignment());
+
// C++0x [class.copy]p19:
// .... If the class definition does not explicitly declare a copy
// assignment operator, there is no user-declared move constructor, and
if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
CopyAssignment->setDeletedAsWritten();
- AddOverriddenMethods(ClassDecl, CopyAssignment);
+ // Note that we have added this copy-assignment operator.
+ ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
+
+ if (Scope *S = getScopeForContext(ClassDecl))
+ PushOnScopeChains(CopyAssignment, S, false);
+ ClassDecl->addDecl(CopyAssignment);
+
return CopyAssignment;
}
MoveAssignment->setAccess(AS_public);
MoveAssignment->setDefaulted();
MoveAssignment->setImplicit();
- MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
SC_None, 0);
MoveAssignment->setParams(FromParam);
- // Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+ AddOverriddenMethods(ClassDecl, MoveAssignment);
+
+ MoveAssignment->setTrivial(
+ ClassDecl->needsOverloadResolutionForMoveAssignment()
+ ? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
+ : ClassDecl->hasTrivialMoveAssignment());
// C++0x [class.copy]p9:
// If the definition of a class X does not explicitly declare a move
return 0;
}
+ // Note that we have added this copy-assignment operator.
+ ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(MoveAssignment, S, false);
ClassDecl->addDecl(MoveAssignment);
- AddOverriddenMethods(ClassDecl, MoveAssignment);
return MoveAssignment;
}
Constexpr);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
- CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
CopyConstructor->setType(
Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
- // Note that we have declared this constructor.
- ++ASTContext::NumImplicitCopyConstructorsDeclared;
-
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
ClassLoc, ClassLoc,
SC_None, 0);
CopyConstructor->setParams(FromParam);
- if (Scope *S = getScopeForContext(ClassDecl))
- PushOnScopeChains(CopyConstructor, S, false);
- ClassDecl->addDecl(CopyConstructor);
+ CopyConstructor->setTrivial(
+ ClassDecl->needsOverloadResolutionForCopyConstructor()
+ ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
+ : ClassDecl->hasTrivialCopyConstructor());
// C++11 [class.copy]p8:
// ... If the class definition does not explicitly declare a copy
if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
CopyConstructor->setDeletedAsWritten();
+ // Note that we have declared this constructor.
+ ++ASTContext::NumImplicitCopyConstructorsDeclared;
+
+ if (Scope *S = getScopeForContext(ClassDecl))
+ PushOnScopeChains(CopyConstructor, S, false);
+ ClassDecl->addDecl(CopyConstructor);
+
return CopyConstructor;
}
Constexpr);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
- MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
SC_None, 0);
MoveConstructor->setParams(FromParam);
+ MoveConstructor->setTrivial(
+ ClassDecl->needsOverloadResolutionForMoveConstructor()
+ ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
+ : ClassDecl->hasTrivialMoveConstructor());
+
// C++0x [class.copy]p9:
// If the definition of a class X does not explicitly declare a move
// constructor, one will be implicitly declared as defaulted if and only if:
Data.HasOnlyCMembers = Record[Idx++];
Data.HasInClassInitializer = Record[Idx++];
Data.HasUninitializedReferenceMember = Record[Idx++];
+ Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++];
+ Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++];
+ Data.NeedOverloadResolutionForDestructor = Record[Idx++];
+ Data.DefaultedMoveConstructorIsDeleted = Record[Idx++];
+ Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++];
+ Data.DefaultedDestructorIsDeleted = Record[Idx++];
Data.HasTrivialSpecialMembers = Record[Idx++];
Data.HasIrrelevantDestructor = Record[Idx++];
Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
Record.push_back(Data.HasOnlyCMembers);
Record.push_back(Data.HasInClassInitializer);
Record.push_back(Data.HasUninitializedReferenceMember);
+ Record.push_back(Data.NeedOverloadResolutionForMoveConstructor);
+ Record.push_back(Data.NeedOverloadResolutionForMoveAssignment);
+ Record.push_back(Data.NeedOverloadResolutionForDestructor);
+ Record.push_back(Data.DefaultedMoveConstructorIsDeleted);
+ Record.push_back(Data.DefaultedMoveAssignmentIsDeleted);
+ Record.push_back(Data.DefaultedDestructorIsDeleted);
Record.push_back(Data.HasTrivialSpecialMembers);
Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
// RUN: %clang_cc1 -std=c++11 -verify %s
+// expected-no-diagnostics
+
template<typename T, bool B> struct trivially_copyable_check {
static_assert(B == __has_trivial_copy(T), "");
static_assert(B == __is_trivially_constructible(T, T), "");
struct MutableTemplateCtorMember {
mutable TemplateCtor mtc;
};
-// FIXME: This is wrong! The "trivial" copy constructor calls the templated
-// constructor for the mutable member.
-static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); // expected-error {{}}
+static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), "");
static_assert(__is_trivially_constructible(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
struct MutableTemplateCtorMember2 {
MutableTemplateCtorMember2(const MutableTemplateCtorMember2 &) = default;
static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &&), "");
static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &&), "");
static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &&), "");
+
+struct TemplateCtorNoMove {
+ TemplateCtorNoMove(const TemplateCtorNoMove &) = default;
+ template<typename T> TemplateCtorNoMove(T &&);
+};
+static_assert(__is_trivially_constructible(TemplateCtorNoMove, const TemplateCtorNoMove &), "");
+static_assert(!__is_trivially_constructible(TemplateCtorNoMove, TemplateCtorNoMove &&), "");
+
+struct UseTemplateCtorNoMove {
+ TemplateCtorNoMove tcnm;
+};
+static_assert(__is_trivially_constructible(UseTemplateCtorNoMove, const UseTemplateCtorNoMove &), "");
+static_assert(!__is_trivially_constructible(UseTemplateCtorNoMove, UseTemplateCtorNoMove &&), "");
+
+struct TemplateCtorNoMoveSFINAE {
+ TemplateCtorNoMoveSFINAE(const TemplateCtorNoMoveSFINAE &) = default;
+ template<typename T, typename U = typename T::error> TemplateCtorNoMoveSFINAE(T &&);
+};
+static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, const TemplateCtorNoMoveSFINAE &), "");
+static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, TemplateCtorNoMoveSFINAE &&), "");
+
+struct UseTemplateCtorNoMoveSFINAE {
+ TemplateCtorNoMoveSFINAE tcnm;
+};
+static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, const UseTemplateCtorNoMoveSFINAE &), "");
+static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, UseTemplateCtorNoMoveSFINAE &&), "");
+
+namespace TrivialityDependsOnImplicitDeletion {
+ struct PrivateMove {
+ PrivateMove(const PrivateMove &) = default;
+ private:
+ PrivateMove(PrivateMove &&);
+ friend class Access;
+ };
+ static_assert(__is_trivially_constructible(PrivateMove, const PrivateMove &), "");
+ static_assert(!__is_trivially_constructible(PrivateMove, PrivateMove &&), "");
+
+ struct NoAccess {
+ PrivateMove pm;
+ // NoAccess's move would be deleted, so is suppressed,
+ // so moves of it use PrivateMove's copy ctor, which is trivial.
+ };
+ static_assert(__is_trivially_constructible(NoAccess, const NoAccess &), "");
+ static_assert(__is_trivially_constructible(NoAccess, NoAccess &&), "");
+ struct TopNoAccess : NoAccess {};
+ static_assert(__is_trivially_constructible(TopNoAccess, const TopNoAccess &), "");
+ static_assert(__is_trivially_constructible(TopNoAccess, TopNoAccess &&), "");
+
+ struct Access {
+ PrivateMove pm;
+ // NoAccess's move would *not* be deleted, so is *not* suppressed,
+ // so moves of it use PrivateMove's move ctor, which is not trivial.
+ };
+ static_assert(__is_trivially_constructible(Access, const Access &), "");
+ static_assert(!__is_trivially_constructible(Access, Access &&), "");
+ struct TopAccess : Access {};
+ static_assert(__is_trivially_constructible(TopAccess, const TopAccess &), "");
+ static_assert(!__is_trivially_constructible(TopAccess, TopAccess &&), "");
+}
+
+namespace TrivialityDependsOnDestructor {
+ class HasInaccessibleDestructor { ~HasInaccessibleDestructor() = default; };
+ struct HasImplicitlyDeletedDestructor : HasInaccessibleDestructor {};
+ struct HasImplicitlyDeletedCopyCtor : HasImplicitlyDeletedDestructor {
+ HasImplicitlyDeletedCopyCtor() = default;
+ template<typename T> HasImplicitlyDeletedCopyCtor(T &&);
+ // Copy ctor is deleted but trivial.
+ // Move ctor is suppressed.
+ HasImplicitlyDeletedCopyCtor(const HasImplicitlyDeletedCopyCtor&) = default;
+ HasImplicitlyDeletedCopyCtor(HasImplicitlyDeletedCopyCtor&&) = default;
+ };
+ struct Test : HasImplicitlyDeletedCopyCtor {
+ Test(const Test&) = default;
+ Test(Test&&) = default;
+ };
+ // Implicit copy ctor calls deleted trivial copy ctor.
+ static_assert(__has_trivial_copy(Test), "");
+ // This is false because the destructor is deleted.
+ static_assert(!__is_trivially_constructible(Test, const Test &), "");
+ // Implicit move ctor calls template ctor.
+ static_assert(!__is_trivially_constructible(Test, Test &&), "");
+
+ struct HasAccessibleDestructor { ~HasAccessibleDestructor() = default; };
+ struct HasImplicitlyDefaultedDestructor : HasAccessibleDestructor {};
+ struct HasImplicitlyDefaultedCopyCtor : HasImplicitlyDefaultedDestructor {
+ template<typename T> HasImplicitlyDefaultedCopyCtor(T &&);
+ // Copy ctor is trivial.
+ // Move ctor is trivial.
+ };
+ struct Test2 : HasImplicitlyDefaultedCopyCtor {};
+ // Implicit copy ctor calls trivial copy ctor.
+ static_assert(__has_trivial_copy(Test2), "");
+ static_assert(__is_trivially_constructible(Test2, const Test2 &), "");
+ // Implicit move ctor calls trivial move ctor.
+ static_assert(__is_trivially_constructible(Test2, Test2 &&), "");
+}
// RUN: %clang_cc1 -std=c++11 -verify %s
+// expected-no-diagnostics
+
template<typename T, bool B> struct trivially_assignable_check {
static_assert(B == __has_trivial_assign(T), "");
static_assert(B == __is_trivially_assignable(T&, T), "");
struct MutableTemplateCtorMember {
mutable TemplateCtor mtc;
};
-// FIXME: This is wrong! The "trivial" copy constructor calls the templated
-// constructor for the mutable member.
-static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); // expected-error {{}}
+static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), "");
static_assert(__is_trivially_assignable(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
// Both trivial and non-trivial special members.
static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), "");
static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), "");
static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), "");
+
+struct TemplateAssignNoMove {
+ TemplateAssignNoMove &operator=(const TemplateAssignNoMove &) = default;
+ template<typename T> TemplateAssignNoMove &operator=(T &&);
+};
+static_assert(__is_trivially_assignable(TemplateAssignNoMove, const TemplateAssignNoMove &), "");
+static_assert(!__is_trivially_assignable(TemplateAssignNoMove, TemplateAssignNoMove &&), "");
+
+struct UseTemplateAssignNoMove {
+ TemplateAssignNoMove tanm;
+};
+static_assert(__is_trivially_assignable(UseTemplateAssignNoMove, const UseTemplateAssignNoMove &), "");
+static_assert(!__is_trivially_assignable(UseTemplateAssignNoMove, UseTemplateAssignNoMove &&), "");
+
+struct TemplateAssignNoMoveSFINAE {
+ TemplateAssignNoMoveSFINAE &operator=(const TemplateAssignNoMoveSFINAE &) = default;
+ template<typename T, typename U = typename T::error> TemplateAssignNoMoveSFINAE &operator=(T &&);
+};
+static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, const TemplateAssignNoMoveSFINAE &), "");
+static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, TemplateAssignNoMoveSFINAE &&), "");
+
+struct UseTemplateAssignNoMoveSFINAE {
+ TemplateAssignNoMoveSFINAE tanm;
+};
+static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, const UseTemplateAssignNoMoveSFINAE &), "");
+static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, UseTemplateAssignNoMoveSFINAE &&), "");
+
+namespace TrivialityDependsOnImplicitDeletion {
+ struct PrivateMove {
+ PrivateMove &operator=(const PrivateMove &) = default;
+ private:
+ PrivateMove &operator=(PrivateMove &&);
+ friend class Access;
+ };
+ static_assert(__is_trivially_assignable(PrivateMove, const PrivateMove &), "");
+ static_assert(!__is_trivially_assignable(PrivateMove, PrivateMove &&), "");
+
+ struct NoAccess {
+ PrivateMove pm;
+ // NoAccess's move would be deleted, so is suppressed,
+ // so moves of it use PrivateMove's copy ctor, which is trivial.
+ };
+ static_assert(__is_trivially_assignable(NoAccess, const NoAccess &), "");
+ static_assert(__is_trivially_assignable(NoAccess, NoAccess &&), "");
+ struct TopNoAccess : NoAccess {};
+ static_assert(__is_trivially_assignable(TopNoAccess, const TopNoAccess &), "");
+ static_assert(__is_trivially_assignable(TopNoAccess, TopNoAccess &&), "");
+
+ struct Access {
+ PrivateMove pm;
+ // NoAccess's move would *not* be deleted, so is *not* suppressed,
+ // so moves of it use PrivateMove's move ctor, which is not trivial.
+ };
+ static_assert(__is_trivially_assignable(Access, const Access &), "");
+ static_assert(!__is_trivially_assignable(Access, Access &&), "");
+ struct TopAccess : Access {};
+ static_assert(__is_trivially_assignable(TopAccess, const TopAccess &), "");
+ static_assert(!__is_trivially_assignable(TopAccess, TopAccess &&), "");
+}
~quux() = default;
};
+struct A {
+ A(const A&) = default;
+ template<typename T> A(T&&);
+};
+
#else
foo::foo() { } // expected-error{{definition of explicitly defaulted default constructor}}
baz bz; // expected-error{{deleted function}} expected-note@16{{deleted here}}
quux qx; // expected-error{{private destructor}} expected-note@20{{private here}}
+struct B { A a; };
+struct C { mutable A a; };
+static_assert(__is_trivially_constructible(B, const B&), "");
+static_assert(!__is_trivially_constructible(B, B&&), "");
+static_assert(!__is_trivially_constructible(C, const C&), "");
+static_assert(!__is_trivially_constructible(C, C&&), "");
+
#endif
{ int arr[T(__has_trivial_copy(AllDefaulted))]; }
{ int arr[T(__has_trivial_copy(AllDeleted))]; }
{ int arr[T(__has_trivial_copy(DerivesAr))]; }
+ { int arr[T(__has_trivial_copy(DerivesHasRef))]; }
{ int arr[F(__has_trivial_copy(HasCopy))]; }
{ int arr[F(__has_trivial_copy(HasTemplateCons))]; }
{ int arr[T(__has_trivial_assign(AllDefaulted))]; }
{ int arr[T(__has_trivial_assign(AllDeleted))]; }
{ int arr[T(__has_trivial_assign(DerivesAr))]; }
+ { int arr[T(__has_trivial_assign(DerivesHasRef))]; }
{ int arr[F(__has_trivial_assign(IntRef))]; }
{ int arr[F(__has_trivial_assign(HasCopyAssign))]; }
{ int arr[T(__has_trivial_destructor(VirtAr))]; }
{ int arr[T(__has_trivial_destructor(AllDefaulted))]; }
{ int arr[T(__has_trivial_destructor(AllDeleted))]; }
+ { int arr[T(__has_trivial_destructor(DerivesHasRef))]; }
{ int arr[F(__has_trivial_destructor(HasDest))]; }
{ int arr[F(__has_trivial_destructor(void))]; }