A step towards sorting out handling of triviality of special members in C++11.
Separate out the notions of 'has a trivial special member' and 'has a
non-trivial special member', and use them appropriately. These are not
opposites of one another (there might be no special member, or in C++11 there
might be a trivial one and a non-trivial one). The CXXRecordDecl predicates
continue to produce incorrect results, but do so in fewer cases now, and
they document the cases where they might be wrong.
No functionality changes are intended here (they will come when the predicates
start producing the right answers...).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168119 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 72516fd..cc19ce9 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -9735,13 +9735,18 @@
// copy constructors.
CXXSpecialMember member = CXXInvalid;
- if (!RDecl->hasTrivialCopyConstructor())
+ // We're required to check for any non-trivial constructors. Since the
+ // implicit default constructor is suppressed if there are any
+ // user-declared constructors, we just need to check that there is a
+ // trivial default constructor and a trivial copy constructor. (We don't
+ // worry about move constructors here, since this is a C++98 check.)
+ if (RDecl->hasNonTrivialCopyConstructor())
member = CXXCopyConstructor;
else if (!RDecl->hasTrivialDefaultConstructor())
member = CXXDefaultConstructor;
- else if (!RDecl->hasTrivialCopyAssignment())
+ else if (RDecl->hasNonTrivialCopyAssignment())
member = CXXCopyAssignment;
- else if (!RDecl->hasTrivialDestructor())
+ else if (RDecl->hasNonTrivialDestructor())
member = CXXDestructor;
if (member != CXXInvalid) {
@@ -9789,6 +9794,8 @@
/// 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());
@@ -9887,17 +9894,21 @@
}
}
- bool (CXXRecordDecl::*hasTrivial)() const;
+ bool (CXXRecordDecl::*hasNonTrivial)() const;
switch (member) {
case CXXDefaultConstructor:
- hasTrivial = &CXXRecordDecl::hasTrivialDefaultConstructor; break;
+ hasNonTrivial = &CXXRecordDecl::hasNonTrivialDefaultConstructor; break;
case CXXCopyConstructor:
- hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
+ hasNonTrivial = &CXXRecordDecl::hasNonTrivialCopyConstructor; break;
case CXXCopyAssignment:
- hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
+ hasNonTrivial = &CXXRecordDecl::hasNonTrivialCopyAssignment; break;
+ case CXXMoveConstructor:
+ hasNonTrivial = &CXXRecordDecl::hasNonTrivialMoveConstructor; break;
+ case CXXMoveAssignment:
+ hasNonTrivial = &CXXRecordDecl::hasNonTrivialMoveAssignment; break;
case CXXDestructor:
- hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
- default:
+ hasNonTrivial = &CXXRecordDecl::hasNonTrivialDestructor; break;
+ case CXXInvalid:
llvm_unreachable("unexpected special member");
}
@@ -9906,7 +9917,7 @@
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->*hasTrivial)()) {
+ if ((BaseRecTy->*hasNonTrivial)()) {
SourceLocation BaseLoc = bi->getLocStart();
Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
DiagnoseNontrivial(BaseRT, member);
@@ -9922,7 +9933,7 @@
if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
- if (!(EltRD->*hasTrivial)()) {
+ if ((EltRD->*hasNonTrivial)()) {
SourceLocation FLoc = fi->getLocation();
Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
DiagnoseNontrivial(EltRT, member);
@@ -9945,8 +9956,6 @@
}
}
}
-
- llvm_unreachable("found no explanation for non-trivial member");
}
/// TranslateIvarVisibility - Translate visibility from a token ID to an
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index a8ddc51..e98f75e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -8201,10 +8201,7 @@
if (BaseClass->needsImplicitMoveAssignment())
S.DeclareImplicitMoveAssignment(BaseClass);
- // If the class has both a trivial move assignment and a non-trivial move
- // assignment, hasTrivialMoveAssignment() is false.
- if (BaseClass->hasDeclaredMoveAssignment() &&
- !BaseClass->hasTrivialMoveAssignment())
+ if (BaseClass->hasNonTrivialMoveAssignment())
return true;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e419ba5..840f04f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -635,16 +635,16 @@
if (Ty.isCXX98PODType(Context))
return VAK_Valid;
- // C++0x [expr.call]p7:
- // Passing a potentially-evaluated argument of class type (Clause 9)
+ // C++11 [expr.call]p7:
+ // Passing a potentially-evaluated argument of class type (Clause 9)
// having a non-trivial copy constructor, a non-trivial move constructor,
- // or a non-trivial destructor, with no corresponding parameter,
+ // or a non-trivial destructor, with no corresponding parameter,
// is conditionally-supported with implementation-defined semantics.
if (getLangOpts().CPlusPlus0x && !Ty->isDependentType())
if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl())
- if (Record->hasTrivialCopyConstructor() &&
- Record->hasTrivialMoveConstructor() &&
- Record->hasTrivialDestructor())
+ if (!Record->hasNonTrivialCopyConstructor() &&
+ !Record->hasNonTrivialMoveConstructor() &&
+ !Record->hasNonTrivialDestructor())
return VAK_ValidInCXX11;
if (getLangOpts().ObjCAutoRefCount && Ty->isObjCLifetimeType())