return data().FirstFriend != 0;
}
+ /// \brief Determine whether this class has any default constructors.
+ bool hasDefaultConstructor() const {
+ return !data().UserDeclaredConstructor ||
+ data().DeclaredDefaultConstructor;
+ }
+
/// \brief Determine if we need to declare a default constructor for
/// this class.
///
!data().DeclaredDefaultConstructor;
}
- /// hasDeclaredDefaultConstructor - Whether this class's default constructor
- /// has been declared (either explicitly or implicitly).
+ /// \brief Determine whether any default constructors have been declared for
+ /// this class (either explicitly or implicitly).
bool hasDeclaredDefaultConstructor() const {
return data().DeclaredDefaultConstructor;
}
/// mutable field.
bool hasMutableFields() const { return data().HasMutableFields; }
- /// hasTrivialDefaultConstructor - Whether this class has a trivial default
- /// constructor (C++11 [class.ctor]p5).
+ /// \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 data().HasTrivialDefaultConstructor &&
- (!data().UserDeclaredConstructor ||
- data().DeclaredDefaultConstructor);
+ return hasDefaultConstructor() && data().HasTrivialDefaultConstructor;
+ }
+
+ /// \brief Determine whether this class has a non-trivial default constructor
+ /// (C++11 [class.ctor]p5).
+ bool hasNonTrivialDefaultConstructor() const {
+ return hasDefaultConstructor() && !data().HasTrivialDefaultConstructor;
}
- /// hasConstexprNonCopyMoveConstructor - Whether this class has at least one
- /// constexpr constructor other than the copy or move constructors.
+ /// \brief Determine whether this class has at least one constexpr constructor
+ /// other than the copy or move constructors.
bool hasConstexprNonCopyMoveConstructor() const {
return data().HasConstexprNonCopyMoveConstructor ||
(!hasUserDeclaredConstructor() &&
defaultedDefaultConstructorIsConstexpr());
}
- /// defaultedDefaultConstructorIsConstexpr - Whether a defaulted default
- /// constructor for this class would be constexpr.
+ /// \brief Determine whether a defaulted default constructor for this class
+ /// would be constexpr.
bool defaultedDefaultConstructorIsConstexpr() const {
return data().DefaultedDefaultConstructorIsConstexpr &&
(!isUnion() || hasInClassInitializer());
}
- /// hasConstexprDefaultConstructor - Whether this class has a constexpr
- /// default constructor.
+ /// \brief Determine whether this class has a constexpr default constructor.
bool hasConstexprDefaultConstructor() const {
return data().HasConstexprDefaultConstructor ||
(!data().UserDeclaredConstructor &&
defaultedDefaultConstructorIsConstexpr());
}
- // hasTrivialCopyConstructor - Whether this class has a trivial copy
- // constructor (C++ [class.copy]p6, C++0x [class.copy]p13)
+ /// \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().HasTrivialCopyConstructor;
}
- // hasTrivialMoveConstructor - Whether this class has a trivial move
- // constructor (C++0x [class.copy]p13)
+ /// \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().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.
bool hasTrivialMoveConstructor() const {
- return data().HasTrivialMoveConstructor;
+ return data().HasTrivialMoveConstructor &&
+ (hasDeclaredMoveConstructor() || needsImplicitMoveConstructor());
}
- // hasTrivialCopyAssignment - Whether this class has a trivial copy
- // assignment operator (C++ [class.copy]p11, C++0x [class.copy]p27)
+ /// \brief Determine whether this class has a non-trivial move constructor
+ /// (C++11 [class.copy]p12)
+ /// FIXME: This can be wrong if the implicit move constructor would be
+ /// deleted.
+ bool hasNonTrivialMoveConstructor() const {
+ return !data().HasTrivialMoveConstructor &&
+ (hasDeclaredMoveConstructor() || needsImplicitMoveConstructor());
+ }
+
+ /// \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().HasTrivialCopyAssignment;
}
- // hasTrivialMoveAssignment - Whether this class has a trivial move
- // assignment operator (C++0x [class.copy]p27)
+ /// \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().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.
bool hasTrivialMoveAssignment() const {
- return data().HasTrivialMoveAssignment;
+ return data().HasTrivialMoveAssignment &&
+ (hasDeclaredMoveAssignment() || needsImplicitMoveAssignment());
}
- // hasTrivialDestructor - Whether this class has a trivial destructor
- // (C++ [class.dtor]p3)
+ /// \brief Determine whether this class has a non-trivial move assignment
+ /// operator (C++11 [class.copy]p25)
+ /// FIXME: This can be wrong if the implicit move assignment would be deleted.
+ bool hasNonTrivialMoveAssignment() const {
+ return !data().HasTrivialMoveAssignment &&
+ (hasDeclaredMoveAssignment() || needsImplicitMoveAssignment());
+ }
+
+ /// \brief Determine whether this class has a trivial destructor
+ /// (C++ [class.dtor]p3)
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
+ /// \brief Determine whether this class has a non-trivial destructor
+ /// (C++ [class.dtor]p3)
+ bool hasNonTrivialDestructor() const { return !data().HasTrivialDestructor; }
+
// hasIrrelevantDestructor - Whether this class has a destructor which has no
// semantic effect. Any such destructor will be trivial, public, defaulted
// and not deleted, and will call only irrelevant destructors.
// non-trivial if it calls anything other than a trivial move constructor.
if (!BaseClassDecl->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
- if (!BaseClassDecl->hasTrivialMoveConstructor() ||
- !(BaseClassDecl->hasDeclaredMoveConstructor() ||
- BaseClassDecl->needsImplicitMoveConstructor()))
+ if (!BaseClassDecl->hasTrivialMoveConstructor())
data().HasTrivialMoveConstructor = false;
// C++0x [class.copy]p27:
// of all of them.
if (!BaseClassDecl->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
- if (!BaseClassDecl->hasTrivialMoveAssignment() ||
- !(BaseClassDecl->hasDeclaredMoveAssignment() ||
- BaseClassDecl->needsImplicitMoveAssignment()))
+ if (!BaseClassDecl->hasTrivialMoveAssignment())
data().HasTrivialMoveAssignment = false;
// C++11 [class.ctor]p6:
// C++0x [class]p5:
// A trivially copyable class is a class that:
// -- has no non-trivial copy constructors,
- if (!hasTrivialCopyConstructor()) return false;
+ if (hasNonTrivialCopyConstructor()) return false;
// -- has no non-trivial move constructors,
- if (!hasTrivialMoveConstructor()) return false;
+ if (hasNonTrivialMoveConstructor()) return false;
// -- has no non-trivial copy assignment operators,
- if (!hasTrivialCopyAssignment()) return false;
+ if (hasNonTrivialCopyAssignment()) return false;
// -- has no non-trivial move assignment operators, and
- if (!hasTrivialMoveAssignment()) return false;
+ if (hasNonTrivialMoveAssignment()) return false;
// -- has a trivial destructor.
if (!hasTrivialDestructor()) return false;
// FIXME: C++0x: We don't correctly model 'selected' constructors.
if (!FieldRec->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
- if (!FieldRec->hasTrivialMoveConstructor() ||
- !(FieldRec->hasDeclaredMoveConstructor() ||
- FieldRec->needsImplicitMoveConstructor()))
+ if (!FieldRec->hasTrivialMoveConstructor())
data().HasTrivialMoveConstructor = false;
// C++0x [class.copy]p27:
// FIXME: C++0x: We don't correctly model 'selected' operators.
if (!FieldRec->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
- if (!FieldRec->hasTrivialMoveAssignment() ||
- !(FieldRec->hasDeclaredMoveAssignment() ||
- FieldRec->needsImplicitMoveAssignment()))
+ if (!FieldRec->hasTrivialMoveAssignment())
data().HasTrivialMoveAssignment = false;
if (!FieldRec->hasTrivialDestructor())
if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // C++0x [class]p5:
- // A trivial class is a class that has a trivial default constructor
- if (!ClassDecl->hasTrivialDefaultConstructor()) return false;
- // and is trivially copyable.
- if (!ClassDecl->isTriviallyCopyable()) return false;
+ // C++11 [class]p6:
+ // A trivial class is a class that has a default constructor,
+ // has no non-trivial default constructors, and is trivially
+ // copyable.
+ return ClassDecl->hasDefaultConstructor() &&
+ !ClassDecl->hasNonTrivialDefaultConstructor() &&
+ ClassDecl->isTriviallyCopyable();
}
return true;
// Maintain semantics for classes with non-trivial dtors or copy ctors.
if (!record->hasTrivialDestructor()) return false;
- if (!record->hasTrivialCopyConstructor()) return false;
+ if (record->hasNonTrivialCopyConstructor()) return false;
// Otherwise, we just have to make sure there aren't any mutable
// fields that might have changed since initialization.
// If an aggregate variable has non trivial destructor or non trivial copy
// constructor than it is pass indirectly. Let debug info know about this
// by using reference of the aggregate type as a argument type.
- if (!Record->hasTrivialCopyConstructor() ||
+ if (Record->hasNonTrivialCopyConstructor() ||
!Record->hasTrivialDestructor())
Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
}
// Don't mess with non-trivial C++ types.
RecordDecl *Record = RecordTy->getDecl();
if (isa<CXXRecordDecl>(Record) &&
- (!cast<CXXRecordDecl>(Record)->hasTrivialCopyConstructor() ||
+ (cast<CXXRecordDecl>(Record)->hasNonTrivialCopyConstructor() ||
!cast<CXXRecordDecl>(Record)->hasTrivialDestructor()))
return false;
Record->hasTrivialCopyAssignment() ||
Record->hasTrivialMoveConstructor() ||
Record->hasTrivialMoveAssignment()) &&
- "Trying to aggregate-copy a type without a trivial copy "
+ "Trying to aggregate-copy a type without a trivial copy/move "
"constructor or assignment operator");
// Ignore empty classes in C++.
if (Record->isEmpty())
if (!RD)
return false;
- return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor();
+ return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor();
}
/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is
// 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) {
/// 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());
}
}
- 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");
}
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);
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);
}
}
}
-
- llvm_unreachable("found no explanation for non-trivial member");
}
/// TranslateIvarVisibility - Translate visibility from a token ID to an
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;
}
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())