Implement caching of default constructors on the resolution table. This

isn't yet used for the less controlled environments of initialization.

Also a few random text fixups.

llvm-svn: 132833
This commit is contained in:
Alexis Hunt 2011-06-10 03:50:41 +00:00
parent 280ddee8bd
commit eef8ee0c8d
4 changed files with 197 additions and 75 deletions

View File

@ -1668,6 +1668,7 @@ public:
SourceLocation GnuLabelLoc = SourceLocation());
DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class);
CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class);
CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class);
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
@ -3465,6 +3466,10 @@ public:
const InitializedEntity &Entity,
AccessSpecifier Access,
bool IsCopyBindingRefToTemp = false);
AccessResult CheckConstructorAccess(SourceLocation Loc,
CXXConstructorDecl *D,
AccessSpecifier Access,
PartialDiagnostic PD);
AccessResult CheckDestructorAccess(SourceLocation Loc,
CXXDestructorDecl *Dtor,
const PartialDiagnostic &PDiag);

View File

@ -1460,30 +1460,48 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
DeclAccessPair::make(Constructor, Access),
QualType());
PartialDiagnostic PD(PDiag());
switch (Entity.getKind()) {
default:
AccessEntity.setDiag(IsCopyBindingRefToTemp
? diag::ext_rvalue_to_reference_access_ctor
: diag::err_access_ctor);
PD = PDiag(IsCopyBindingRefToTemp
? diag::ext_rvalue_to_reference_access_ctor
: diag::err_access_ctor);
break;
case InitializedEntity::EK_Base:
AccessEntity.setDiag(PDiag(diag::err_access_base_ctor)
<< Entity.isInheritedVirtualBase()
<< Entity.getBaseSpecifier()->getType()
<< getSpecialMember(Constructor));
PD = PDiag(diag::err_access_base_ctor);
PD << Entity.isInheritedVirtualBase()
<< Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
break;
case InitializedEntity::EK_Member: {
const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
AccessEntity.setDiag(PDiag(diag::err_access_field_ctor)
<< Field->getType()
<< getSpecialMember(Constructor));
PD = PDiag(diag::err_access_field_ctor);
PD << Field->getType() << getSpecialMember(Constructor);
break;
}
}
return CheckConstructorAccess(UseLoc, Constructor, Access, PD);
}
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
AccessSpecifier Access,
PartialDiagnostic PD) {
if (!getLangOptions().AccessControl ||
Access == AS_public)
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
DeclAccessPair::make(Constructor, Access),
QualType());
AccessEntity.setDiag(PD);
return CheckAccess(*this, UseLoc, AccessEntity);
}

View File

@ -3318,7 +3318,7 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
// 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:
// 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();
@ -3331,7 +3331,7 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
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
// deleted or inaccessible from the defaulted default constructor
CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
if (BaseDtor->isDeleted())
return true;
@ -3343,14 +3343,12 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
// 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(Loc, Loc, Loc);
CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
if (!BaseDefault || BaseDefault->isDeleted())
return true;
InitializationSequence InitSeq(*this, BaseEntity, Kind, 0, 0);
if (InitSeq.Failed())
if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
PDiag()) != AR_accessible)
return true;
}
@ -3373,14 +3371,12 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
// 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(Loc, Loc, Loc);
CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
if (!BaseDefault || BaseDefault->isDeleted())
return true;
InitializationSequence InitSeq(*this, BaseEntity, Kind, 0, 0);
if (InitSeq.Failed())
if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
PDiag()) != AR_accessible)
return true;
}
@ -3448,22 +3444,24 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
// This is technically non-conformant, but sanity demands it.
continue;
}
// -- any non-static data member ... 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.
CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
if (!FieldDefault || FieldDefault->isDeleted())
return true;
if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
PDiag()) != AR_accessible)
return true;
} else if (!Union && FieldType.isConstQualified()) {
// -- 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
return true;
}
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*FI, 0);
InitializationKind Kind =
InitializationKind::CreateDirect(Loc, Loc, Loc);
InitializationSequence InitSeq(*this, MemberEntity, Kind, 0, 0);
if (InitSeq.Failed())
return true;
}
if (Union && AllConst)
@ -3548,7 +3546,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
// -- any [direct base class] of a type with a destructor that is deleted or
// -- any [virtual base class] of a type with a destructor that is deleted or
// inaccessible from the defaulted constructor
CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
if (BaseDtor->isDeleted())
@ -5895,28 +5893,6 @@ namespace {
};
}
static CXXConstructorDecl *getDefaultConstructorUnsafe(Sema &Self,
CXXRecordDecl *D) {
ASTContext &Context = Self.Context;
QualType ClassType = Context.getTypeDeclType(D);
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType.getUnqualifiedType()));
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
Con != ConEnd; ++Con) {
// FIXME: In C++0x, a constructor template can be a default constructor.
if (isa<FunctionTemplateDecl>(*Con))
continue;
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
if (Constructor->isDefaultConstructor())
return Constructor;
}
return 0;
}
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// C++ [except.spec]p14:
@ -5933,10 +5909,10 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (BaseClassDecl->needsImplicitDefaultConstructor())
ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
else if (CXXConstructorDecl *Constructor
= getDefaultConstructorUnsafe(*this, BaseClassDecl))
CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}
@ -5947,10 +5923,10 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
B != BEnd; ++B) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (BaseClassDecl->needsImplicitDefaultConstructor())
ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
else if (CXXConstructorDecl *Constructor
= getDefaultConstructorUnsafe(*this, BaseClassDecl))
CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}
@ -5961,12 +5937,14 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
F != FEnd; ++F) {
if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldClassDecl->needsImplicitDefaultConstructor())
ExceptSpec.CalledDecl(
DeclareImplicitDefaultConstructor(FieldClassDecl));
else if (CXXConstructorDecl *Constructor
= getDefaultConstructorUnsafe(*this, FieldClassDecl))
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
// In particular, the problem is that this function never gets called. It
// might just be ill-formed because this function attempts to refer to
// a deleted function here.
if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}

