aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorSean Hunt <scshunt@csclub.uwaterloo.ca>2011-05-11 22:34:38 +0000
committerSean Hunt <scshunt@csclub.uwaterloo.ca>2011-05-11 22:34:38 +0000
commitcdee3fee8ca4df7fb9179f29cc3ba96ac4fd0f95 (patch)
tree9d86f43d739eac08f4290ac8d1563ea609d83ef1 /lib/Sema
parent83e0995105222b078a57e1e20ef71fbfd0f67d3d (diff)
Implement implicit deletion of default constructors.
Yes, I'm aware that the diagnostics are awful. Tests to follow. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131203 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/SemaDecl.cpp5
-rw-r--r--lib/Sema/SemaDeclCXX.cpp186
-rw-r--r--lib/Sema/SemaLookup.cpp6
3 files changed, 189 insertions, 8 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 29343886f7..44e47ea8d8 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -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
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 47e4ca129e..bd16cda9f1 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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();
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index db8d29c1bb..2bfa86cb55 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -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);