Implement implicit deletion of default constructors.

Yes, I'm aware that the diagnostics are awful.

Tests to follow.

llvm-svn: 131203
This commit is contained in:
Alexis Hunt 2011-05-11 22:34:38 +00:00
parent 6f7289d9c5
commit ea6f0320f0
8 changed files with 210 additions and 21 deletions

View File

@ -436,9 +436,9 @@ class CXXRecordDecl : public RecordDecl {
/// already computed and are available.
bool ComputedVisibleConversions : 1;
/// \brief Whether we have already declared the default constructor or
/// do not need to have one declared.
bool NeedsImplicitDefaultConstructor : 1;
/// \brief Whether we have a C++0x user-provided default constructor (not
/// explicitly deleted or defaulted.
bool UserProvidedDefaultConstructor : 1;
/// \brief Whether we have already declared the default constructor.
bool DeclaredDefaultConstructor : 1;
@ -675,12 +675,13 @@ public:
return data().FirstFriend != 0;
}
/// \brief Determine whether this class has had its default constructor
/// declared implicitly or does not need one declared implicitly.
/// \brief Determine if we need to declare a default constructor for
/// this class.
///
/// This value is used for lazy creation of default constructors.
bool needsImplicitDefaultConstructor() const {
return data().NeedsImplicitDefaultConstructor;
return !data().UserDeclaredConstructor &&
!data().DeclaredDefaultConstructor;
}
/// hasConstCopyConstructor - Determines whether this class has a
@ -710,6 +711,12 @@ public:
return data().UserDeclaredConstructor;
}
/// hasUserProvidedDefaultconstructor - Whether this class has a
/// user-provided default constructor per C++0x.
bool hasUserProvidedDefaultConstructor() const {
return data().UserProvidedDefaultConstructor;
}
/// hasUserDeclaredCopyConstructor - Whether this class has a
/// user-declared copy constructor. When false, a copy constructor
/// will be implicitly declared.

View File

@ -2582,6 +2582,10 @@ public:
ImplicitExceptionSpecification
ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl);
/// \brief Determine if a defaulted default constructor ought to be
/// deleted.
bool ShouldDeleteDefaultConstructor(CXXConstructorDecl *RD);
/// \brief Declare the implicit default constructor for the given class.
///
/// \param ClassDecl The class declaration into which the implicit

View File

