[cfe-commits] r141528 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp test/CXX/special/class.ctor/p5-0x.cpp
Sean Hunt
scshunt at csclub.uwaterloo.ca
Sun Oct 9 23:18:57 PDT 2011
Author: coppro
Date: Mon Oct 10 01:18:57 2011
New Revision: 141528
URL: http://llvm.org/viewvc/llvm-project?rev=141528&view=rev
Log:
Begin work consolidating ShouldDelete* functions.
Begin with just default constructors. One note is that as a side effect
of this, a conformance test was removed on the basis that this is almost
certainly a defect as with most of union initialization. As it is, clang
does not implement union initialization close to the standard as it's
quite broken as written. I hope to write a paper addressing the issues
eventually.
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=141528&r1=141527&r2=141528&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Oct 10 01:18:57 2011
@@ -2830,9 +2830,9 @@
ImplicitExceptionSpecification
ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl);
- /// \brief Determine if a defaulted default constructor ought to be
- /// deleted.
- bool ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD);
+ /// \brief Determine if a special member function should have a deleted
+ /// definition when it is defaulted.
+ bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM);
/// \brief Determine if a defaulted copy constructor ought to be
/// deleted.
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=141528&r1=141527&r2=141528&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Oct 10 01:18:57 2011
@@ -3742,7 +3742,7 @@
return;
}
- if (ShouldDeleteDefaultConstructor(CD)) {
+ if (ShouldDeleteSpecialMember(CD, CXXDefaultConstructor)) {
if (First) {
CD->setDeletedAsWritten();
} else {
@@ -4096,30 +4096,44 @@
}
}
-bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
- CXXRecordDecl *RD = CD->getParent();
+/// This function implements the following C++0x paragraphs:
+/// - [class.ctor]/5
+bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) {
+ assert(!MD->isInvalidDecl());
+ CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
- SourceLocation Loc = CD->getLocation();
+ bool IsUnion = RD->isUnion();
+ bool IsConstructor = false;
+ bool IsAssignment = false;
+ bool IsMove = false;
+
+ bool ConstArg = false;
+
+ switch (CSM) {
+ case CXXDefaultConstructor:
+ IsConstructor = true;
+ break;
+ default:
+ llvm_unreachable("function only currently implemented for default ctors");
+ }
+
+ SourceLocation Loc = MD->getLocation();
// Do access control from the constructor
- ContextRAII CtorContext(*this, CD);
+ ContextRAII MethodContext(*this, MD);
- bool Union = RD->isUnion();
bool AllConst = true;
// We do this because we should never actually use an anonymous
// union's constructor.
- if (Union && RD->isAnonymousStructOrUnion())
+ if (IsUnion && 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 deleted if:
-
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
BE = RD->bases_end();
BI != BE; ++BI) {
@@ -4130,26 +4144,33 @@
CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
- // -- any [direct base class] has a type with a destructor that is
- // deleted or inaccessible from the defaulted default constructor
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- if (BaseDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
- return true;
-
- // -- 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
- CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
- if (!BaseDefault || BaseDefault->isDeleted())
- return true;
+ // Unless we have an assignment operator, the base's destructor must
+ // be accessible and not deleted.
+ if (!IsAssignment) {
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
- if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
- PDiag()) != AR_accessible)
- return true;
+ // Finding the corresponding member in the base should lead to a
+ // unique, accessible, non-deleted function.
+ if (CSM != CXXDestructor) {
+ SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(BaseDecl, CSM, ConstArg, false, IsMove, false,
+ false);
+ if (!SMOR->hasSuccess())
+ return true;
+ CXXMethodDecl *BaseMember = SMOR->getMethod();
+ if (IsConstructor) {
+ CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember);
+ if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+ }
}
for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
@@ -4158,26 +4179,33 @@
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(Loc, 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
- CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
- if (!BaseDefault || BaseDefault->isDeleted())
- return true;
+ // Unless we have an assignment operator, the base's destructor must
+ // be accessible and not deleted.
+ if (!IsAssignment) {
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
- if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
- PDiag()) != AR_accessible)
- return true;
+ // Finding the corresponding member in the base should lead to a
+ // unique, accessible, non-deleted function.
+ if (CSM != CXXDestructor) {
+ SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(BaseDecl, CSM, ConstArg, false, IsMove, false,
+ false);
+ if (!SMOR->hasSuccess())
+ return true;
+ CXXMethodDecl *BaseMember = SMOR->getMethod();
+ if (IsConstructor) {
+ CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember);
+ if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+ }
}
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
@@ -4189,38 +4217,38 @@
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() && !FI->hasInClassInitializer())
- return true;
+ // For a default constructor, all references must be initialized in-class
+ // and, if a union, it must have a non-const member.
+ if (CSM == CXXDefaultConstructor) {
+ if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
+ 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 (IsUnion && !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(Loc, FieldDtor, PDiag()) !=
- AR_accessible)
- return true;
+ // Unless we're doing assignment, the field's destructor must be
+ // accessible and not deleted.
+ if (!IsAssignment) {
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, 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() &&
+ // For a default constructor, a const member must have a user-provided
+ // default constructor or else be explicitly initialized.
+ if (CSM == CXXDefaultConstructor && FieldType.isConstQualified() &&
!FI->hasInClassInitializer() &&
!FieldRecord->hasUserProvidedDefaultConstructor())
return true;
- if (!Union && FieldRecord->isUnion() &&
+ // For a default constructor, additional restrictions exist on the
+ // variant members.
+ if (CSM == CXXDefaultConstructor && !IsUnion && 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.
@@ -4249,29 +4277,43 @@
continue;
}
- // -- any non-static data member with no brace-or-equal-initializer has
- // class type M (or array thereof) and either M has no default
- // constructor or overload resolution as applied to M's default
- // constructor results in an ambiguity or in a function that is deleted
- // or inaccessible from the defaulted default constructor.
- if (!FI->hasInClassInitializer()) {
- CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
- if (!FieldDefault || FieldDefault->isDeleted())
+ // Check that the corresponding member of the field is accessible,
+ // unique, and non-deleted. We don't do this if it has an explicit
+ // initialization when default-constructing.
+ if (CSM != CXXDestructor &&
+ (CSM != CXXDefaultConstructor || !FI->hasInClassInitializer())) {
+ SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(FieldRecord, CSM, ConstArg, false, IsMove, false,
+ false);
+ if (!SMOR->hasSuccess())
return true;
- if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
- PDiag()) != AR_accessible)
+
+ CXXMethodDecl *FieldMember = SMOR->getMethod();
+ if (IsConstructor) {
+ CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember);
+ if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+
+ // We need the corresponding member of a union to be trivial so that
+ // we can safely copy them all simultaneously.
+ // FIXME: Note that performing the check here (where we rely on the lack
+ // of an in-class initializer) is technically ill-formed. However, this
+ // seems most obviously to be a bug in the standard.
+ if (IsUnion && !FieldMember->isTrivial())
return true;
}
- } else if (!Union && FieldType.isConstQualified() &&
- !FI->hasInClassInitializer()) {
- // -- 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
+ } else if (CSM == CXXDefaultConstructor && !IsUnion &&
+ FieldType.isConstQualified() && !FI->hasInClassInitializer()) {
+ // We can't initialize a const member of non-class type to any value.
return true;
}
}
- if (Union && AllConst)
+ // We can't have all const members in a union when default-constructing,
+ // or else they're all nonsensical garbage values that can't be changed.
+ if (CSM == CXXDefaultConstructor && IsUnion && AllConst)
return true;
return false;
@@ -6979,7 +7021,7 @@
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
- if (ShouldDeleteDefaultConstructor(DefaultCon))
+ if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
DefaultCon->setDeletedAsWritten();
return DefaultCon;
Modified: cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp?rev=141528&r1=141527&r2=141528&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp Mon Oct 10 01:18:57 2011
@@ -23,10 +23,6 @@
// default constructor,
union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{deleted here}}
Deleted1a d1a; // expected-error {{deleted constructor}}
-// FIXME: treating this as having a deleted default constructor is probably a
-// bug in the standard.
-union Deleted1b { UserProvidedDefCtor u = UserProvidedDefCtor(); }; // expected-note {{deleted here}}
-Deleted1b d1b; // expected-error {{deleted constructor}}
union NotDeleted1a { DefaultedDefCtor1 nu; };
NotDeleted1a nd1a;
// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
More information about the cfe-commits
mailing list