diff options
author | Sean Hunt <scshunt@csclub.uwaterloo.ca> | 2011-05-12 22:46:25 +0000 |
---|---|---|
committer | Sean Hunt <scshunt@csclub.uwaterloo.ca> | 2011-05-12 22:46:25 +0000 |
commit | cb45a0f42964ab5fa1474b25abcc1ae3a8bd0ab8 (patch) | |
tree | 5dd2297bb73ce9419b11740944166afd88b202f0 /lib/Sema/SemaDeclCXX.cpp | |
parent | 5762c0bec6b73a7f6360a71b94b07b7ba0e4b5e8 (diff) |
Hrm
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131259 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 227 |
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; |