diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 227 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 39 |
4 files changed, 226 insertions, 50 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index f340bb3fda..80995eb66f 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1463,7 +1463,8 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, SourceRange PlacementRange, CXXRecordDecl *NamingClass, - DeclAccessPair Found) { + DeclAccessPair Found, + bool Diagnose) { if (!getLangOptions().AccessControl || !NamingClass || Found.getAccess() == AS_public) @@ -1471,8 +1472,9 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, QualType()); - Entity.setDiag(diag::err_access) - << PlacementRange; + if (Diagnose) + Entity.setDiag(diag::err_access) + << PlacementRange; return CheckAccess(*this, OpLoc, Entity); } 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; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e2426952b2..5a171eca98 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9866,7 +9866,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { MarkVTableUsed(Loc, Constructor->getParent()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { - if (Destructor->isImplicit() && !Destructor->isUsed(false)) + if (Destructor->isDefaulted() && !Destructor->isUsed(false)) DefineImplicitDestructor(Loc, Destructor); if (Destructor->isVirtual()) MarkVTableUsed(Loc, Destructor->getParent()); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index b2a67aa935..867bd3515b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1569,7 +1569,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, - FunctionDecl* &Operator) { + FunctionDecl* &Operator, bool AllowMissing) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); @@ -1597,32 +1597,35 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, if (Matches.size() == 1) { Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl()); CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), - Matches[0]); + Matches[0], !AllowMissing); return false; // We found multiple suitable operators; complain about the ambiguity. } else if (!Matches.empty()) { - Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) - << Name << RD; - - for (llvm::SmallVectorImpl<DeclAccessPair>::iterator - F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) - Diag((*F)->getUnderlyingDecl()->getLocation(), - diag::note_member_declared_here) << Name; + if (!AllowMissing) { + Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) + << Name << RD; + + for (llvm::SmallVectorImpl<DeclAccessPair>::iterator + F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) + Diag((*F)->getUnderlyingDecl()->getLocation(), + diag::note_member_declared_here) << Name; + } return true; } // We did find operator delete/operator delete[] declarations, but // none of them were suitable. if (!Found.empty()) { - Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) - << Name << RD; - - for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); - F != FEnd; ++F) - Diag((*F)->getUnderlyingDecl()->getLocation(), - diag::note_member_declared_here) << Name; - + if (!AllowMissing) { + Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) + << Name << RD; + + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); + F != FEnd; ++F) + Diag((*F)->getUnderlyingDecl()->getLocation(), + diag::note_member_declared_here) << Name; + } return true; } @@ -1634,7 +1637,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Expr* DeallocArgs[1]; DeallocArgs[0] = &Null; if (FindAllocationOverload(StartLoc, SourceRange(), Name, - DeallocArgs, 1, TUDecl, /*AllowMissing=*/false, + DeallocArgs, 1, TUDecl, AllowMissing, Operator)) return true; |