forked from OSchip/llvm-project
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:
parent
6f7289d9c5
commit
ea6f0320f0
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++];
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue