[cfe-commits] r131259 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Sema/SemaAccess.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp
Sean Hunt
scshunt at csclub.uwaterloo.ca
Thu May 12 15:46:25 PDT 2011
Author: coppro
Date: Thu May 12 17:46:25 2011
New Revision: 131259
URL: http://llvm.org/viewvc/llvm-project?rev=131259&view=rev
Log:
Hrm
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaAccess.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=131259&r1=131258&r2=131259&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu May 12 17:46:25 2011
@@ -3629,7 +3629,9 @@
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 "
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=131259&r1=131258&r2=131259&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu May 12 17:46:25 2011
@@ -2582,9 +2582,17 @@
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 @@
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 @@
void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record);
void CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *Ctor);
+ void CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *Dtor);
//===--------------------------------------------------------------------===//
// C++ Derived Classes
@@ -3347,7 +3357,8 @@
AccessResult CheckAllocationAccess(SourceLocation OperatorLoc,
SourceRange PlacementRange,
CXXRecordDecl *NamingClass,
- DeclAccessPair FoundDecl);
+ DeclAccessPair FoundDecl,
+ bool Diagnose = true);
AccessResult CheckConstructorAccess(SourceLocation Loc,
CXXConstructorDecl *D,
const InitializedEntity &Entity,
Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=131259&r1=131258&r2=131259&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Thu May 12 17:46:25 2011
@@ -1463,7 +1463,8 @@
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 @@
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);
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=131259&r1=131258&r2=131259&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu May 12 17:46:25 2011
@@ -2998,19 +2998,31 @@
}
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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
}
}
-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 @@
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 @@
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
+ Destructor->setDefaulted();
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
@@ -5553,6 +5713,9 @@
// 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 @@
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 @@
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;
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=131259&r1=131258&r2=131259&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu May 12 17:46:25 2011
@@ -9866,7 +9866,7 @@
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());
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=131259&r1=131258&r2=131259&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu May 12 17:46:25 2011
@@ -1569,7 +1569,7 @@
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 @@
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 @@
Expr* DeallocArgs[1];
DeallocArgs[0] = &Null;
if (FindAllocationOverload(StartLoc, SourceRange(), Name,
- DeallocArgs, 1, TUDecl, /*AllowMissing=*/false,
+ DeallocArgs, 1, TUDecl, AllowMissing,
Operator))
return true;
More information about the cfe-commits
mailing list