View File

@ -2186,12 +2186,133 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
return Result;
}
llvm_unreachable("haven't implemented this for non-destructors yet");
// Prepare for overload resolution. Here we construct a synthetic argument
// if necessary and make sure that implicit functions are declared.
CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D));
DeclarationName Name;
Expr *Arg = 0;
unsigned NumArgs;
if (SM == CXXDefaultConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
NumArgs = 0;
if (D->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(D);
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
if (!D->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(D);
// TODO: Move constructors
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
if (!D->hasDeclaredCopyAssignment())
DeclareImplicitCopyAssignment(D);
// TODO: Move assignment
}
QualType ArgType = CanTy;
if (ConstArg)
ArgType.addConst();
if (VolatileArg)
ArgType.addVolatile();
// This isn't /really/ specified by the standard, but it's implied
// we should be working from an RValue in the case of move to ensure
// that we prefer to bind to rvalue references, and an LValue in the
// case of copy to ensure we don't bind to rvalue references.
// Possibly an XValue is actually correct in the case of move, but
// there is no semantic difference for class types in this restricted
// case.
ExprValueKind VK;
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
VK = VK_LValue;
else
VK = VK_RValue;
NumArgs = 1;
Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType, VK);
}
// Create the object argument
QualType ThisTy = CanTy;
if (ConstThis)
ThisTy.addConst();
if (VolatileThis)
ThisTy.addVolatile();
Expr::Classification ObjectClassification =
(new (Context) OpaqueValueExpr(SourceLocation(), ThisTy,
RValueThis ? VK_RValue : VK_LValue))->
Classify(Context);
// Now we perform lookup on the name we computed earlier and do overload
// resolution. Lookup is only performed directly into the class since there
// will always be a (possibly implicit) declaration to shadow any others.
OverloadCandidateSet OCS((SourceLocation()));
DeclContext::lookup_iterator I, E;
Result->setConstParamMatch(false);
llvm::tie(I, E) = D->lookup(Name);
assert((I != E) &&
"lookup for a constructor or assignment operator was empty");
for ( ; I != E; ++I) {
if ((*I)->isInvalidDecl())
continue;
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) {
AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs,
OCS, true);
// Here we're looking for a const parameter to speed up creation of
// implicit copy methods.
if ((SM == CXXCopyAssignment && M->isCopyAssignmentOperator()) ||
(SM == CXXCopyConstructor &&
cast<CXXConstructorDecl>(M)->isCopyConstructor())) {
QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0);
if (ArgType->getPointeeType().isConstQualified())
Result->setConstParamMatch(true);
}
} else {
FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I);
AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
0, &Arg, NumArgs, OCS, true);
}
}
OverloadCandidateSet::iterator Best;
switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) {
case OR_Success:
Result->setMethod(cast<CXXMethodDecl>(Best->Function));
Result->setSuccess(true);
break;
case OR_Deleted:
Result->setMethod(cast<CXXMethodDecl>(Best->Function));
Result->setSuccess(false);
break;
case OR_Ambiguous:
case OR_No_Viable_Function:
Result->setMethod(0);
Result->setSuccess(false);
break;
}
return Result;
}
/// \brief Look up the default constructor for the given class.
CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) {
SpecialMemberOverloadResult *Result =
LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false,
false, false);
return cast_or_null<CXXConstructorDecl>(Result->getMethod());
}
/// \brief Look up the constructors for the given class.
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the copy constructor has not yet been declared, do so now.
// If the implicit constructors have not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Context, Class)) {
if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);