[cfe-commits] r131203 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/Sema/Sema.h lib/AST/DeclCXX.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaLookup.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriter.cpp
Sean Hunt
scshunt at csclub.uwaterloo.ca
Wed May 11 15:34:38 PDT 2011
Author: coppro
Date: Wed May 11 17:34:38 2011
New Revision: 131203
URL: http://llvm.org/viewvc/llvm-project?rev=131203&view=rev
Log:
Implement implicit deletion of default constructors.
Yes, I'm aware that the diagnostics are awful.
Tests to follow.
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/lib/Serialization/ASTWriter.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=131203&r1=131202&r2=131203&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed May 11 17:34:38 2011
@@ -436,9 +436,9 @@
/// 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 @@
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 @@
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.
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=131203&r1=131202&r2=131203&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed May 11 17:34:38 2011
@@ -2582,6 +2582,10 @@
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
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=131203&r1=131202&r2=131203&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed May 11 17:34:38 2011
@@ -38,7 +38,7 @@
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 @@
// 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 @@
// 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 @@
data().DeclaredDefaultConstructor = true;
if (Constructor->isUserProvided()) {
data().HasTrivialDefaultConstructor = false;
+ data().UserProvidedDefaultConstructor = true;
UserProvided = true;
}
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=131203&r1=131202&r2=131203&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed May 11 17:34:38 2011
@@ -5642,7 +5642,7 @@
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 @@
// 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
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=131203&r1=131202&r2=131203&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed May 11 17:34:38 2011
@@ -3057,7 +3057,180 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
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();
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=131203&r1=131202&r2=131203&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed May 11 17:34:38 2011
@@ -534,7 +534,7 @@
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 @@
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 @@
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);
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=131203&r1=131202&r2=131203&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed May 11 17:34:38 2011
@@ -867,7 +867,7 @@
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++];
Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=131203&r1=131202&r2=131203&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed May 11 17:34:38 2011
@@ -3827,7 +3827,7 @@
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);
More information about the cfe-commits
mailing list