@ -38,7 +38,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
NeedsImplicitDefaultConstructor(false), DeclaredDefaultConstructor(false),
UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
DeclaredCopyConstructor(false), DeclaredCopyAssignment(false),
DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(),
Definition(D), FirstFriend(0) {
@ -460,7 +460,6 @@ void CXXRecordDecl::addedMember(Decl *D) {
// declared it.
if (Constructor->isDefaultConstructor()) {
data().DeclaredDefaultConstructor = true;
data().NeedsImplicitDefaultConstructor = true;
}
// If this is the implicit copy constructor, note that we have now
// declared it.
@ -491,9 +490,6 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Note that we have a user-declared constructor.
data().UserDeclaredConstructor = true;
// Note that we have no need of an implicitly-declared default constructor.
data().NeedsImplicitDefaultConstructor = true;
// FIXME: Under C++0x, /only/ special member functions may be user-provided.
// This is probably a defect.
bool UserProvided = false;
@ -504,6 +500,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().DeclaredDefaultConstructor = true;
if (Constructor->isUserProvided()) {
data().HasTrivialDefaultConstructor = false;
data().UserProvidedDefaultConstructor = true;
UserProvided = true;
}
}

View File

@ -5642,7 +5642,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
const RecordType *Record
= Context.getBaseElementType(Type)->getAs<RecordType>();
if (Record && getLangOptions().CPlusPlus &&
if (Record && getLangOptions().CPlusPlus && !getLangOptions().CPlusPlus0x &&
cast<CXXRecordDecl>(Record->getDecl())->isPOD()) {
// C++03 [dcl.init]p9:
// If no initializer is specified for an object, and the
@ -5655,6 +5655,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// any, have an indeterminate initial value); if the object
// or any of its subobjects are of const-qualified type, the
// program is ill-formed.
// C++0x [dcl.init]p11:
// If no initializer is specified for an object, the object is
// default-intiialized; [...].
} else {
// Check for jumps past the implicit initializer. C++0x
// clarifies that this applies to a "variable with automatic

View File

@ -3057,7 +3057,180 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
// We know there are no parameters.
CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
}
}
bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *RD = CD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x)
return false;
// Do access control from the constructor
ContextRAII CtorContext(*this, 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())
return false;
// FIXME: We should put some diagnostic logic right into this function.
// C++0x [class.ctor]/5
// A defaulted default constructor for class X is defined as delete if:
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
BE = RD->bases_end();
BI != BE; ++BI) {
CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
// -- any [direct base class] has a type with a destructor that is
// delete or inaccessible from the defaulted default constructor
CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
if (BaseDtor->isDeleted())
return true;
if (CheckDestructorAccess(SourceLocation(), BaseDtor, PDiag()) !=
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
// inaccessible from the defaulted default constructor
InitializedEntity BaseEntity =
InitializedEntity::InitializeBase(Context, BI, 0);
InitializationKind Kind =
InitializationKind::CreateDirect(SourceLocation(), SourceLocation(),
SourceLocation());
InitializationSequence InitSeq(*this, BaseEntity, Kind, 0, 0);
if (InitSeq.getKind() == InitializationSequence::FailedSequence)
return true;
}
for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
BE = RD->vbases_end();
BI != BE; ++BI) {
CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
// -- any [virtual base class] has a type with a destructor that is
// delete or inaccessible from the defaulted default constructor
CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
if (BaseDtor->isDeleted())
return true;
if (CheckDestructorAccess(SourceLocation(), BaseDtor, PDiag()) !=
AR_accessible)
return true;
// -- any [virtual 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
// inaccessible from the defaulted default constructor
InitializedEntity BaseEntity =
InitializedEntity::InitializeBase(Context, BI, BI);
InitializationKind Kind =
InitializationKind::CreateDirect(SourceLocation(), SourceLocation(),
SourceLocation());
InitializationSequence InitSeq(*this, BaseEntity, Kind, 0, 0);
if (InitSeq.getKind() == InitializationSequence::FailedSequence)
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();
// -- any non-static data member with no brace-or-equal-initializer is of
// reference type
if (FieldType->isReferenceType())
return true;
// -- X is a union and all its variant members are of const-qualified type
// (or array thereof)
if (Union && !FieldType.isConstQualified())
AllConst = false;
if (FieldRecord) {
// -- X is a union-like class that has a variant member with a non-trivial
// default constructor
if (Union && !FieldRecord->hasTrivialDefaultConstructor())
return true;
CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
if (FieldDtor->isDeleted())
return true;
if (CheckDestructorAccess(SourceLocation(), FieldDtor, PDiag()) !=
AR_accessible)
return true;
// -- any non-variant non-static data member of const-qualified type (or
// array thereof) with no brace-or-equal-initializer does not have a
// user-provided default constructor
if (FieldType.isConstQualified() &&
!FieldRecord->hasUserProvidedDefaultConstructor())
return true;
if (!Union && FieldRecord->isUnion() &&
FieldRecord->isAnonymousStructOrUnion()) {
// We're okay to reuse AllConst here since we only care about the
// value otherwise if we're in a union.
AllConst = true;
for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
UE = FieldRecord->field_end();
UI != UE; ++UI) {
QualType UnionFieldType = Context.getBaseElementType(UI->getType());
CXXRecordDecl *UnionFieldRecord =
UnionFieldType->getAsCXXRecordDecl();
if (!UnionFieldType.isConstQualified())
AllConst = false;
if (UnionFieldRecord &&
!UnionFieldRecord->hasTrivialDefaultConstructor())
return true;
}
if (AllConst)
return true;
// Don't try to initialize the anonymous union
// This is technically non-conformant, but sanity deamands it.
continue;
}
}
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*FI, 0);
InitializationKind Kind =
InitializationKind::CreateDirect(SourceLocation(), SourceLocation(),
SourceLocation());
InitializationSequence InitSeq(*this, MemberEntity, Kind, 0, 0);
if (InitSeq.getKind() == InitializationSequence::FailedSequence)
return true;
}
if (Union && AllConst)
return true;
return false;
}
/// \brief Data used with FindHiddenVirtualMethod
@ -5010,7 +5183,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (!BaseClassDecl->needsImplicitDefaultConstructor())
if (BaseClassDecl->needsImplicitDefaultConstructor())
ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
else if (CXXConstructorDecl *Constructor
= getDefaultConstructorUnsafe(*this, BaseClassDecl))
@ -5024,7 +5197,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
B != BEnd; ++B) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (!BaseClassDecl->needsImplicitDefaultConstructor())
if (BaseClassDecl->needsImplicitDefaultConstructor())
ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
else if (CXXConstructorDecl *Constructor
= getDefaultConstructorUnsafe(*this, BaseClassDecl))
@ -5039,7 +5212,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
if (!FieldClassDecl->needsImplicitDefaultConstructor())
if (FieldClassDecl->needsImplicitDefaultConstructor())
ExceptSpec.CalledDecl(
DeclareImplicitDefaultConstructor(FieldClassDecl));
else if (CXXConstructorDecl *Constructor
@ -5087,6 +5260,11 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
// Do not delete this yet if we're in a template
if (!ClassDecl->isDependentType() &&
ShouldDeleteDefaultConstructor(DefaultCon))
DefaultCon->setDeletedAsWritten();
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(DefaultCon, S, false);
@ -5098,7 +5276,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor) {
assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
!Constructor->isUsed(false)) &&
!Constructor->isUsed(false) && !Constructor->isDeleted()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
CXXRecordDecl *ClassDecl = Constructor->getParent();

View File

@ -534,7 +534,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
return;
// If the default constructor has not yet been declared, do so now.
if (!Class->needsImplicitDefaultConstructor())
if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
// If the copy constructor has not yet been declared, do so now.
@ -581,7 +581,7 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
if (Record->getDefinition() &&
CanDeclareSpecialMemberFunction(S.Context, Record)) {
if (!Record->needsImplicitDefaultConstructor())
if (Record->needsImplicitDefaultConstructor())
S.DeclareImplicitDefaultConstructor(
const_cast<CXXRecordDecl *>(Record));
if (!Record->hasDeclaredCopyConstructor())
@ -2140,7 +2140,7 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the copy constructor has not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Context, Class)) {
if (!Class->needsImplicitDefaultConstructor())
if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
if (!Class->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(Class);

View File

@ -867,7 +867,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasTrivialDestructor = Record[Idx++];
Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
Data.NeedsImplicitDefaultConstructor = Record[Idx++];
Data.UserProvidedDefaultConstructor = Record[Idx++];
Data.DeclaredDefaultConstructor = Record[Idx++];
Data.DeclaredCopyConstructor = Record[Idx++];
Data.DeclaredCopyAssignment = Record[Idx++];

View File

@ -3827,7 +3827,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasTrivialDestructor);
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record.push_back(Data.ComputedVisibleConversions);
Record.push_back(Data.NeedsImplicitDefaultConstructor);
Record.push_back(Data.UserProvidedDefaultConstructor);
Record.push_back(Data.DeclaredDefaultConstructor);
Record.push_back(Data.DeclaredCopyConstructor);
Record.push_back(Data.DeclaredCopyAssignment);