forked from OSchip/llvm-project
Properly compute triviality for explicitly-defaulted or deleted special members.
Remove pre-standard restriction on explicitly-defaulted copy constructors with 'incorrect' parameter types, and instead just make those special members non-trivial as the standard requires. This required making CXXRecordDecl correctly handle classes which have both a trivial and a non-trivial special member of the same kind. This also fixes PR13217 by reimplementing DiagnoseNontrivial in terms of the new triviality computation technology. llvm-svn: 169667
This commit is contained in:
parent
f77b0f8886
commit
92f241f188
|
@ -1736,7 +1736,7 @@ public:
|
|||
|
||||
/// Whether this is a (C++11) constexpr function or constexpr constructor.
|
||||
bool isConstexpr() const { return IsConstexpr; }
|
||||
void setConstexpr(bool IC);
|
||||
void setConstexpr(bool IC) { IsConstexpr = IC; }
|
||||
|
||||
/// \brief Whether this function has been deleted.
|
||||
///
|
||||
|
|
|
@ -360,9 +360,20 @@ class CXXRecordDecl : public RecordDecl {
|
|||
|
||||
/// \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.
|
||||
/// C++11 [class.dtor]p5, or would have if the member were not suppressed.
|
||||
///
|
||||
/// This excludes any user-declared but not user-provided special members
|
||||
/// which have been declared but not yet defined.
|
||||
unsigned HasTrivialSpecialMembers : 6;
|
||||
|
||||
/// \brief The declared special members of this class which are known to be
|
||||
/// non-trivial.
|
||||
///
|
||||
/// This excludes any user-declared but not user-provided special members
|
||||
/// which have been declared but not yet defined, and any implicit special
|
||||
/// members which have not yet been declared.
|
||||
unsigned DeclaredNonTrivialSpecialMembers : 6;
|
||||
|
||||
/// HasIrrelevantDestructor - True when this class has a destructor with no
|
||||
/// semantic effect.
|
||||
bool HasIrrelevantDestructor : 1;
|
||||
|
@ -565,9 +576,6 @@ class CXXRecordDecl : public RecordDecl {
|
|||
void markedVirtualFunctionPure();
|
||||
friend void FunctionDecl::setPure(bool);
|
||||
|
||||
void markedConstructorConstexpr(CXXConstructorDecl *CD);
|
||||
friend void FunctionDecl::setConstexpr(bool);
|
||||
|
||||
friend class ASTNodeImporter;
|
||||
|
||||
protected:
|
||||
|
@ -1035,7 +1043,6 @@ public:
|
|||
|
||||
/// \brief Determine whether this class has a trivial default constructor
|
||||
/// (C++11 [class.ctor]p5).
|
||||
/// FIXME: This can be wrong when the class has multiple default constructors.
|
||||
bool hasTrivialDefaultConstructor() const {
|
||||
return hasDefaultConstructor() &&
|
||||
(data().HasTrivialSpecialMembers & SMF_DefaultConstructor);
|
||||
|
@ -1044,8 +1051,9 @@ public:
|
|||
/// \brief Determine whether this class has a non-trivial default constructor
|
||||
/// (C++11 [class.ctor]p5).
|
||||
bool hasNonTrivialDefaultConstructor() const {
|
||||
return hasDefaultConstructor() &&
|
||||
!(data().HasTrivialSpecialMembers & SMF_DefaultConstructor);
|
||||
return (data().DeclaredNonTrivialSpecialMembers & SMF_DefaultConstructor) ||
|
||||
(needsImplicitDefaultConstructor() &&
|
||||
!(data().HasTrivialSpecialMembers & SMF_DefaultConstructor));
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has at least one constexpr constructor
|
||||
|
@ -1072,7 +1080,6 @@ public:
|
|||
|
||||
/// \brief Determine whether this class has a trivial copy constructor
|
||||
/// (C++ [class.copy]p6, C++11 [class.copy]p12)
|
||||
/// FIXME: This can be wrong if the class has multiple copy constructors.
|
||||
bool hasTrivialCopyConstructor() const {
|
||||
return data().HasTrivialSpecialMembers & SMF_CopyConstructor;
|
||||
}
|
||||
|
@ -1080,13 +1087,14 @@ public:
|
|||
/// \brief Determine whether this class has a non-trivial copy constructor
|
||||
/// (C++ [class.copy]p6, C++11 [class.copy]p12)
|
||||
bool hasNonTrivialCopyConstructor() const {
|
||||
return !(data().HasTrivialSpecialMembers & SMF_CopyConstructor);
|
||||
return data().DeclaredNonTrivialSpecialMembers & SMF_CopyConstructor ||
|
||||
!hasTrivialCopyConstructor();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has a trivial move constructor
|
||||
/// (C++11 [class.copy]p12)
|
||||
/// FIXME: This can be wrong if the class has multiple move constructors,
|
||||
/// or if the implicit move constructor would be deleted.
|
||||
/// FIXME: This can be wrong if the implicit move constructor would be
|
||||
/// deleted.
|
||||
bool hasTrivialMoveConstructor() const {
|
||||
return hasMoveConstructor() &&
|
||||
(data().HasTrivialSpecialMembers & SMF_MoveConstructor);
|
||||
|
@ -1097,14 +1105,13 @@ public:
|
|||
/// FIXME: This can be wrong if the implicit move constructor would be
|
||||
/// deleted.
|
||||
bool hasNonTrivialMoveConstructor() const {
|
||||
return hasMoveConstructor() &&
|
||||
!(data().HasTrivialSpecialMembers & SMF_MoveConstructor);
|
||||
return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) ||
|
||||
(needsImplicitMoveConstructor() &&
|
||||
!(data().HasTrivialSpecialMembers & SMF_MoveConstructor));
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has a trivial copy assignment operator
|
||||
/// (C++ [class.copy]p11, C++11 [class.copy]p25)
|
||||
/// FIXME: This can be wrong if the class has multiple copy assignment
|
||||
/// operators.
|
||||
bool hasTrivialCopyAssignment() const {
|
||||
return data().HasTrivialSpecialMembers & SMF_CopyAssignment;
|
||||
}
|
||||
|
@ -1112,13 +1119,13 @@ public:
|
|||
/// \brief Determine whether this class has a non-trivial copy assignment
|
||||
/// operator (C++ [class.copy]p11, C++11 [class.copy]p25)
|
||||
bool hasNonTrivialCopyAssignment() const {
|
||||
return !(data().HasTrivialSpecialMembers & SMF_CopyAssignment);
|
||||
return data().DeclaredNonTrivialSpecialMembers & SMF_CopyAssignment ||
|
||||
!hasTrivialCopyAssignment();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has a trivial move assignment operator
|
||||
/// (C++11 [class.copy]p25)
|
||||
/// FIXME: This can be wrong if the class has multiple move assignment
|
||||
/// operators, or if the implicit move assignment operator would be deleted.
|
||||
/// FIXME: This can be wrong if the implicit move assignment would be deleted.
|
||||
bool hasTrivialMoveAssignment() const {
|
||||
return hasMoveAssignment() &&
|
||||
(data().HasTrivialSpecialMembers & SMF_MoveAssignment);
|
||||
|
@ -1128,8 +1135,9 @@ public:
|
|||
/// operator (C++11 [class.copy]p25)
|
||||
/// FIXME: This can be wrong if the implicit move assignment would be deleted.
|
||||
bool hasNonTrivialMoveAssignment() const {
|
||||
return hasMoveAssignment() &&
|
||||
!(data().HasTrivialSpecialMembers & SMF_MoveAssignment);
|
||||
return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveAssignment) ||
|
||||
(needsImplicitMoveAssignment() &&
|
||||
!(data().HasTrivialSpecialMembers & SMF_MoveAssignment));
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has a trivial destructor
|
||||
|
@ -1447,6 +1455,10 @@ public:
|
|||
return (PathAccess > DeclAccess ? PathAccess : DeclAccess);
|
||||
}
|
||||
|
||||
/// \brief Indicates that the declaration of a defaulted or deleted special
|
||||
/// member function is now complete.
|
||||
void finishedDefaultedOrDeletedMember(CXXMethodDecl *MD);
|
||||
|
||||
/// \brief Indicates that the definition of this class is now complete.
|
||||
virtual void completeDefinition();
|
||||
|
||||
|
|
|
@ -1073,6 +1073,7 @@ def err_missing_default_ctor : Error<
|
|||
"%select{|implicit default }0constructor for %1 must explicitly initialize "
|
||||
"the %select{base class|member}2 %3 which does not have a default "
|
||||
"constructor">;
|
||||
|
||||
def err_illegal_union_or_anon_struct_member : Error<
|
||||
"%select{anonymous struct|union}0 member %1 has a non-trivial "
|
||||
"%select{constructor|copy constructor|move constructor|copy assignment "
|
||||
|
@ -1082,16 +1083,40 @@ def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning<
|
|||
"%select{constructor|copy constructor|move constructor|copy assignment "
|
||||
"operator|move assignment operator|destructor}2 is incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
|
||||
def note_nontrivial_virtual_dtor : Note<
|
||||
"destructor for %0 is not trivial because it is virtual">;
|
||||
def note_nontrivial_has_virtual : Note<
|
||||
"because type %0 has a virtual %select{member function|base class}1">;
|
||||
def note_nontrivial_has_nontrivial : Note<
|
||||
"because type %0 has a %select{member|base class}1 with a non-trivial "
|
||||
"%select{constructor|copy constructor|move constructor|copy assignment "
|
||||
"operator|move assignment operator|destructor}2">;
|
||||
def note_nontrivial_user_defined : Note<
|
||||
"because type %0 has a user-declared %select{constructor|copy constructor|"
|
||||
"move constructor|copy assignment operator|move assignment operator|"
|
||||
"destructor}1">;
|
||||
def note_nontrivial_no_def_ctor : Note<
|
||||
"because %select{base class of |field of |}0type %1 has no "
|
||||
"default constructor">;
|
||||
def note_user_declared_ctor : Note<
|
||||
"implicit default constructor suppressed by user-declared constructor">;
|
||||
def note_nontrivial_no_copy : Note<
|
||||
"because no %select{<<ERROR>>|constructor|constructor|assignment operator|"
|
||||
"assignment operator|<<ERROR>>}2 can be used to "
|
||||
"%select{<<ERROR>>|copy|move|copy|move|<<ERROR>>}2 "
|
||||
"%select{base class|field|an object}0 of type %3">;
|
||||
def note_nontrivial_user_provided : Note<
|
||||
"because %select{base class of |field of |}0type %1 has a user-provided "
|
||||
"%select{default constructor|copy constructor|move constructor|"
|
||||
"copy assignment operator|move assignment operator|destructor}2">;
|
||||
def note_nontrivial_in_class_init : Note<
|
||||
"because field %0 has an initializer">;
|
||||
def note_nontrivial_param_type : Note<
|
||||
"because its parameter is %diff{of type $, not $|of the wrong type}2,3">;
|
||||
def note_nontrivial_default_arg : Note<"because it has a default argument">;
|
||||
def note_nontrivial_variadic : Note<"because it is a variadic function">;
|
||||
def note_nontrivial_subobject : Note<
|
||||
"because the function selected to %select{construct|copy|move|copy|move|"
|
||||
"destroy}2 %select{base class|field}0 of type %1 is not trivial">;
|
||||
def note_nontrivial_user_declared_ctor : Note<
|
||||
"because type %0 has a user-declared constructor">;
|
||||
def note_nontrivial_objc_ownership : Note<
|
||||
"because type %0 has a member with %select{no|no|__strong|__weak|"
|
||||
"__autoreleasing}1 ownership">;
|
||||
|
||||
def err_static_data_member_not_allowed_in_anon_struct : Error<
|
||||
"static data member %0 not allowed in anonymous struct">;
|
||||
def ext_static_data_member_in_union : ExtWarn<
|
||||
|
@ -3706,9 +3731,6 @@ def note_arc_retain_cycle_owner : Note<
|
|||
|
||||
} // end "ARC Retain Cycle" category
|
||||
|
||||
def note_nontrivial_objc_ownership : Note<
|
||||
"because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 "
|
||||
"ownership">;
|
||||
def warn_arc_object_memaccess : Warning<
|
||||
"%select{destination for|source of}0 this %1 call is a pointer to "
|
||||
"ownership-qualified type %2">, InGroup<ARCNonPodMemAccess>;
|
||||
|
@ -5429,10 +5451,6 @@ def err_defaulted_special_member_copy_const_param : Error<
|
|||
"the parameter for this explicitly-defaulted copy "
|
||||
"%select{constructor|assignment operator}0 is const, but a member or base "
|
||||
"requires it to be non-const">;
|
||||
def err_defaulted_special_member_copy_non_const_param : Error<
|
||||
"explicitly-defaulted copy %select{constructor|assignment operator}0 with "
|
||||
"a non-const parameter must be defaulted outside the class, unless a base or "
|
||||
"member requires the parameter to be non-const">;
|
||||
def err_defaulted_copy_assign_not_ref : Error<
|
||||
"the parameter for an explicitly-defaulted copy assignment operator must be an "
|
||||
"lvalue reference type">;
|
||||
|
|
|
@ -1530,7 +1530,9 @@ public:
|
|||
Declarator *D = 0);
|
||||
|
||||
bool CheckNontrivialField(FieldDecl *FD);
|
||||
void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
|
||||
void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM);
|
||||
bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
|
||||
bool Diagnose = false);
|
||||
CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
|
||||
void ActOnLastBitfield(SourceLocation DeclStart,
|
||||
SmallVectorImpl<Decl *> &AllIvarDecls);
|
||||
|
@ -4438,7 +4440,7 @@ public:
|
|||
StorageClass& SC);
|
||||
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
|
||||
|
||||
void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record);
|
||||
void CheckExplicitlyDefaultedAndDeletedMethods(CXXRecordDecl *Record);
|
||||
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -1658,13 +1658,6 @@ void FunctionDecl::setPure(bool P) {
|
|||
Parent->markedVirtualFunctionPure();
|
||||
}
|
||||
|
||||
void FunctionDecl::setConstexpr(bool IC) {
|
||||
IsConstexpr = IC;
|
||||
CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(this);
|
||||
if (IC && CD)
|
||||
CD->getParent()->markedConstructorConstexpr(CD);
|
||||
}
|
||||
|
||||
bool FunctionDecl::isMain() const {
|
||||
const TranslationUnitDecl *tunit =
|
||||
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
|
||||
|
|
|
@ -43,6 +43,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
|||
HasMutableFields(false), HasOnlyCMembers(true),
|
||||
HasInClassInitializer(false), HasUninitializedReferenceMember(false),
|
||||
HasTrivialSpecialMembers(SMF_All),
|
||||
DeclaredNonTrivialSpecialMembers(0),
|
||||
HasIrrelevantDestructor(true),
|
||||
HasConstexprNonCopyMoveConstructor(false),
|
||||
DefaultedDefaultConstructorIsConstexpr(true),
|
||||
|
@ -261,7 +262,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
|||
if (!BaseClassDecl->hasConstexprDefaultConstructor())
|
||||
data().DefaultedDefaultConstructorIsConstexpr = false;
|
||||
}
|
||||
|
||||
|
||||
// C++ [class.ctor]p3:
|
||||
// A destructor is trivial if all the direct base classes of its class
|
||||
// have trivial destructors.
|
||||
|
@ -470,14 +471,6 @@ void CXXRecordDecl::markedVirtualFunctionPure() {
|
|||
data().Abstract = true;
|
||||
}
|
||||
|
||||
void CXXRecordDecl::markedConstructorConstexpr(CXXConstructorDecl *CD) {
|
||||
if (!CD->isCopyOrMoveConstructor())
|
||||
data().HasConstexprNonCopyMoveConstructor = true;
|
||||
|
||||
if (CD->isDefaultConstructor())
|
||||
data().HasConstexprDefaultConstructor = true;
|
||||
}
|
||||
|
||||
void CXXRecordDecl::addedMember(Decl *D) {
|
||||
if (!D->isImplicit() &&
|
||||
!isa<FieldDecl>(D) &&
|
||||
|
@ -638,6 +631,20 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
|||
}
|
||||
|
||||
if (SMKind) {
|
||||
// If this is the first declaration of a special member, we no longer have
|
||||
// an implicit trivial special member.
|
||||
data().HasTrivialSpecialMembers &=
|
||||
data().DeclaredSpecialMembers | ~SMKind;
|
||||
|
||||
if (!Method->isImplicit() && !Method->isUserProvided()) {
|
||||
// This method is user-declared but not user-provided. We can't work out
|
||||
// whether it's trivial yet (not until we get to the end of the class).
|
||||
// We'll handle this method in finishedDefaultedOrDeletedMember.
|
||||
} else if (Method->isTrivial())
|
||||
data().HasTrivialSpecialMembers |= SMKind;
|
||||
else
|
||||
data().DeclaredNonTrivialSpecialMembers |= SMKind;
|
||||
|
||||
// Note when we have declared a declared special member, and suppress the
|
||||
// implicit declaration of this special member.
|
||||
data().DeclaredSpecialMembers |= SMKind;
|
||||
|
@ -658,14 +665,6 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
|||
// This is an extension in C++03.
|
||||
data().PlainOldData = false;
|
||||
}
|
||||
|
||||
// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25,
|
||||
// C++11 [class.dtor]p5:
|
||||
// A [special member] is trivial if it is not user-provided [...]
|
||||
// FIXME: This is bogus. A class can have both (say) a trivial copy
|
||||
// constructor *and* a user-provided copy constructor.
|
||||
if (Method->isUserProvided())
|
||||
data().HasTrivialSpecialMembers &= ~SMKind;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -910,6 +909,40 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
|||
data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
|
||||
}
|
||||
|
||||
void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
|
||||
assert(!D->isImplicit() && !D->isUserProvided());
|
||||
|
||||
// The kind of special member this declaration is, if any.
|
||||
unsigned SMKind = 0;
|
||||
|
||||
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||
if (Constructor->isDefaultConstructor()) {
|
||||
SMKind |= SMF_DefaultConstructor;
|
||||
if (Constructor->isConstexpr())
|
||||
data().HasConstexprDefaultConstructor = true;
|
||||
}
|
||||
if (Constructor->isCopyConstructor())
|
||||
SMKind |= SMF_CopyConstructor;
|
||||
else if (Constructor->isMoveConstructor())
|
||||
SMKind |= SMF_MoveConstructor;
|
||||
else if (Constructor->isConstexpr())
|
||||
// We may now know that the constructor is constexpr.
|
||||
data().HasConstexprNonCopyMoveConstructor = true;
|
||||
} else if (isa<CXXDestructorDecl>(D))
|
||||
SMKind |= SMF_Destructor;
|
||||
else if (D->isCopyAssignmentOperator())
|
||||
SMKind |= SMF_CopyAssignment;
|
||||
else if (D->isMoveAssignmentOperator())
|
||||
SMKind |= SMF_MoveAssignment;
|
||||
|
||||
// Update which trivial / non-trivial special members we have.
|
||||
// addedMember will have skipped this step for this member.
|
||||
if (D->isTrivial())
|
||||
data().HasTrivialSpecialMembers |= SMKind;
|
||||
else
|
||||
data().DeclaredNonTrivialSpecialMembers |= SMKind;
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::isCLike() const {
|
||||
if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface ||
|
||||
!TemplateOrInstantiation.isNull())
|
||||
|
|
|
@ -9772,7 +9772,7 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
|
|||
|
||||
QualType EltTy = Context.getBaseElementType(FD->getType());
|
||||
if (const RecordType *RT = EltTy->getAs<RecordType>()) {
|
||||
CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
|
||||
CXXRecordDecl *RDecl = cast<CXXRecordDecl>(RT->getDecl());
|
||||
if (RDecl->getDefinition()) {
|
||||
// We check for copy constructors before constructors
|
||||
// because otherwise we'll never get complaints about
|
||||
|
@ -9814,194 +9814,15 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
|
|||
diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member :
|
||||
diag::err_illegal_union_or_anon_struct_member)
|
||||
<< (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
|
||||
DiagnoseNontrivial(RT, member);
|
||||
DiagnoseNontrivial(RDecl, member);
|
||||
return !getLangOpts().CPlusPlus0x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// If the given constructor is user-declared, produce a diagnostic explaining
|
||||
/// that it makes the class non-trivial.
|
||||
static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT,
|
||||
CXXConstructorDecl *CD,
|
||||
Sema::CXXSpecialMember CSM) {
|
||||
if (CD->isImplicit())
|
||||
return false;
|
||||
|
||||
SourceLocation CtorLoc = CD->getLocation();
|
||||
S.Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << CSM;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// DiagnoseNontrivial - Given that a class has a non-trivial
|
||||
/// special member, figure out why.
|
||||
/// FIXME: These checks are not correct in C++11 mode. Currently, this is OK
|
||||
/// since we only use this in C++11 for a -Wc++98-compat warning.
|
||||
void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
|
||||
QualType QT(T, 0U);
|
||||
CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
|
||||
|
||||
// Check whether the member was user-declared.
|
||||
switch (member) {
|
||||
case CXXInvalid:
|
||||
break;
|
||||
|
||||
case CXXDefaultConstructor:
|
||||
if (RD->hasUserDeclaredConstructor()) {
|
||||
typedef CXXRecordDecl::ctor_iterator ctor_iter;
|
||||
for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI)
|
||||
if (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member))
|
||||
return;
|
||||
|
||||
// No user-delcared constructors; look for constructor templates.
|
||||
typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
|
||||
tmpl_iter;
|
||||
for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end());
|
||||
TI != TE; ++TI) {
|
||||
CXXConstructorDecl *CD =
|
||||
dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl());
|
||||
if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member))
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CXXCopyConstructor:
|
||||
if (RD->hasUserDeclaredCopyConstructor()) {
|
||||
SourceLocation CtorLoc =
|
||||
RD->getCopyConstructor(0)->getLocation();
|
||||
Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case CXXMoveConstructor:
|
||||
if (RD->hasUserDeclaredMoveConstructor()) {
|
||||
SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation();
|
||||
Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case CXXCopyAssignment:
|
||||
if (RD->hasUserDeclaredCopyAssignment()) {
|
||||
SourceLocation AssignLoc =
|
||||
RD->getCopyAssignmentOperator(0)->getLocation();
|
||||
Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case CXXMoveAssignment:
|
||||
if (RD->hasUserDeclaredMoveAssignment()) {
|
||||
SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation();
|
||||
Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case CXXDestructor:
|
||||
if (RD->hasUserDeclaredDestructor()) {
|
||||
SourceLocation DtorLoc = LookupDestructor(RD)->getLocation();
|
||||
Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
typedef CXXRecordDecl::base_class_iterator base_iter;
|
||||
|
||||
// Virtual bases and members inhibit trivial copying/construction,
|
||||
// but not trivial destruction.
|
||||
if (member != CXXDestructor) {
|
||||
// Check for virtual bases. vbases includes indirect virtual bases,
|
||||
// so we just iterate through the direct bases.
|
||||
for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi)
|
||||
if (bi->isVirtual()) {
|
||||
SourceLocation BaseLoc = bi->getLocStart();
|
||||
Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for virtual methods.
|
||||
typedef CXXRecordDecl::method_iterator meth_iter;
|
||||
for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
|
||||
++mi) {
|
||||
if (mi->isVirtual()) {
|
||||
SourceLocation MLoc = mi->getLocStart();
|
||||
Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool (CXXRecordDecl::*hasNonTrivial)() const;
|
||||
switch (member) {
|
||||
case CXXDefaultConstructor:
|
||||
hasNonTrivial = &CXXRecordDecl::hasNonTrivialDefaultConstructor; break;
|
||||
case CXXCopyConstructor:
|
||||
hasNonTrivial = &CXXRecordDecl::hasNonTrivialCopyConstructor; break;
|
||||
case CXXCopyAssignment:
|
||||
hasNonTrivial = &CXXRecordDecl::hasNonTrivialCopyAssignment; break;
|
||||
case CXXMoveConstructor:
|
||||
hasNonTrivial = &CXXRecordDecl::hasNonTrivialMoveConstructor; break;
|
||||
case CXXMoveAssignment:
|
||||
hasNonTrivial = &CXXRecordDecl::hasNonTrivialMoveAssignment; break;
|
||||
case CXXDestructor:
|
||||
hasNonTrivial = &CXXRecordDecl::hasNonTrivialDestructor; break;
|
||||
case CXXInvalid:
|
||||
llvm_unreachable("unexpected special member");
|
||||
}
|
||||
|
||||
// Check for nontrivial bases (and recurse).
|
||||
for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) {
|
||||
const RecordType *BaseRT = bi->getType()->getAs<RecordType>();
|
||||
assert(BaseRT && "Don't know how to handle dependent bases");
|
||||
CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
|
||||
if ((BaseRecTy->*hasNonTrivial)()) {
|
||||
SourceLocation BaseLoc = bi->getLocStart();
|
||||
Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
|
||||
DiagnoseNontrivial(BaseRT, member);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for nontrivial members (and recurse).
|
||||
typedef RecordDecl::field_iterator field_iter;
|
||||
for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
|
||||
++fi) {
|
||||
QualType EltTy = Context.getBaseElementType(fi->getType());
|
||||
if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
|
||||
CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
|
||||
|
||||
if ((EltRD->*hasNonTrivial)()) {
|
||||
SourceLocation FLoc = fi->getLocation();
|
||||
Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
|
||||
DiagnoseNontrivial(EltRT, member);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (EltTy->isObjCLifetimeType()) {
|
||||
switch (EltTy.getObjCLifetime()) {
|
||||
case Qualifiers::OCL_None:
|
||||
case Qualifiers::OCL_ExplicitNone:
|
||||
break;
|
||||
|
||||
case Qualifiers::OCL_Autoreleasing:
|
||||
case Qualifiers::OCL_Weak:
|
||||
case Qualifiers::OCL_Strong:
|
||||
Diag(fi->getLocation(), diag::note_nontrivial_objc_ownership)
|
||||
<< QT << EltTy.getObjCLifetime();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TranslateIvarVisibility - Translate visibility from a token ID to an
|
||||
/// AST enum value.
|
||||
static ObjCIvarDecl::AccessControl
|
||||
|
|
|
@ -3990,42 +3990,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
|
|||
}
|
||||
}
|
||||
|
||||
// C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
|
||||
// function that is not a constructor declares that member function to be
|
||||
// const. [...] The class of which that function is a member shall be
|
||||
// a literal type.
|
||||
//
|
||||
// If the class has virtual bases, any constexpr members will already have
|
||||
// been diagnosed by the checks performed on the member declaration, so
|
||||
// suppress this (less useful) diagnostic.
|
||||
if (LangOpts.CPlusPlus0x && !Record->isDependentType() &&
|
||||
!Record->isLiteral() && !Record->getNumVBases()) {
|
||||
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
|
||||
MEnd = Record->method_end();
|
||||
M != MEnd; ++M) {
|
||||
if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
|
||||
switch (Record->getTemplateSpecializationKind()) {
|
||||
case TSK_ImplicitInstantiation:
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
// If a template instantiates to a non-literal type, but its members
|
||||
// instantiate to constexpr functions, the template is technically
|
||||
// ill-formed, but we allow it for sanity.
|
||||
continue;
|
||||
|
||||
case TSK_Undeclared:
|
||||
case TSK_ExplicitSpecialization:
|
||||
RequireLiteralType(M->getLocation(), Context.getRecordType(Record),
|
||||
diag::err_constexpr_method_non_literal);
|
||||
break;
|
||||
}
|
||||
|
||||
// Only produce one error per class.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Declare inherited constructors. We do this eagerly here because:
|
||||
// - The standard requires an eager diagnostic for conflicting inherited
|
||||
// constructors from different classes.
|
||||
|
@ -4036,12 +4000,25 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
|
|||
DeclareInheritedConstructors(Record);
|
||||
}
|
||||
|
||||
void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
|
||||
void Sema::CheckExplicitlyDefaultedAndDeletedMethods(CXXRecordDecl *Record) {
|
||||
for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
|
||||
ME = Record->method_end();
|
||||
MI != ME; ++MI)
|
||||
MI != ME; ++MI) {
|
||||
if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted())
|
||||
CheckExplicitlyDefaultedSpecialMember(*MI);
|
||||
|
||||
if (!MI->isImplicit() && !MI->isUserProvided()) {
|
||||
// For an explicitly defaulted or deleted special member, we defer
|
||||
// determining triviality until the class is complete. That time is now!
|
||||
CXXSpecialMember CSM = getSpecialMember(*MI);
|
||||
if (CSM != CXXInvalid) {
|
||||
MI->setTrivial(SpecialMemberIsTrivial(*MI, CSM));
|
||||
|
||||
// Inform the class that we've finished declaring this member.
|
||||
Record->finishedDefaultedOrDeletedMember(*MI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the special member function which would be selected to perform the
|
||||
|
@ -4231,33 +4208,11 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
|||
|
||||
const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>();
|
||||
|
||||
// Compute argument constness, constexpr, and triviality.
|
||||
bool CanHaveConstParam = false;
|
||||
bool Trivial = false;
|
||||
switch (CSM) {
|
||||
case CXXDefaultConstructor:
|
||||
Trivial = RD->hasTrivialDefaultConstructor();
|
||||
break;
|
||||
case CXXCopyConstructor:
|
||||
if (CSM == CXXCopyConstructor)
|
||||
CanHaveConstParam = RD->implicitCopyConstructorHasConstParam();
|
||||
Trivial = RD->hasTrivialCopyConstructor();
|
||||
break;
|
||||
case CXXCopyAssignment:
|
||||
else if (CSM == CXXCopyAssignment)
|
||||
CanHaveConstParam = RD->implicitCopyAssignmentHasConstParam();
|
||||
Trivial = RD->hasTrivialCopyAssignment();
|
||||
break;
|
||||
case CXXMoveConstructor:
|
||||
Trivial = RD->hasTrivialMoveConstructor();
|
||||
break;
|
||||
case CXXMoveAssignment:
|
||||
Trivial = RD->hasTrivialMoveAssignment();
|
||||
break;
|
||||
case CXXDestructor:
|
||||
Trivial = RD->hasTrivialDestructor();
|
||||
break;
|
||||
case CXXInvalid:
|
||||
llvm_unreachable("non-special member explicitly defaulted!");
|
||||
}
|
||||
|
||||
QualType ReturnType = Context.VoidTy;
|
||||
if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) {
|
||||
|
@ -4306,14 +4261,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
|||
}
|
||||
HadError = true;
|
||||
}
|
||||
|
||||
// If a function is explicitly defaulted on its first declaration, it shall
|
||||
// have the same parameter type as if it had been implicitly declared.
|
||||
// (Presumably this is to prevent it from being trivial?)
|
||||
if (!HasConstParam && CanHaveConstParam && First)
|
||||
Diag(MD->getLocation(),
|
||||
diag::err_defaulted_special_member_copy_non_const_param)
|
||||
<< (CSM == CXXCopyAssignment);
|
||||
} else if (ExpectedParams) {
|
||||
// A copy assignment operator can take its argument by value, but a
|
||||
// defaulted one cannot.
|
||||
|
@ -4363,10 +4310,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
|||
// -- it is implicitly considered to have the same exception-specification
|
||||
// as if it had been implicitly declared,
|
||||
MD->setType(QualType(ImplicitType, 0));
|
||||
|
||||
// Such a function is also trivial if the implicitly-declared function
|
||||
// would have been.
|
||||
MD->setTrivial(Trivial);
|
||||
}
|
||||
|
||||
if (ShouldDeleteSpecialMember(MD, CSM)) {
|
||||
|
@ -4805,6 +4748,427 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Perform lookup for a special member of the specified kind, and determine
|
||||
/// whether it is trivial. If the triviality can be determined without the
|
||||
/// lookup, skip it. This is intended for use when determining whether a
|
||||
/// special member of a containing object is trivial, and thus does not ever
|
||||
/// perform overload resolution for default constructors.
|
||||
///
|
||||
/// If \p Selected is not \c NULL, \c *Selected will be filled in with the
|
||||
/// member that was most likely to be intended to be trivial, if any.
|
||||
static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
|
||||
Sema::CXXSpecialMember CSM, unsigned Quals,
|
||||
CXXMethodDecl **Selected) {
|
||||
if (Selected)
|
||||
*Selected = 0;
|
||||
|
||||
switch (CSM) {
|
||||
case Sema::CXXInvalid:
|
||||
llvm_unreachable("not a special member");
|
||||
|
||||
case Sema::CXXDefaultConstructor:
|
||||
// C++11 [class.ctor]p5:
|
||||
// A default constructor is trivial if:
|
||||
// - all the [direct subobjects] have trivial default constructors
|
||||
//
|
||||
// Note, no overload resolution is performed in this case.
|
||||
if (RD->hasTrivialDefaultConstructor())
|
||||
return true;
|
||||
|
||||
if (Selected) {
|
||||
// If there's a default constructor which could have been trivial, dig it
|
||||
// out. Otherwise, if there's any user-provided default constructor, point
|
||||
// to that as an example of why there's not a trivial one.
|
||||
CXXConstructorDecl *DefCtor = 0;
|
||||
if (RD->needsImplicitDefaultConstructor())
|
||||
S.DeclareImplicitDefaultConstructor(RD);
|
||||
for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(),
|
||||
CE = RD->ctor_end(); CI != CE; ++CI) {
|
||||
if (!CI->isDefaultConstructor())
|
||||
continue;
|
||||
DefCtor = *CI;
|
||||
if (!DefCtor->isUserProvided())
|
||||
break;
|
||||
}
|
||||
|
||||
*Selected = DefCtor;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
case Sema::CXXDestructor:
|
||||
// C++11 [class.dtor]p5:
|
||||
// A destructor is trivial if:
|
||||
// - all the direct [subobjects] have trivial destructors
|
||||
if (RD->hasTrivialDestructor())
|
||||
return true;
|
||||
|
||||
if (Selected) {
|
||||
if (RD->needsImplicitDestructor())
|
||||
S.DeclareImplicitDestructor(RD);
|
||||
*Selected = RD->getDestructor();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
case Sema::CXXCopyConstructor:
|
||||
// C++11 [class.copy]p12:
|
||||
// A copy constructor is trivial if:
|
||||
// - the constructor selected to copy each direct [subobject] is trivial
|
||||
if (RD->hasTrivialCopyConstructor()) {
|
||||
if (Quals == Qualifiers::Const)
|
||||
// We must either select the trivial copy constructor or reach an
|
||||
// ambiguity; no need to actually perform overload resolution.
|
||||
return true;
|
||||
} else if (!Selected) {
|
||||
return false;
|
||||
}
|
||||
// In C++98, we are not supposed to perform overload resolution here, but we
|
||||
// treat that as a language defect, as suggested on cxx-abi-dev, to treat
|
||||
// cases like B as having a non-trivial copy constructor:
|
||||
// struct A { template<typename T> A(T&); };
|
||||
// struct B { mutable A a; };
|
||||
goto NeedOverloadResolution;
|
||||
|
||||
case Sema::CXXCopyAssignment:
|
||||
// C++11 [class.copy]p25:
|
||||
// A copy assignment operator is trivial if:
|
||||
// - the assignment operator selected to copy each direct [subobject] is
|
||||
// trivial
|
||||
if (RD->hasTrivialCopyAssignment()) {
|
||||
if (Quals == Qualifiers::Const)
|
||||
return true;
|
||||
} else if (!Selected) {
|
||||
return false;
|
||||
}
|
||||
// In C++98, we are not supposed to perform overload resolution here, but we
|
||||
// treat that as a language defect.
|
||||
goto NeedOverloadResolution;
|
||||
|
||||
case Sema::CXXMoveConstructor:
|
||||
case Sema::CXXMoveAssignment:
|
||||
NeedOverloadResolution:
|
||||
Sema::SpecialMemberOverloadResult *SMOR =
|
||||
S.LookupSpecialMember(RD, CSM,
|
||||
Quals & Qualifiers::Const,
|
||||
Quals & Qualifiers::Volatile,
|
||||
/*RValueThis*/false, /*ConstThis*/false,
|
||||
/*VolatileThis*/false);
|
||||
|
||||
// The standard doesn't describe how to behave if the lookup is ambiguous.
|
||||
// We treat it as not making the member non-trivial, just like the standard
|
||||
// mandates for the default constructor. This should rarely matter, because
|
||||
// the member will also be deleted.
|
||||
if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
|
||||
return true;
|
||||
|
||||
if (!SMOR->getMethod()) {
|
||||
assert(SMOR->getKind() ==
|
||||
Sema::SpecialMemberOverloadResult::NoMemberOrDeleted);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We deliberately don't check if we found a deleted special member. We're
|
||||
// not supposed to!
|
||||
if (Selected)
|
||||
*Selected = SMOR->getMethod();
|
||||
return SMOR->getMethod()->isTrivial();
|
||||
}
|
||||
|
||||
llvm_unreachable("unknown special method kind");
|
||||
}
|
||||
|
||||
CXXConstructorDecl *findUserDeclaredCtor(CXXRecordDecl *RD) {
|
||||
for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(), CE = RD->ctor_end();
|
||||
CI != CE; ++CI)
|
||||
if (!CI->isImplicit())
|
||||
return *CI;
|
||||
|
||||
// Look for constructor templates.
|
||||
typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> tmpl_iter;
|
||||
for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) {
|
||||
if (CXXConstructorDecl *CD =
|
||||
dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl()))
|
||||
return CD;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// The kind of subobject we are checking for triviality. The values of this
|
||||
/// enumeration are used in diagnostics.
|
||||
enum TrivialSubobjectKind {
|
||||
/// The subobject is a base class.
|
||||
TSK_BaseClass,
|
||||
/// The subobject is a non-static data member.
|
||||
TSK_Field,
|
||||
/// The object is actually the complete object.
|
||||
TSK_CompleteObject
|
||||
};
|
||||
|
||||
/// Check whether the special member selected for a given type would be trivial.
|
||||
static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc,
|
||||
QualType SubType,
|
||||
Sema::CXXSpecialMember CSM,
|
||||
TrivialSubobjectKind Kind,
|
||||
bool Diagnose) {
|
||||
CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl();
|
||||
if (!SubRD)
|
||||
return true;
|
||||
|
||||
CXXMethodDecl *Selected;
|
||||
if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(),
|
||||
Diagnose ? &Selected : 0))
|
||||
return true;
|
||||
|
||||
if (Diagnose) {
|
||||
if (!Selected && CSM == Sema::CXXDefaultConstructor) {
|
||||
S.Diag(SubobjLoc, diag::note_nontrivial_no_def_ctor)
|
||||
<< Kind << SubType.getUnqualifiedType();
|
||||
if (CXXConstructorDecl *CD = findUserDeclaredCtor(SubRD))
|
||||
S.Diag(CD->getLocation(), diag::note_user_declared_ctor);
|
||||
} else if (!Selected)
|
||||
S.Diag(SubobjLoc, diag::note_nontrivial_no_copy)
|
||||
<< Kind << SubType.getUnqualifiedType() << CSM << SubType;
|
||||
else if (Selected->isUserProvided()) {
|
||||
if (Kind == TSK_CompleteObject)
|
||||
S.Diag(Selected->getLocation(), diag::note_nontrivial_user_provided)
|
||||
<< Kind << SubType.getUnqualifiedType() << CSM;
|
||||
else {
|
||||
S.Diag(SubobjLoc, diag::note_nontrivial_user_provided)
|
||||
<< Kind << SubType.getUnqualifiedType() << CSM;
|
||||
S.Diag(Selected->getLocation(), diag::note_declared_at);
|
||||
}
|
||||
} else {
|
||||
if (Kind != TSK_CompleteObject)
|
||||
S.Diag(SubobjLoc, diag::note_nontrivial_subobject)
|
||||
<< Kind << SubType.getUnqualifiedType() << CSM;
|
||||
|
||||
// Explain why the defaulted or deleted special member isn't trivial.
|
||||
S.SpecialMemberIsTrivial(Selected, CSM, Diagnose);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check whether the members of a class type allow a special member to be
|
||||
/// trivial.
|
||||
static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
|
||||
Sema::CXXSpecialMember CSM,
|
||||
bool ConstArg, bool Diagnose) {
|
||||
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
|
||||
FE = RD->field_end(); FI != FE; ++FI) {
|
||||
if (FI->isInvalidDecl() || FI->isUnnamedBitfield())
|
||||
continue;
|
||||
|
||||
QualType FieldType = S.Context.getBaseElementType(FI->getType());
|
||||
|
||||
// Pretend anonymous struct or union members are members of this class.
|
||||
if (FI->isAnonymousStructOrUnion()) {
|
||||
if (!checkTrivialClassMembers(S, FieldType->getAsCXXRecordDecl(),
|
||||
CSM, ConstArg, Diagnose))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// C++11 [class.ctor]p5:
|
||||
// A default constructor is trivial if [...]
|
||||
// -- no non-static data member of its class has a
|
||||
// brace-or-equal-initializer
|
||||
if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) {
|
||||
if (Diagnose)
|
||||
S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << *FI;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Objective C ARC 4.3.5:
|
||||
// [...] nontrivally ownership-qualified types are [...] not trivially
|
||||
// default constructible, copy constructible, move constructible, copy
|
||||
// assignable, move assignable, or destructible [...]
|
||||
if (S.getLangOpts().ObjCAutoRefCount &&
|
||||
FieldType.hasNonTrivialObjCLifetime()) {
|
||||
if (Diagnose)
|
||||
S.Diag(FI->getLocation(), diag::note_nontrivial_objc_ownership)
|
||||
<< RD << FieldType.getObjCLifetime();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ConstArg && !FI->isMutable())
|
||||
FieldType.addConst();
|
||||
if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, CSM,
|
||||
TSK_Field, Diagnose))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Diagnose why the specified class does not have a trivial special member of
|
||||
/// the given kind.
|
||||
void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) {
|
||||
QualType Ty = Context.getRecordType(RD);
|
||||
if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)
|
||||
Ty.addConst();
|
||||
|
||||
checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, CSM,
|
||||
TSK_CompleteObject, /*Diagnose*/true);
|
||||
}
|
||||
|
||||
/// Determine whether a defaulted or deleted special member function is trivial,
|
||||
/// as specified in C++11 [class.ctor]p5, C++11 [class.copy]p12,
|
||||
/// 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();
|
||||
|
||||
bool ConstArg = false;
|
||||
ParmVarDecl *Param0 = MD->getNumParams() ? MD->getParamDecl(0) : 0;
|
||||
|
||||
// C++11 [class.copy]p12, p25:
|
||||
// A [special member] is trivial if its declared parameter type is the same
|
||||
// as if it had been implicitly declared [...]
|
||||
switch (CSM) {
|
||||
case CXXDefaultConstructor:
|
||||
case CXXDestructor:
|
||||
// Trivial default constructors and destructors cannot have parameters.
|
||||
break;
|
||||
|
||||
case CXXCopyConstructor:
|
||||
case CXXCopyAssignment: {
|
||||
// Trivial copy operations always have const, non-volatile parameter types.
|
||||
ConstArg = true;
|
||||
const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
|
||||
if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
|
||||
if (Diagnose)
|
||||
Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
|
||||
<< Param0->getSourceRange() << Param0->getType()
|
||||
<< Context.getLValueReferenceType(
|
||||
Context.getRecordType(RD).withConst());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CXXMoveConstructor:
|
||||
case CXXMoveAssignment: {
|
||||
// Trivial move operations always have non-cv-qualified parameters.
|
||||
const RValueReferenceType *RT =
|
||||
Param0->getType()->getAs<RValueReferenceType>();
|
||||
if (!RT || RT->getPointeeType().getCVRQualifiers()) {
|
||||
if (Diagnose)
|
||||
Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
|
||||
<< Param0->getSourceRange() << Param0->getType()
|
||||
<< Context.getRValueReferenceType(Context.getRecordType(RD));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CXXInvalid:
|
||||
llvm_unreachable("not a special member");
|
||||
}
|
||||
|
||||
// FIXME: We require that the parameter-declaration-clause is equivalent to
|
||||
// that of an implicit declaration, not just that the declared parameter type
|
||||
// matches, in order to prevent absuridities like a function simultaneously
|
||||
// being a trivial copy constructor and a non-trivial default constructor.
|
||||
// This issue has not yet been assigned a core issue number.
|
||||
if (MD->getMinRequiredArguments() < MD->getNumParams()) {
|
||||
if (Diagnose)
|
||||
Diag(MD->getParamDecl(MD->getMinRequiredArguments())->getLocation(),
|
||||
diag::note_nontrivial_default_arg)
|
||||
<< MD->getParamDecl(MD->getMinRequiredArguments())->getSourceRange();
|
||||
return false;
|
||||
}
|
||||
if (MD->isVariadic()) {
|
||||
if (Diagnose)
|
||||
Diag(MD->getLocation(), diag::note_nontrivial_variadic);
|
||||
return false;
|
||||
}
|
||||
|
||||
// C++11 [class.ctor]p5, C++11 [class.dtor]p5:
|
||||
// A copy/move [constructor or assignment operator] is trivial if
|
||||
// -- the [member] selected to copy/move each direct base class subobject
|
||||
// is trivial
|
||||
//
|
||||
// C++11 [class.copy]p12, C++11 [class.copy]p25:
|
||||
// A [default constructor or destructor] is trivial if
|
||||
// -- all the direct base classes have trivial [default constructors or
|
||||
// destructors]
|
||||
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
|
||||
BE = RD->bases_end(); BI != BE; ++BI)
|
||||
if (!checkTrivialSubobjectCall(*this, BI->getLocStart(),
|
||||
ConstArg ? BI->getType().withConst()
|
||||
: BI->getType(),
|
||||
CSM, TSK_BaseClass, Diagnose))
|
||||
return false;
|
||||
|
||||
// C++11 [class.ctor]p5, C++11 [class.dtor]p5:
|
||||
// A copy/move [constructor or assignment operator] for a class X is
|
||||
// trivial if
|
||||
// -- for each non-static data member of X that is of class type (or array
|
||||
// thereof), the constructor selected to copy/move that member is
|
||||
// trivial
|
||||
//
|
||||
// C++11 [class.copy]p12, C++11 [class.copy]p25:
|
||||
// A [default constructor or destructor] is trivial if
|
||||
// -- for all of the non-static data members of its class that are of class
|
||||
// type (or array thereof), each such class has a trivial [default
|
||||
// constructor or destructor]
|
||||
if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, Diagnose))
|
||||
return false;
|
||||
|
||||
// C++11 [class.dtor]p5:
|
||||
// A destructor is trivial if [...]
|
||||
// -- the destructor is not virtual
|
||||
if (CSM == CXXDestructor && MD->isVirtual()) {
|
||||
if (Diagnose)
|
||||
Diag(MD->getLocation(), diag::note_nontrivial_virtual_dtor) << RD;
|
||||
return false;
|
||||
}
|
||||
|
||||
// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
|
||||
// A [special member] for class X is trivial if [...]
|
||||
// -- class X has no virtual functions and no virtual base classes
|
||||
if (CSM != CXXDestructor && MD->getParent()->isDynamicClass()) {
|
||||
if (!Diagnose)
|
||||
return false;
|
||||
|
||||
if (RD->getNumVBases()) {
|
||||
// Check for virtual bases. We already know that the corresponding
|
||||
// member in all bases is trivial, so vbases must all be direct.
|
||||
CXXBaseSpecifier &BS = *RD->vbases_begin();
|
||||
assert(BS.isVirtual());
|
||||
Diag(BS.getLocStart(), diag::note_nontrivial_has_virtual) << RD << 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Must have a virtual method.
|
||||
for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
|
||||
ME = RD->method_end(); MI != ME; ++MI) {
|
||||
if (MI->isVirtual()) {
|
||||
SourceLocation MLoc = MI->getLocStart();
|
||||
Diag(MLoc, diag::note_nontrivial_has_virtual) << RD << 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("dynamic class with no vbases and no virtual functions");
|
||||
}
|
||||
|
||||
// Looks like it's trivial!
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Data used with FindHiddenVirtualMethod
|
||||
namespace {
|
||||
struct FindHiddenVirtualMethodData {
|
||||
|
@ -7113,7 +7477,46 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
|
|||
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
|
||||
|
||||
if (!ClassDecl->isDependentType())
|
||||
CheckExplicitlyDefaultedMethods(ClassDecl);
|
||||
CheckExplicitlyDefaultedAndDeletedMethods(ClassDecl);
|
||||
|
||||
// C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member
|
||||
// function that is not a constructor declares that member function to be
|
||||
// const. [...] The class of which that function is a member shall be
|
||||
// a literal type.
|
||||
//
|
||||
// If the class has virtual bases, any constexpr members will already have
|
||||
// been diagnosed by the checks performed on the member declaration, so
|
||||
// suppress this (less useful) diagnostic.
|
||||
//
|
||||
// We delay this until we know whether an explicitly-defaulted (or deleted)
|
||||
// destructor for the class is trivial.
|
||||
if (LangOpts.CPlusPlus0x && !ClassDecl->isDependentType() &&
|
||||
!ClassDecl->isLiteral() && !ClassDecl->getNumVBases()) {
|
||||
for (CXXRecordDecl::method_iterator M = ClassDecl->method_begin(),
|
||||
MEnd = ClassDecl->method_end();
|
||||
M != MEnd; ++M) {
|
||||
if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
|
||||
switch (ClassDecl->getTemplateSpecializationKind()) {
|
||||
case TSK_ImplicitInstantiation:
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
// If a template instantiates to a non-literal type, but its members
|
||||
// instantiate to constexpr functions, the template is technically
|
||||
// ill-formed, but we allow it for sanity.
|
||||
continue;
|
||||
|
||||
case TSK_Undeclared:
|
||||
case TSK_ExplicitSpecialization:
|
||||
RequireLiteralType(M->getLocation(), Context.getRecordType(ClassDecl),
|
||||
diag::err_constexpr_method_non_literal);
|
||||
break;
|
||||
}
|
||||
|
||||
// Only produce one error per class.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
|
||||
|
@ -10395,35 +10798,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
|
|||
// recovery.
|
||||
}
|
||||
Fn->setDeletedAsWritten();
|
||||
|
||||
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
|
||||
if (!MD)
|
||||
return;
|
||||
|
||||
// A deleted special member function is trivial if the corresponding
|
||||
// implicitly-declared function would have been.
|
||||
switch (getSpecialMember(MD)) {
|
||||
case CXXInvalid:
|
||||
break;
|
||||
case CXXDefaultConstructor:
|
||||
MD->setTrivial(MD->getParent()->hasTrivialDefaultConstructor());
|
||||
break;
|
||||
case CXXCopyConstructor:
|
||||
MD->setTrivial(MD->getParent()->hasTrivialCopyConstructor());
|
||||
break;
|
||||
case CXXMoveConstructor:
|
||||
MD->setTrivial(MD->getParent()->hasTrivialMoveConstructor());
|
||||
break;
|
||||
case CXXCopyAssignment:
|
||||
MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment());
|
||||
break;
|
||||
case CXXMoveAssignment:
|
||||
MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment());
|
||||
break;
|
||||
case CXXDestructor:
|
||||
MD->setTrivial(MD->getParent()->hasTrivialDestructor());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
|
||||
|
|
|
@ -3058,6 +3058,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
//
|
||||
// 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
|
||||
// 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
|
||||
//
|
||||
// Note that these builtins do not behave as documented in g++: if a class
|
||||
// has both a trivial and a non-trivial special member of a particular kind,
|
||||
// they return false! For now, we emulate this behavior.
|
||||
// FIXME: This appears to be a g++ bug: more complex cases reveal that it
|
||||
// does not correctly compute triviality in the presence of multiple special
|
||||
// members of the same kind. Revisit this once the g++ bug is fixed.
|
||||
case UTT_HasTrivialDefaultConstructor:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
|
||||
// If __is_pod (type) is true then the trait is true, else if type is
|
||||
|
@ -3065,9 +3072,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
// constructor ([class.ctor]) then the trait is true, else it is false.
|
||||
if (T.isPODType(Self.Context))
|
||||
return true;
|
||||
if (const RecordType *RT =
|
||||
C.getBaseElementType(T)->getAs<RecordType>())
|
||||
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDefaultConstructor();
|
||||
if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
|
||||
return RD->hasTrivialDefaultConstructor() &&
|
||||
!RD->hasNonTrivialDefaultConstructor();
|
||||
return false;
|
||||
case UTT_HasTrivialCopy:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
|
||||
|
@ -3077,8 +3084,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
// is true, else it is false.
|
||||
if (T.isPODType(Self.Context) || T->isReferenceType())
|
||||
return true;
|
||||
if (const RecordType *RT = T->getAs<RecordType>())
|
||||
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
|
||||
if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
|
||||
return RD->hasTrivialCopyConstructor() &&
|
||||
!RD->hasNonTrivialCopyConstructor();
|
||||
return false;
|
||||
case UTT_HasTrivialAssign:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
|
||||
|
@ -3093,12 +3101,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
// errors if the copy assignment operator is actually used, q.v.
|
||||
// [class.copy]p12).
|
||||
|
||||
if (C.getBaseElementType(T).isConstQualified())
|
||||
if (T.isConstQualified())
|
||||
return false;
|
||||
if (T.isPODType(Self.Context))
|
||||
return true;
|
||||
if (const RecordType *RT = T->getAs<RecordType>())
|
||||
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
|
||||
if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
|
||||
return RD->hasTrivialCopyAssignment() &&
|
||||
!RD->hasNonTrivialCopyAssignment();
|
||||
return false;
|
||||
case UTT_HasTrivialDestructor:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
|
||||
|
@ -3115,9 +3124,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
|
||||
return true;
|
||||
|
||||
if (const RecordType *RT =
|
||||
C.getBaseElementType(T)->getAs<RecordType>())
|
||||
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
|
||||
if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
|
||||
return RD->hasTrivialDestructor();
|
||||
return false;
|
||||
// TODO: Propagate nothrowness for implicitly declared special members.
|
||||
case UTT_HasNothrowAssign:
|
||||
|
@ -3134,9 +3142,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
return false;
|
||||
if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
|
||||
return true;
|
||||
if (const RecordType *RT = T->getAs<RecordType>()) {
|
||||
CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
if (RD->hasTrivialCopyAssignment())
|
||||
if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
|
||||
if (RD->hasTrivialCopyAssignment() && !RD->hasNonTrivialCopyAssignment())
|
||||
return true;
|
||||
|
||||
bool FoundAssign = false;
|
||||
|
@ -3175,9 +3182,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
// false.
|
||||
if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
|
||||
return true;
|
||||
if (const RecordType *RT = T->getAs<RecordType>()) {
|
||||
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
if (RD->hasTrivialCopyConstructor())
|
||||
if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
|
||||
if (RD->hasTrivialCopyConstructor() &&
|
||||
!RD->hasNonTrivialCopyConstructor())
|
||||
return true;
|
||||
|
||||
bool FoundConstructor = false;
|
||||
|
@ -3216,9 +3223,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
// throw an exception then the trait is true, else it is false.
|
||||
if (T.isPODType(C) || T->isObjCLifetimeType())
|
||||
return true;
|
||||
if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
|
||||
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
if (RD->hasTrivialDefaultConstructor())
|
||||
if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
|
||||
if (RD->hasTrivialDefaultConstructor() &&
|
||||
!RD->hasNonTrivialDefaultConstructor())
|
||||
return true;
|
||||
|
||||
DeclContext::lookup_const_iterator Con, ConEnd;
|
||||
|
@ -3245,11 +3252,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
|
||||
// If type is a class type with a virtual destructor ([class.dtor])
|
||||
// then the trait is true, else it is false.
|
||||
if (const RecordType *Record = T->getAs<RecordType>()) {
|
||||
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
|
||||
if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
|
||||
if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD))
|
||||
return Destructor->isVirtual();
|
||||
}
|
||||
return false;
|
||||
|
||||
// These type trait expressions are modeled on the specifications for the
|
||||
|
|
|
@ -1581,10 +1581,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
|||
SemaRef.CheckOverrideControl(Method);
|
||||
|
||||
// If a function is defined as defaulted or deleted, mark it as such now.
|
||||
if (D->isDefaulted())
|
||||
Method->setDefaulted();
|
||||
if (D->isExplicitlyDefaulted())
|
||||
SemaRef.SetDeclDefaulted(Method, Method->getLocation());
|
||||
if (D->isDeletedAsWritten())
|
||||
Method->setDeletedAsWritten();
|
||||
SemaRef.SetDeclDeleted(Method, Method->getLocation());
|
||||
|
||||
// If there's a function template, let our caller handle it.
|
||||
if (FunctionTemplate) {
|
||||
|
@ -1610,13 +1610,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
|||
Owner->addDecl(Method);
|
||||
}
|
||||
|
||||
if (D->isExplicitlyDefaulted()) {
|
||||
SemaRef.SetDeclDefaulted(Method, Method->getLocation());
|
||||
} else {
|
||||
assert(!D->isDefaulted() &&
|
||||
"should not implicitly default uninstantiated function");
|
||||
}
|
||||
|
||||
return Method;
|
||||
}
|
||||
|
||||
|
|
|
@ -4564,6 +4564,8 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
|
|||
Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
|
||||
diag::note_non_literal_user_provided_dtor :
|
||||
diag::note_non_literal_nontrivial_dtor) << RD;
|
||||
if (!Dtor->isUserProvided())
|
||||
SpecialMemberIsTrivial(Dtor, CXXDestructor, /*Diagnose*/true);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -39,7 +39,7 @@ struct UserProvDtor {
|
|||
struct NonTrivDtor {
|
||||
constexpr NonTrivDtor();
|
||||
constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
|
||||
virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
|
||||
virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} expected-note {{because it is virtual}}
|
||||
};
|
||||
struct NonTrivDtorBase {
|
||||
~NonTrivDtorBase();
|
||||
|
|
|
@ -14,25 +14,25 @@ class VirtualBase : virtual Okay { // expected-note 4 {{because type 'VirtualBas
|
|||
};
|
||||
|
||||
class Ctor {
|
||||
Ctor() { abort(); } // expected-note 4 {{because type 'Ctor' has a user-declared constructor}}
|
||||
Ctor() { abort(); } // expected-note 2{{because type 'Ctor' has a user-provided default constructor}} expected-note 2{{here}}
|
||||
};
|
||||
class Ctor2 {
|
||||
Ctor2(); // expected-note 3 {{because type 'Ctor2' has a user-declared constructor}}
|
||||
Ctor2(); // expected-note {{because type 'Ctor2' has a user-provided default constructor}} expected-note 2{{here}}
|
||||
};
|
||||
class CtorTmpl {
|
||||
template<typename T> CtorTmpl(); // expected-note {{because type 'CtorTmpl' has a user-declared constructor}}
|
||||
class CtorTmpl { // expected-note {{because type 'CtorTmpl' has no default constructor}}
|
||||
template<typename T> CtorTmpl(); // expected-note {{implicit default constructor suppressed by user-declared constructor}}
|
||||
};
|
||||
|
||||
class CopyCtor {
|
||||
CopyCtor(CopyCtor &cc) { abort(); } // expected-note 4 {{because type 'CopyCtor' has a user-declared copy constructor}}
|
||||
class CopyCtor { // expected-note 2{{because no constructor can be used to copy an object of type 'const CopyCtor'}}
|
||||
CopyCtor(CopyCtor &cc) { abort(); }
|
||||
};
|
||||
|
||||
class CopyAssign {
|
||||
CopyAssign& operator=(CopyAssign& CA) { abort(); } // expected-note 4 {{because type 'CopyAssign' has a user-declared copy assignment operator}}
|
||||
class CopyAssign { // expected-note 2 {{because no assignment operator can be used to copy an object of type 'const CopyAssign'}}
|
||||
CopyAssign& operator=(CopyAssign& CA) { abort(); }
|
||||
};
|
||||
|
||||
class Dtor {
|
||||
~Dtor() { abort(); } // expected-note 4 {{because type 'Dtor' has a user-declared destructor}}
|
||||
~Dtor() { abort(); } // expected-note 2 {{because type 'Dtor' has a user-provided destructor}} expected-note 2{{here}}
|
||||
};
|
||||
|
||||
union U1 {
|
||||
|
@ -49,25 +49,25 @@ union U1 {
|
|||
|
||||
union U2 {
|
||||
struct {
|
||||
Virtual v; // expected-note {{because type 'U2::<anonymous struct}}
|
||||
Virtual v; // expected-note {{because the function selected to copy field of type 'Virtual' is not trivial}}
|
||||
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
|
||||
struct {
|
||||
VirtualBase vbase; // expected-note {{because type 'U2::<anonymous struct}}
|
||||
VirtualBase vbase; // expected-note {{because the function selected to copy field of type 'VirtualBase' is not trivial}}
|
||||
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
|
||||
struct {
|
||||
Ctor ctor; // expected-note {{because type 'U2::<anonymous struct}}
|
||||
Ctor ctor; // expected-note {{because field of type 'Ctor' has a user-provided default constructor}}
|
||||
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
|
||||
struct {
|
||||
Ctor2 ctor2; // expected-note {{because type 'U2::<anonymous struct}}
|
||||
Ctor2 ctor2; // expected-note {{because field of type 'Ctor2' has a user-provided default constructor}}
|
||||
} m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}}
|
||||
struct {
|
||||
CopyCtor copyctor; // expected-note {{because type 'U2::<anonymous struct}}
|
||||
struct { // expected-note {{no constructor can be used to copy an object of type 'const}}
|
||||
CopyCtor copyctor;
|
||||
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
|
||||
struct {
|
||||
CopyAssign copyassign; // expected-note {{because type 'U2::<anonymous struct}}
|
||||
struct { // expected-note {{no assignment operator can be used to copy an object of type 'const}}
|
||||
CopyAssign copyassign;
|
||||
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
|
||||
struct {
|
||||
Dtor dtor; // expected-note {{because type 'U2::<anonymous struct}}
|
||||
Dtor dtor; // expected-note {{because field of type 'Dtor' has a user-provided destructor}}
|
||||
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
|
||||
struct {
|
||||
Okay okay;
|
||||
|
@ -75,22 +75,25 @@ union U2 {
|
|||
};
|
||||
|
||||
union U3 {
|
||||
struct s1 : Virtual { // expected-note {{because type 'U3::s1' has a base class with a non-trivial copy constructor}}
|
||||
struct s1 : Virtual { // expected-note {{because the function selected to copy base class of type 'Virtual' is not trivial}}
|
||||
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
|
||||
struct s2 : VirtualBase { // expected-note {{because type 'U3::s2' has a base class with a non-trivial copy constructor}}
|
||||
struct s2 : VirtualBase { // expected-note {{because the function selected to copy base class of type 'VirtualBase' is not trivial}}
|
||||
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
|
||||
struct s3 : Ctor { // expected-note {{because type 'U3::s3' has a base class with a non-trivial constructor}}
|
||||
struct s3 : Ctor { // expected-note {{because base class of type 'Ctor' has a user-provided default constructor}}
|
||||
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
|
||||
struct s3a : Ctor2 { // expected-note {{because type 'U3::s3a' has a base class with a non-trivial constructor}}
|
||||
struct s3a : Ctor2 { // expected-note {{because base class of type 'Ctor2' has a user-provided default constructor}}
|
||||
} m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}}
|
||||
struct s4 : CopyCtor { // expected-note {{because type 'U3::s4' has a base class with a non-trivial copy constructor}}
|
||||
struct s4 : CopyCtor { // expected-note {{because no constructor can be used to copy an object of type 'const U3::s4'}}
|
||||
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
|
||||
struct s5 : CopyAssign { // expected-note {{because type 'U3::s5' has a base class with a non-trivial copy assignment operator}}
|
||||
struct s5 : CopyAssign { // expected-note {{because no assignment operator can be used to copy an object of type 'const U3::s5'}}
|
||||
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
|
||||
struct s6 : Dtor { // expected-note {{because type 'U3::s6' has a base class with a non-trivial destructor}}
|
||||
struct s6 : Dtor { // expected-note {{because base class of type 'Dtor' has a user-provided destructor}}
|
||||
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
|
||||
struct s7 : Okay {
|
||||
} m7;
|
||||
struct s8 {
|
||||
s8(...) = delete; // expected-note {{because it is a variadic function}} expected-warning {{C++11}}
|
||||
} m8; // expected-error {{union member 'm8' has a non-trivial constructor}}
|
||||
};
|
||||
|
||||
union U4 {
|
||||
|
|
|
@ -14,11 +14,10 @@ struct A {
|
|||
// (except for possibly differing ref-qualifiers
|
||||
A &operator=(A &&) & = default;
|
||||
|
||||
// FIXME:
|
||||
// and except that in the case of a copy constructor or copy assignment
|
||||
// operator, the parameter type may be "reference to non-const T")
|
||||
A(A &) = default; // FIXME: expected-error {{must be defaulted outside the class}}
|
||||
A &operator=(A &) = default; // FIXME: expected-error {{must be defaulted outside the class}}
|
||||
A(A &) = default;
|
||||
A &operator=(A &) = default;
|
||||
|
||||
// -- not have default arguments
|
||||
A(double = 0.0) = default; // expected-error {{cannot have default arguments}}
|
||||
|
|
|
@ -38,8 +38,8 @@ namespace copy {
|
|||
};
|
||||
|
||||
struct NonConst {
|
||||
NonConst(NonConst&) = default; // expected-error {{must be defaulted outside the class}}
|
||||
NonConst& operator=(NonConst&) = default; // expected-error {{must be defaulted outside the class}}
|
||||
NonConst(NonConst&) = default;
|
||||
NonConst& operator=(NonConst&) = default;
|
||||
};
|
||||
|
||||
struct NonConst2 {
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||||
|
||||
template<typename T, bool B> struct trivially_copyable_check {
|
||||
static_assert(B == __has_trivial_copy(T), "");
|
||||
static_assert(B == __is_trivially_constructible(T, T), "");
|
||||
static_assert(B == __is_trivially_constructible(T, const T &), "");
|
||||
static_assert(B == __is_trivially_constructible(T, T &&), "");
|
||||
typedef void type;
|
||||
};
|
||||
template<typename T> using trivially_copyable =
|
||||
typename trivially_copyable_check<T, true>::type;
|
||||
template<typename T> using not_trivially_copyable =
|
||||
typename trivially_copyable_check<T, false>::type;
|
||||
|
||||
struct Trivial {};
|
||||
using _ = trivially_copyable<Trivial>;
|
||||
|
||||
// A copy/move constructor for class X is trivial if it is not user-provided,
|
||||
struct UserProvided {
|
||||
UserProvided(const UserProvided &);
|
||||
};
|
||||
using _ = not_trivially_copyable<UserProvided>;
|
||||
|
||||
// its declared parameter type is the same as if it had been implicitly
|
||||
// declared,
|
||||
struct NonConstCopy {
|
||||
NonConstCopy(NonConstCopy &) = default;
|
||||
};
|
||||
using _ = not_trivially_copyable<NonConstCopy>;
|
||||
|
||||
// class X has no virtual functions
|
||||
struct VFn {
|
||||
virtual void f();
|
||||
};
|
||||
using _ = not_trivially_copyable<VFn>;
|
||||
|
||||
// and no virtual base classes
|
||||
struct VBase : virtual Trivial {};
|
||||
using _ = not_trivially_copyable<VBase>;
|
||||
|
||||
// and the constructor selected to copy/move each [direct subobject] is trivial
|
||||
struct TemplateCtor {
|
||||
template<typename T> TemplateCtor(T &);
|
||||
};
|
||||
using _ = trivially_copyable<TemplateCtor>;
|
||||
struct TemplateCtorMember {
|
||||
TemplateCtor tc;
|
||||
};
|
||||
using _ = trivially_copyable<TemplateCtorMember>;
|
||||
|
||||
// We can select a non-trivial copy ctor even if there is a trivial one.
|
||||
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, MutableTemplateCtorMember &&), "");
|
||||
struct MutableTemplateCtorMember2 {
|
||||
MutableTemplateCtorMember2(const MutableTemplateCtorMember2 &) = default;
|
||||
MutableTemplateCtorMember2(MutableTemplateCtorMember2 &&) = default;
|
||||
mutable TemplateCtor mtc;
|
||||
};
|
||||
static_assert(!__is_trivially_constructible(MutableTemplateCtorMember2, const MutableTemplateCtorMember2 &), "");
|
||||
static_assert(__is_trivially_constructible(MutableTemplateCtorMember2, MutableTemplateCtorMember2 &&), "");
|
||||
|
||||
// Both trivial and non-trivial special members.
|
||||
struct TNT {
|
||||
TNT(const TNT &) = default; // trivial
|
||||
TNT(TNT &); // non-trivial
|
||||
|
||||
TNT(TNT &&) = default; // trivial
|
||||
TNT(const TNT &&); // non-trivial
|
||||
};
|
||||
|
||||
static_assert(!__has_trivial_copy(TNT), "lie deliberately for gcc compatibility");
|
||||
static_assert(__is_trivially_constructible(TNT, TNT), "");
|
||||
static_assert(!__is_trivially_constructible(TNT, TNT &), "");
|
||||
static_assert(__is_trivially_constructible(TNT, const TNT &), "");
|
||||
static_assert(!__is_trivially_constructible(TNT, volatile TNT &), "");
|
||||
static_assert(__is_trivially_constructible(TNT, TNT &&), "");
|
||||
static_assert(!__is_trivially_constructible(TNT, const TNT &&), "");
|
||||
static_assert(!__is_trivially_constructible(TNT, volatile TNT &&), "");
|
||||
|
||||
// This has only trivial special members.
|
||||
struct DerivedFromTNT : TNT {};
|
||||
|
||||
static_assert(__has_trivial_copy(DerivedFromTNT), "");
|
||||
static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT), "");
|
||||
static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &), "");
|
||||
static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &), "");
|
||||
static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &), "");
|
||||
static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &&), "");
|
||||
static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &&), "");
|
||||
static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &&), "");
|
||||
|
||||
// This has only trivial special members.
|
||||
struct TNTMember {
|
||||
TNT tnt;
|
||||
};
|
||||
|
||||
static_assert(__has_trivial_copy(TNTMember), "");
|
||||
static_assert(__is_trivially_constructible(TNTMember, TNTMember), "");
|
||||
static_assert(__is_trivially_constructible(TNTMember, TNTMember &), "");
|
||||
static_assert(__is_trivially_constructible(TNTMember, const TNTMember &), "");
|
||||
static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &), "");
|
||||
static_assert(__is_trivially_constructible(TNTMember, TNTMember &&), "");
|
||||
static_assert(__is_trivially_constructible(TNTMember, const TNTMember &&), "");
|
||||
static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &&), "");
|
||||
|
||||
struct NCCTNT : NonConstCopy, TNT {};
|
||||
|
||||
static_assert(!__has_trivial_copy(NCCTNT), "");
|
||||
static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT), "");
|
||||
static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &), "");
|
||||
static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &), "");
|
||||
static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &), "");
|
||||
static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &&), "");
|
||||
static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &&), "");
|
||||
static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &&), "");
|
|
@ -0,0 +1,143 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||||
|
||||
template<typename T, bool B> struct trivially_assignable_check {
|
||||
static_assert(B == __has_trivial_assign(T), "");
|
||||
static_assert(B == __is_trivially_assignable(T&, T), "");
|
||||
static_assert(B == __is_trivially_assignable(T&, const T &), "");
|
||||
static_assert(B == __is_trivially_assignable(T&, T &&), "");
|
||||
static_assert(B == __is_trivially_assignable(T&&, T), "");
|
||||
static_assert(B == __is_trivially_assignable(T&&, const T &), "");
|
||||
static_assert(B == __is_trivially_assignable(T&&, T &&), "");
|
||||
typedef void type;
|
||||
};
|
||||
template<typename T> using trivially_assignable =
|
||||
typename trivially_assignable_check<T, true>::type;
|
||||
template<typename T> using not_trivially_assignable =
|
||||
typename trivially_assignable_check<T, false>::type;
|
||||
|
||||
struct Trivial {};
|
||||
using _ = trivially_assignable<Trivial>;
|
||||
|
||||
// A copy/move assignment operator for class X is trivial if it is not user-provided,
|
||||
struct UserProvided {
|
||||
UserProvided &operator=(const UserProvided &);
|
||||
};
|
||||
using _ = not_trivially_assignable<UserProvided>;
|
||||
|
||||
// its declared parameter type is the same as if it had been implicitly
|
||||
// declared,
|
||||
struct NonConstCopy {
|
||||
NonConstCopy &operator=(NonConstCopy &) = default;
|
||||
};
|
||||
using _ = not_trivially_assignable<NonConstCopy>;
|
||||
|
||||
// class X has no virtual functions
|
||||
struct VFn {
|
||||
virtual void f();
|
||||
};
|
||||
using _ = not_trivially_assignable<VFn>;
|
||||
|
||||
// and no virtual base classes
|
||||
struct VBase : virtual Trivial {};
|
||||
using _ = not_trivially_assignable<VBase>;
|
||||
|
||||
// and the assignment operator selected to copy/move each [direct subobject] is trivial
|
||||
struct TemplateCtor {
|
||||
template<typename T> TemplateCtor operator=(T &);
|
||||
};
|
||||
using _ = trivially_assignable<TemplateCtor>;
|
||||
struct TemplateCtorMember {
|
||||
TemplateCtor tc;
|
||||
};
|
||||
using _ = trivially_assignable<TemplateCtorMember>;
|
||||
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, MutableTemplateCtorMember &&), "");
|
||||
|
||||
// Both trivial and non-trivial special members.
|
||||
struct TNT {
|
||||
TNT &operator=(const TNT &) = default; // trivial
|
||||
TNT &operator=(TNT &); // non-trivial
|
||||
|
||||
TNT &operator=(TNT &&) = default; // trivial
|
||||
TNT &operator=(const TNT &&); // non-trivial
|
||||
};
|
||||
|
||||
static_assert(!__has_trivial_assign(TNT), "lie deliberately for gcc compatibility");
|
||||
static_assert(__is_trivially_assignable(TNT, TNT), "");
|
||||
static_assert(!__is_trivially_assignable(TNT, TNT &), "");
|
||||
static_assert(__is_trivially_assignable(TNT, const TNT &), "");
|
||||
static_assert(!__is_trivially_assignable(TNT, volatile TNT &), "");
|
||||
static_assert(__is_trivially_assignable(TNT, TNT &&), "");
|
||||
static_assert(!__is_trivially_assignable(TNT, const TNT &&), "");
|
||||
static_assert(!__is_trivially_assignable(TNT, volatile TNT &&), "");
|
||||
|
||||
// This has only trivial special members.
|
||||
struct DerivedFromTNT : TNT {};
|
||||
|
||||
static_assert(__has_trivial_assign(DerivedFromTNT), "");
|
||||
static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT), "");
|
||||
static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &), "");
|
||||
static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &), "");
|
||||
static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &), "");
|
||||
static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &&), "");
|
||||
static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &&), "");
|
||||
static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &&), "");
|
||||
|
||||
// This has only trivial special members.
|
||||
struct TNTMember {
|
||||
TNT tnt;
|
||||
};
|
||||
|
||||
static_assert(__has_trivial_assign(TNTMember), "");
|
||||
static_assert(__is_trivially_assignable(TNTMember, TNTMember), "");
|
||||
static_assert(__is_trivially_assignable(TNTMember, TNTMember &), "");
|
||||
static_assert(__is_trivially_assignable(TNTMember, const TNTMember &), "");
|
||||
static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &), "");
|
||||
static_assert(__is_trivially_assignable(TNTMember, TNTMember &&), "");
|
||||
static_assert(__is_trivially_assignable(TNTMember, const TNTMember &&), "");
|
||||
static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &&), "");
|
||||
|
||||
struct NCCTNT : NonConstCopy, TNT {};
|
||||
|
||||
static_assert(!__has_trivial_assign(NCCTNT), "");
|
||||
static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT), "");
|
||||
static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &), "");
|
||||
static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &), "");
|
||||
static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &), "");
|
||||
static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &&), "");
|
||||
static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &&), "");
|
||||
static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &&), "");
|
||||
|
||||
struct MultipleTrivial {
|
||||
// All four of these are trivial.
|
||||
MultipleTrivial &operator=(const MultipleTrivial &) & = default;
|
||||
MultipleTrivial &operator=(const MultipleTrivial &) && = default;
|
||||
MultipleTrivial &operator=(MultipleTrivial &&) & = default;
|
||||
MultipleTrivial &operator=(MultipleTrivial &&) && = default;
|
||||
};
|
||||
|
||||
using _ = trivially_assignable<MultipleTrivial>;
|
||||
|
||||
struct RefQualifier {
|
||||
RefQualifier &operator=(const RefQualifier &) & = default;
|
||||
RefQualifier &operator=(const RefQualifier &) &&;
|
||||
RefQualifier &operator=(RefQualifier &&) &;
|
||||
RefQualifier &operator=(RefQualifier &&) && = default;
|
||||
};
|
||||
struct DerivedFromRefQualifier : RefQualifier {
|
||||
// Both of these call the trivial copy operation.
|
||||
DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) & = default;
|
||||
DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) && = default;
|
||||
// Both of these call the non-trivial move operation.
|
||||
DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) & = default;
|
||||
DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) && = default;
|
||||
};
|
||||
static_assert(__is_trivially_assignable(DerivedFromRefQualifier&, const DerivedFromRefQualifier&), "");
|
||||
static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), "");
|
||||
static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), "");
|
||||
static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), "");
|
|
@ -149,26 +149,41 @@ static_assert(__has_trivial_constructor(Trivial), "Trivial is nontrivial");
|
|||
class NonTrivialDefCtor1 { NonTrivialDefCtor1(); };
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor1), "NonTrivialDefCtor1 is trivial");
|
||||
|
||||
#define ASSERT_NONTRIVIAL_IMPL(Class, Bases, Body) \
|
||||
class Class Bases { Body }; \
|
||||
static_assert(!__has_trivial_constructor(Class), "");
|
||||
#define ASSERT_NONTRIVIAL(Class, Bases, Body) \
|
||||
ASSERT_NONTRIVIAL_IMPL(Class, Bases, Body) \
|
||||
ASSERT_NONTRIVIAL_IMPL(Def ## Class, Bases, Def ## Class() = default; Body) \
|
||||
ASSERT_NONTRIVIAL_IMPL(Del ## Class, Bases, Del ## Class() = delete; Body)
|
||||
|
||||
// - its class has no virtual functions (10.3) and no virtual base classes (10.1), and
|
||||
class NonTrivialDefCtor2 { virtual void f(); };
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor2), "NonTrivialDefCtor2 is trivial");
|
||||
class NonTrivialDefCtor3 : virtual Trivial {};
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor3), "NonTrivialDefCtor3 is trivial");
|
||||
ASSERT_NONTRIVIAL(NonTrivialDefCtor2, , virtual void f();)
|
||||
ASSERT_NONTRIVIAL(NonTrivialDefCtor3, : virtual Trivial, )
|
||||
|
||||
// - no non-static data member of its class has a brace-or-equal-initializer, and
|
||||
class NonTrivialDefCtor4 { int m = 52; };
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor4), "NonTrivialDefCtor4 is trivial");
|
||||
ASSERT_NONTRIVIAL(NonTrivialDefCtor4, , int m = 52;)
|
||||
|
||||
// - all the direct base classes of its class have trivial default constructors, and
|
||||
class NonTrivialDefCtor5 : NonTrivialDefCtor1 {};
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor5), "NonTrivialDefCtor5 is trivial");
|
||||
ASSERT_NONTRIVIAL(NonTrivialDefCtor5, : NonTrivialDefCtor1, )
|
||||
|
||||
// - for all the non-static data members of its class that are of class type (or array thereof), each such class
|
||||
// has a trivial default constructor.
|
||||
class NonTrivialDefCtor6 { NonTrivialDefCtor1 t; };
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor5 is trivial");
|
||||
ASSERT_NONTRIVIAL(NonTrivialDefCtor6, , NonTrivialDefCtor1 t;)
|
||||
|
||||
// FIXME: No core issue number yet.
|
||||
// - its parameter-declaration-clause is equivalent to that of an implicit declaration.
|
||||
struct NonTrivialDefCtor7 {
|
||||
NonTrivialDefCtor7(...) = delete;
|
||||
};
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor7), "");
|
||||
struct NonTrivialDefCtor8 {
|
||||
NonTrivialDefCtor8(int = 0) = delete;
|
||||
};
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor8), "");
|
||||
|
||||
// Otherwise, the default constructor is non-trivial.
|
||||
|
||||
class Trivial2 { Trivial2() = delete; };
|
||||
static_assert(__has_trivial_constructor(Trivial2), "Trivial2 is trivial");
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
struct S {
|
||||
S(); // expected-note {{because type 'S' has a user-declared constructor}}
|
||||
S(); // expected-note {{because type 'S' has a user-provided default constructor}}
|
||||
};
|
||||
|
||||
struct { // expected-error {{anonymous structs and classes must be class members}}
|
||||
|
@ -9,7 +9,7 @@ struct { // expected-error {{anonymous structs and classes must be class members
|
|||
|
||||
struct E {
|
||||
struct {
|
||||
S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}}
|
||||
S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}}
|
||||
};
|
||||
static struct {
|
||||
};
|
||||
|
|
|
@ -36,9 +36,9 @@ struct non_const_derived : non_const_copy {
|
|||
};
|
||||
|
||||
struct bad_decls {
|
||||
bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}} expected-error {{must be defaulted outside the class}}
|
||||
bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}}
|
||||
bad_decls&& operator = (bad_decls) = default; // expected-error {{lvalue reference}} expected-error {{must return 'bad_decls &'}}
|
||||
bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}} expected-error {{must be defaulted outside the class}}
|
||||
bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}}
|
||||
bad_decls& operator = (const bad_decls&) const = default; // expected-error {{may not have 'const', 'constexpr' or 'volatile' qualifiers}}
|
||||
};
|
||||
|
||||
|
@ -57,14 +57,18 @@ struct except_spec_d_good : except_spec_a, except_spec_b {
|
|||
~except_spec_d_good();
|
||||
};
|
||||
except_spec_d_good::~except_spec_d_good() = default;
|
||||
// FIXME: This should error in the virtual override check.
|
||||
// It doesn't because we generate the implicit specification later than
|
||||
// appropriate.
|
||||
struct except_spec_d_bad : except_spec_a, except_spec_b {
|
||||
~except_spec_d_bad() = default;
|
||||
struct except_spec_d_good2 : except_spec_a, except_spec_b {
|
||||
~except_spec_d_good2() = default;
|
||||
};
|
||||
struct except_spec_d_bad : except_spec_a, except_spec_b {
|
||||
~except_spec_d_bad() noexcept;
|
||||
};
|
||||
// FIXME: This should error because this exception spec is not
|
||||
// compatible with the implicit exception spec.
|
||||
except_spec_d_bad::~except_spec_d_bad() noexcept = default;
|
||||
|
||||
// FIXME: This should error because the exceptions spec doesn't match.
|
||||
// FIXME: This should error because this exception spec is not
|
||||
// compatible with the implicit exception spec.
|
||||
struct except_spec_d_mismatch : except_spec_a, except_spec_b {
|
||||
except_spec_d_mismatch() throw(A) = default;
|
||||
};
|
||||
|
|
|
@ -254,13 +254,13 @@ namespace CopyCtorIssues {
|
|||
|
||||
namespace UnionOrAnonStructMembers {
|
||||
struct NonTrivCtor {
|
||||
NonTrivCtor(); // expected-note 2{{user-declared constructor}}
|
||||
NonTrivCtor(); // expected-note 2{{user-provided default constructor}}
|
||||
};
|
||||
struct NonTrivCopy {
|
||||
NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-declared copy constructor}}
|
||||
NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-provided copy constructor}}
|
||||
};
|
||||
struct NonTrivDtor {
|
||||
~NonTrivDtor(); // expected-note 2{{user-declared destructor}}
|
||||
~NonTrivDtor(); // expected-note 2{{user-provided destructor}}
|
||||
};
|
||||
union BadUnion {
|
||||
NonTrivCtor ntc; // expected-warning {{union member 'ntc' with a non-trivial constructor is incompatible with C++98}}
|
||||
|
@ -338,8 +338,8 @@ namespace NullPointerTemplateArg {
|
|||
|
||||
namespace PR13480 {
|
||||
struct basic_iterator {
|
||||
basic_iterator(const basic_iterator &it) {}
|
||||
basic_iterator(basic_iterator &it) {} // expected-note {{because type 'PR13480::basic_iterator' has a user-declared copy constructor}}
|
||||
basic_iterator(const basic_iterator &it) {} // expected-note {{because type 'PR13480::basic_iterator' has a user-provided copy constructor}}
|
||||
basic_iterator(basic_iterator &it) {}
|
||||
};
|
||||
|
||||
union test {
|
||||
|
@ -349,12 +349,12 @@ namespace PR13480 {
|
|||
|
||||
namespace AssignOpUnion {
|
||||
struct a {
|
||||
void operator=(const a &it) {}
|
||||
void operator=(a &it) {} // expected-note {{because type 'AssignOpUnion::a' has a user-declared copy assignment operator}}
|
||||
void operator=(const a &it) {} // expected-note {{because type 'AssignOpUnion::a' has a user-provided copy assignment operator}}
|
||||
void operator=(a &it) {}
|
||||
};
|
||||
|
||||
struct b {
|
||||
void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-declared copy assignment operator}}
|
||||
void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-provided copy assignment operator}}
|
||||
};
|
||||
|
||||
union test1 {
|
||||
|
@ -364,9 +364,9 @@ namespace AssignOpUnion {
|
|||
}
|
||||
|
||||
namespace rdar11736429 {
|
||||
struct X {
|
||||
struct X { // expected-note {{because type 'rdar11736429::X' has no default constructor}}
|
||||
X(const X&) = delete; // expected-warning{{deleted function definitions are incompatible with C++98}} \
|
||||
// expected-note{{because type 'rdar11736429::X' has a user-declared constructor}}
|
||||
// expected-note {{implicit default constructor suppressed by user-declared constructor}}
|
||||
};
|
||||
|
||||
union S {
|
||||
|
|
Loading…
Reference in New Issue