aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/Sema.h8
-rw-r--r--lib/Sema/SemaDecl.cpp181
-rw-r--r--lib/Sema/SemaDeclCXX.cpp57
3 files changed, 218 insertions, 28 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 7f652f2c1a..7daf3f90a8 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -541,6 +541,14 @@ public:
SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D = 0);
+
+ enum CXXSpecialMember {
+ CXXDefaultConstructor = 0,
+ CXXCopyConstructor = 1,
+ CXXCopyAssignment = 2,
+ CXXDestructor = 3
+ };
+ void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
DeclPtrTy IntfDecl,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index beceeef54d..2db0725611 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2265,6 +2265,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
CurClass->setPOD(false);
CurClass->setPolymorphic(true);
CurClass->setHasTrivialConstructor(false);
+ CurClass->setHasTrivialCopyConstructor(false);
+ CurClass->setHasTrivialCopyAssignment(false);
}
}
@@ -2505,6 +2507,7 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
// C++ [class.dtor]p3: A destructor is trivial if it is an implicitly-
// declared destructor.
+ // FIXME: C++0x: don't do this for "= default" destructors
Record->setHasTrivialDestructor(false);
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(NewFD))
@@ -4085,6 +4088,57 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
NewFD->setInvalidDecl();
}
+ if (getLangOptions().CPlusPlus) {
+ QualType EltTy = T;
+ while (const ArrayType *AT = Context.getAsArrayType(EltTy))
+ EltTy = AT->getElementType();
+
+ if (const RecordType *RT = EltTy->getAsRecordType()) {
+ CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+ if (!RDecl->hasTrivialConstructor())
+ cast<CXXRecordDecl>(Record)->setHasTrivialConstructor(false);
+ if (!RDecl->hasTrivialCopyConstructor())
+ cast<CXXRecordDecl>(Record)->setHasTrivialCopyConstructor(false);
+ if (!RDecl->hasTrivialCopyAssignment())
+ cast<CXXRecordDecl>(Record)->setHasTrivialCopyAssignment(false);
+ if (!RDecl->hasTrivialDestructor())
+ cast<CXXRecordDecl>(Record)->setHasTrivialDestructor(false);
+
+ // C++ 9.5p1: An object of a class with a non-trivial
+ // constructor, a non-trivial copy constructor, a non-trivial
+ // destructor, or a non-trivial copy assignment operator
+ // cannot be a member of a union, nor can an array of such
+ // objects.
+ // TODO: C++0x alters this restriction significantly.
+ if (Record->isUnion()) {
+ // We check for copy constructors before constructors
+ // because otherwise we'll never get complaints about
+ // copy constructors.
+
+ const CXXSpecialMember invalid = (CXXSpecialMember) -1;
+
+ CXXSpecialMember member;
+ if (!RDecl->hasTrivialCopyConstructor())
+ member = CXXCopyConstructor;
+ else if (!RDecl->hasTrivialConstructor())
+ member = CXXDefaultConstructor;
+ else if (!RDecl->hasTrivialCopyAssignment())
+ member = CXXCopyAssignment;
+ else if (!RDecl->hasTrivialDestructor())
+ member = CXXDestructor;
+ else
+ member = invalid;
+
+ if (member != invalid) {
+ Diag(Loc, diag::err_illegal_union_member) << Name << member;
+ DiagnoseNontrivial(RT, member);
+ NewFD->setInvalidDecl();
+ }
+ }
+ }
+ }
+
if (getLangOptions().CPlusPlus && !T->isPODType())
cast<CXXRecordDecl>(Record)->setPOD(false);
@@ -4113,6 +4167,133 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
return NewFD;
}
+/// DiagnoseNontrivial - Given that a class has a non-trivial
+/// special member, figure out why.
+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 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 (!ci->isImplicitlyDefined(Context)) {
+ SourceLocation CtorLoc = ci->getLocation();
+ Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+
+ assert(0 && "found no user-declared constructors");
+ return;
+ }
+ break;
+
+ case CXXCopyConstructor:
+ if (RD->hasUserDeclaredCopyConstructor()) {
+ SourceLocation CtorLoc =
+ RD->getCopyConstructor(Context, 0)->getLocation();
+ Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
+ case CXXCopyAssignment:
+ if (RD->hasUserDeclaredCopyAssignment()) {
+ // FIXME: this should use the location of the copy
+ // assignment, not the type.
+ SourceLocation TyLoc = RD->getSourceRange().getBegin();
+ Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
+ case CXXDestructor:
+ if (RD->hasUserDeclaredDestructor()) {
+ SourceLocation DtorLoc = RD->getDestructor(Context)->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->getSourceRange().getBegin();
+ 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->getSourceRange().getBegin();
+ Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
+ return;
+ }
+ }
+ }
+
+ bool (CXXRecordDecl::*hasTrivial)() const;
+ switch (member) {
+ case CXXDefaultConstructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
+ case CXXCopyConstructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
+ case CXXCopyAssignment:
+ hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
+ case CXXDestructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
+ default:
+ assert(0 && "unexpected special member"); return;
+ }
+
+ // 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()->getAsRecordType();
+ assert(BaseRT);
+ CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
+ if (!(BaseRecTy->*hasTrivial)()) {
+ SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+ 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 = (*fi)->getType();
+ while (const ArrayType *AT = Context.getAsArrayType(EltTy))
+ EltTy = AT->getElementType();
+
+ if (const RecordType *EltRT = EltTy->getAsRecordType()) {
+ CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
+
+ if (!(EltRD->*hasTrivial)()) {
+ SourceLocation FLoc = (*fi)->getLocation();
+ Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
+ DiagnoseNontrivial(EltRT, member);
+ return;
+ }
+ }
+ }
+
+ assert(0 && "found no explanation for non-trivial member");
+}
+
/// TranslateIvarVisibility - Translate visibility from a token ID to an
/// AST enum value.
static ObjCIvarDecl::AccessControl
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 2b8d0a8972..3681709f91 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -400,19 +400,40 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// C++ [class.ctor]p5:
// A constructor is trivial if its class has no virtual base classes.
Class->setHasTrivialConstructor(false);
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if its class has no virtual base classes.
+ Class->setHasTrivialCopyConstructor(false);
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if its class has no virtual
+ // base classes.
+ Class->setHasTrivialCopyAssignment(false);
} else {
// C++ [class.ctor]p5:
// A constructor is trivial if all the direct base classes of its
// class have trivial constructors.
- Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)->
- hasTrivialConstructor());
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor())
+ Class->setHasTrivialConstructor(false);
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if all the direct base classes of its
+ // class have trivial copy constructors.
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor())
+ Class->setHasTrivialCopyConstructor(false);
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if all the direct base classes
+ // of its class have trivial copy assignment operators.
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment())
+ Class->setHasTrivialCopyAssignment(false);
}
// C++ [class.ctor]p3:
// A destructor is trivial if all the direct base classes of its class
// have trivial destructors.
- Class->setHasTrivialDestructor(cast<CXXRecordDecl>(BaseDecl)->
- hasTrivialDestructor());
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor())
+ Class->setHasTrivialDestructor(false);
// Create the base specifier.
// FIXME: Allocate via ASTContext?
@@ -1154,30 +1175,6 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
if (RD->isAbstract())
AbstractClassUsageDiagnoser(*this, RD);
- if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) {
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- // All the nonstatic data members must have trivial constructors.
- QualType FTy = i->getType();
- while (const ArrayType *AT = Context.getAsArrayType(FTy))
- FTy = AT->getElementType();
-
- if (const RecordType *RT = FTy->getAsRecordType()) {
- CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl());
-
- if (!FieldRD->hasTrivialConstructor())
- RD->setHasTrivialConstructor(false);
- if (!FieldRD->hasTrivialDestructor())
- RD->setHasTrivialDestructor(false);
-
- // If RD has neither a trivial constructor nor a trivial destructor
- // we don't need to continue checking.
- if (!RD->hasTrivialConstructor() && !RD->hasTrivialDestructor())
- break;
- }
- }
- }
-
if (!RD->isDependentType())
AddImplicitlyDeclaredMembersToClass(RD);
}
@@ -1213,6 +1210,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*isImplicitlyDeclared=*/true);
DefaultCon->setAccess(AS_public);
DefaultCon->setImplicit();
+ DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
ClassDecl->addDecl(DefaultCon);
}
@@ -1283,6 +1281,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*isImplicitlyDeclared=*/true);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setImplicit();
+ CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
@@ -1359,6 +1358,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
+ CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
@@ -1388,6 +1388,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
Destructor->setImplicit();
+ Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
ClassDecl->addDecl(Destructor);
}
}