llvm-svn: 131259
This commit is contained in:
Alexis Hunt 2011-05-12 22:46:25 +00:00
parent 8a88026ae3
commit f9172946be
6 changed files with 241 additions and 52 deletions

View File

@ -3629,7 +3629,9 @@ def warn_explicit_conversion_functions : Warning<
def err_defaulted_default_ctor_params : Error<
"an explicitly-defaulted default constructor must have no parameters">;
def err_incorrect_defaulted_exception_spec : Error<
"exception specification of explicitly defaulted function is incorrect">;
"exception specification of explicitly defaulted %select{default constructor|"
"copy constructor|copy assignment operator|destructor}0 does not match the "
"calculated one">;
def err_out_of_line_default_deletes : Error<
"defaulting this %select{default constructor|copy constructor|copy "
"assignment operator|destructor}0 would delete it after its first "

View File

@ -2582,9 +2582,17 @@ public:
ImplicitExceptionSpecification
ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl);
/// \brief Determine what sort of exception specification a defaulted
/// destructor of a class will have.
ImplicitExceptionSpecification
ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl);
/// \brief Determine if a defaulted default constructor ought to be
/// deleted.
bool ShouldDeleteDefaultConstructor(CXXConstructorDecl *RD);
bool ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD);
/// \brief Determine if a defaulted destructor ought to be deleted.
bool ShouldDeleteDestructor(CXXDestructorDecl *DD);
/// \brief Declare the implicit default constructor for the given class.
///
@ -2794,7 +2802,8 @@ public:
bool addMallocAttr = false);
bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name, FunctionDecl* &Operator);
DeclarationName Name, FunctionDecl* &Operator,
bool AllowMissing = false);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
ExprResult ActOnCXXDelete(SourceLocation StartLoc,
@ -3259,6 +3268,7 @@ public:
void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record);
void CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *Ctor);
void CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *Dtor);
//===--------------------------------------------------------------------===//
// C++ Derived Classes
@ -3347,7 +3357,8 @@ public:
AccessResult CheckAllocationAccess(SourceLocation OperatorLoc,
SourceRange PlacementRange,
CXXRecordDecl *NamingClass,
DeclAccessPair FoundDecl);
DeclAccessPair FoundDecl,
bool Diagnose = true);
AccessResult CheckConstructorAccess(SourceLocation Loc,
CXXConstructorDecl *D,
const InitializedEntity &Entity,

View File

@ -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);
}

View File

@ -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;
// FIXME: Do copy and move constructors
case CXXDestructor:
CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI));
break;
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,10 +3069,50 @@ 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) {
CXXRecordDecl *RD = CD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
@ -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;

View File

@ -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());

View File

@ -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;
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;
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;