aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp227
1 files changed, 199 insertions, 28 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b98777bad7..d80bfb9b7e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2998,19 +2998,31 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
- for (CXXRecordDecl::ctor_iterator CI = Record->ctor_begin(),
- CE = Record->ctor_end();
- CI != CE; ++CI) {
- if (!CI->isInvalidDecl() && CI->isExplicitlyDefaulted()) {
- if (CI->isDefaultConstructor()) {
- CheckExplicitlyDefaultedDefaultConstructor(*CI);
- }
+ for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
+ ME = Record->method_end();
+ MI != ME; ++MI) {
+ if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) {
+ switch (getSpecialMember(*MI)) {
+ case CXXDefaultConstructor:
+ CheckExplicitlyDefaultedDefaultConstructor(
+ cast<CXXConstructorDecl>(*MI));
+ break;
+
+ case CXXDestructor:
+ CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI));
+ break;
- // FIXME: Do copy and move constructors
+ case CXXCopyConstructor:
+ case CXXCopyAssignment:
+ // FIXME: Do copy and move constructors and assignment operators
+ break;
+
+ default:
+ llvm_unreachable("non-special member explicitly defaulted!");
+ }
}
}
- // FIXME: Do copy and move assignment and destructors
}
void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
@@ -3038,7 +3050,8 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
if (CtorType->hasExceptionSpec()) {
if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec),
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << 0 /* default constructor */,
PDiag(),
ExceptionType, SourceLocation(),
CtorType, CD->getLocation())) {
@@ -3056,8 +3069,48 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
CD->setDeletedAsWritten();
else
Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
- << getSpecialMember(CD);
+ << 0 /* default constructor */;
+ }
+}
+
+void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
+ assert(DD->isExplicitlyDefaulted());
+
+ // Whether this was the first-declared instance of the destructor.
+ bool First = DD == DD->getCanonicalDecl();
+
+ ImplicitExceptionSpecification Spec
+ = ComputeDefaultedDtorExceptionSpec(DD->getParent());
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *DtorType = DD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ if (DtorType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << 3 /* destructor */,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ DtorType, DD->getLocation())) {
+ DD->setInvalidDecl();
+ return;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // There are no parameters.
+ DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
}
+
+ if (ShouldDeleteDestructor(DD)) {
+ if (First)
+ DD->setDeletedAsWritten();
+ else
+ Diag(DD->getLocation(), diag::err_out_of_line_default_deletes)
+ << 3 /* destructor */;
+ }
+
+ CheckDestructor(DD);
}
bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
@@ -3072,8 +3125,6 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
bool Union = RD->isUnion();
bool AllConst = true;
- DiagnosticErrorTrap Trap(Diags);
-
// We do this because we should never actually use an anonymous
// union's constructor.
if (Union && RD->isAnonymousStructOrUnion())
@@ -3087,6 +3138,10 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
BE = RD->bases_end();
BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
@@ -3099,10 +3154,6 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
AR_accessible)
return true;
- // We'll handle this one later
- if (BI->isVirtual())
- continue;
-
// -- any [direct base class either] has no default constructor or
// overload resolution as applied to [its] default constructor
// results in an ambiguity or in a function that is deleted or
@@ -3234,6 +3285,109 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
return false;
}
+bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) {
+ CXXRecordDecl *RD = DD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ // Do access control from the destructor
+ ContextRAII CtorContext(*this, DD);
+
+ bool Union = RD->isUnion();
+
+ // C++0x [class.dtor]p5
+ // A defaulted destructor for a class X is defined as deleted if:
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ assert(BaseDtor && "base has no destructor");
+
+ // -- any direct or virtual base class has a deleted destructor or
+ // a destructor that is inaccessible from the defaulted destructor
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(SourceLocation(), BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ assert(BaseDtor && "base has no destructor");
+
+ // -- any direct or virtual base class has a deleted destructor or
+ // a destructor that is inaccessible from the defaulted destructor
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(SourceLocation(), BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+ if (FieldRecord) {
+ if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(FI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ // -- X is a union-like class that has a variant member with a non-
+ // trivial destructor.
+ if (UnionFieldRecord && !UnionFieldRecord->hasTrivialDestructor())
+ return true;
+ }
+ // Technically we are supposed to do this next check unconditionally.
+ // But that makes absolutely no sense.
+ } else {
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+
+ // -- any of the non-static data members has class type M (or array
+ // thereof) and M has a deleted destructor or a destructor that is
+ // inaccessible from the defaulted destructor
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(SourceLocation(), FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- X is a union-like class that has a variant member with a non-
+ // trivial destructor.
+ if (Union && !FieldDtor->isTrivial())
+ return true;
+ }
+ }
+ }
+
+ if (DD->isVirtual()) {
+ FunctionDecl *OperatorDelete = 0;
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (FindDeallocationFunction(SourceLocation(), RD, Name, OperatorDelete,
+ false))
+ return true;
+ }
+
+
+ return false;
+}
+
/// \brief Data used with FindHiddenVirtualMethod
namespace {
struct FindHiddenVirtualMethodData {
@@ -5480,12 +5634,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
}
}
-CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
- // C++ [class.dtor]p2:
- // If a class has no user-declared destructor, a destructor is
- // declared implicitly. An implicitly-declared destructor is an
- // inline public member of its class.
-
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have
// an exception-specification.
@@ -5522,11 +5672,20 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
}
+ return ExceptSpec;
+}
+
+CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
+ // C++ [class.dtor]p2:
+ // If a class has no user-declared destructor, a destructor is
+ // declared implicitly. An implicitly-declared destructor is an
+ // inline public member of its class.
+
+ ImplicitExceptionSpecification Spec =
+ ComputeDefaultedDtorExceptionSpec(ClassDecl);
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+
// Create the actual destructor declaration.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
CanQualType ClassType
@@ -5540,6 +5699,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
+ Destructor->setDefaulted();
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
@@ -5553,6 +5713,9 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// This could be uniqued if it ever proves significant.
Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
+
+ if (ShouldDeleteDestructor(Destructor))
+ Destructor->setDeletedAsWritten();
AddOverriddenMethods(ClassDecl, Destructor);
@@ -5561,7 +5724,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor) {
- assert((Destructor->isImplicit() && !Destructor->isUsed(false)) &&
+ assert((Destructor->isDefaulted() && !Destructor->isUsed(false)) &&
"DefineImplicitDestructor - call it for implicit default dtor");
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
@@ -7882,6 +8045,14 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
DefineImplicitDefaultConstructor(DefaultLoc, CD);
break;
}
+
+ case CXXDestructor: {
+ CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);
+ CheckExplicitlyDefaultedDestructor(DD);
+ DefineImplicitDestructor(DefaultLoc, DD);
+ break;
+ }
+
default:
// FIXME: Do the rest once we have functions
break;