forked from OSchip/llvm-project
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:
parent
280ddee8bd
commit
eef8ee0c8d
clang
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue