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:
Richard Smith 2012-12-08 02:53:02 +00:00
parent f77b0f8886
commit 92f241f188
21 changed files with 979 additions and 442 deletions

View File

@ -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.
///

View File

@ -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();

View File

@ -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">;

View File

@ -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);
//===--------------------------------------------------------------------===//

View File

@ -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());

View File

@ -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())

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

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

View File

@ -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;

View File

@ -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();

View File

@ -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 {

View File

@ -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}}

View File

@ -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 {

View File

@ -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 &&), "");

View File

@ -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&&), "");

View File

@ -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");

View File

@ -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 {
};

View File

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

View File

@ -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 {