forked from OSchip/llvm-project
Introduce support for constructor templates, which can now be declared
and will participate in overload resolution. Unify the instantiation of CXXMethodDecls and CXXConstructorDecls, which had already gotten out-of-sync. llvm-svn: 79658
This commit is contained in:
parent
cb7444342b
commit
5ed5ae476e
|
@ -161,6 +161,8 @@ public:
|
|||
OverloadIterator(OverloadedFunctionDecl *Ovl)
|
||||
: D(Ovl), Iter(Ovl->function_begin()) { }
|
||||
|
||||
OverloadIterator(NamedDecl *ND);
|
||||
|
||||
reference operator*() const;
|
||||
|
||||
pointer operator->() const { return (**this).get(); }
|
||||
|
|
|
@ -712,6 +712,18 @@ OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
|
|||
return new (C) OverloadedFunctionDecl(DC, N);
|
||||
}
|
||||
|
||||
OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) {
|
||||
if (!ND)
|
||||
return;
|
||||
|
||||
if (isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND))
|
||||
D = ND;
|
||||
else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(ND)) {
|
||||
D = ND;
|
||||
Iter = Ovl->function_begin();
|
||||
}
|
||||
}
|
||||
|
||||
void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) {
|
||||
Functions.push_back(F);
|
||||
this->setLocation(F.get()->getLocation());
|
||||
|
|
|
@ -844,7 +844,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
// being defined and the next token is a '(', then this is a
|
||||
// constructor declaration. We're done with the decl-specifiers
|
||||
// and will treat this token as an identifier.
|
||||
if (getLang().CPlusPlus && CurScope->isClassScope() &&
|
||||
if (getLang().CPlusPlus &&
|
||||
(CurScope->isClassScope() ||
|
||||
(CurScope->isTemplateParamScope() &&
|
||||
CurScope->getParent()->isClassScope())) &&
|
||||
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
|
||||
NextToken().getKind() == tok::l_paren)
|
||||
goto DoneWithDeclSpec;
|
||||
|
|
|
@ -2599,11 +2599,24 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
|
|||
DeclContext::lookup_const_iterator Con, ConEnd;
|
||||
for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
|
||||
Con != ConEnd; ++Con) {
|
||||
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
|
||||
// Find the constructor (which may be a template).
|
||||
CXXConstructorDecl *Constructor = 0;
|
||||
FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
|
||||
if (ConstructorTmpl)
|
||||
Constructor
|
||||
= cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
|
||||
else
|
||||
Constructor = cast<CXXConstructorDecl>(*Con);
|
||||
|
||||
if ((Kind == IK_Direct) ||
|
||||
(Kind == IK_Copy && Constructor->isConvertingConstructor()) ||
|
||||
(Kind == IK_Default && Constructor->isDefaultConstructor()))
|
||||
AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
|
||||
(Kind == IK_Default && Constructor->isDefaultConstructor())) {
|
||||
if (ConstructorTmpl)
|
||||
AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0,
|
||||
Args, NumArgs, CandidateSet);
|
||||
else
|
||||
AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: When we decide not to synthesize the implicitly-declared
|
||||
|
|
|
@ -1343,11 +1343,27 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
|
|||
for (llvm::tie(Con, ConEnd)
|
||||
= ToRecordDecl->lookup(ConstructorName);
|
||||
Con != ConEnd; ++Con) {
|
||||
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
|
||||
// Find the constructor (which may be a template).
|
||||
CXXConstructorDecl *Constructor = 0;
|
||||
FunctionTemplateDecl *ConstructorTmpl
|
||||
= dyn_cast<FunctionTemplateDecl>(*Con);
|
||||
if (ConstructorTmpl)
|
||||
Constructor
|
||||
= cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
|
||||
else
|
||||
Constructor = cast<CXXConstructorDecl>(*Con);
|
||||
|
||||
if (!Constructor->isInvalidDecl() &&
|
||||
Constructor->isConvertingConstructor())
|
||||
AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
|
||||
/*SuppressUserConversions=*/true, ForceRValue);
|
||||
Constructor->isConvertingConstructor()) {
|
||||
if (ConstructorTmpl)
|
||||
AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From,
|
||||
1, CandidateSet,
|
||||
/*SuppressUserConversions=*/true,
|
||||
ForceRValue);
|
||||
else
|
||||
AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
|
||||
/*SuppressUserConversions=*/true, ForceRValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4324,29 +4340,18 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||
OverloadCandidateSet CandidateSet;
|
||||
DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName();
|
||||
|
||||
if (OverloadedFunctionDecl *Ovl
|
||||
= dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) {
|
||||
for (OverloadedFunctionDecl::function_iterator
|
||||
Func = Ovl->function_begin(),
|
||||
FuncEnd = Ovl->function_end();
|
||||
Func != FuncEnd; ++Func) {
|
||||
if ((Method = dyn_cast<CXXMethodDecl>(*Func)))
|
||||
AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
|
||||
/*SuppressUserConversions=*/false);
|
||||
else
|
||||
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
|
||||
/*FIXME:*/false, /*FIXME:*/0,
|
||||
/*FIXME:*/0, ObjectArg, Args, NumArgs,
|
||||
CandidateSet,
|
||||
/*SuppressUsedConversions=*/false);
|
||||
}
|
||||
} else
|
||||
AddMethodTemplateCandidate(
|
||||
cast<FunctionTemplateDecl>(MemExpr->getMemberDecl()),
|
||||
/*FIXME:*/false, /*FIXME:*/0,
|
||||
/*FIXME:*/0, ObjectArg, Args, NumArgs,
|
||||
CandidateSet,
|
||||
/*SuppressUsedConversions=*/false);
|
||||
for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd;
|
||||
Func != FuncEnd; ++Func) {
|
||||
if ((Method = dyn_cast<CXXMethodDecl>(*Func)))
|
||||
AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
|
||||
/*SuppressUserConversions=*/false);
|
||||
else
|
||||
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
|
||||
/*FIXME:*/false, /*FIXME:*/0,
|
||||
/*FIXME:*/0, ObjectArg, Args, NumArgs,
|
||||
CandidateSet,
|
||||
/*SuppressUsedConversions=*/false);
|
||||
}
|
||||
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (BestViableFunction(CandidateSet, MemExpr->getLocStart(), Best)) {
|
||||
|
|
|
@ -485,10 +485,25 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
|||
|
||||
// Build the instantiated method declaration.
|
||||
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
|
||||
CXXMethodDecl *Method
|
||||
= CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
|
||||
D->getDeclName(), T, D->getDeclaratorInfo(),
|
||||
D->isStatic(), D->isInline());
|
||||
CXXMethodDecl *Method = 0;
|
||||
|
||||
DeclarationName Name = D->getDeclName();
|
||||
CXXConstructorDecl *ConstructorD = dyn_cast<CXXConstructorDecl>(D);
|
||||
if (ConstructorD) {
|
||||
QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
|
||||
Name = SemaRef.Context.DeclarationNames.getCXXConstructorName(
|
||||
SemaRef.Context.getCanonicalType(ClassTy));
|
||||
Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
|
||||
ConstructorD->getLocation(),
|
||||
Name, T,
|
||||
ConstructorD->getDeclaratorInfo(),
|
||||
ConstructorD->isExplicit(),
|
||||
ConstructorD->isInline(), false);
|
||||
} else {
|
||||
Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
|
||||
D->getDeclName(), T, D->getDeclaratorInfo(),
|
||||
D->isStatic(), D->isInline());
|
||||
}
|
||||
|
||||
if (!FunctionTemplate)
|
||||
Method->setInstantiationOfMemberFunction(D);
|
||||
|
@ -507,15 +522,20 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
|||
if (InitMethodInstantiation(Method, D))
|
||||
Method->setInvalidDecl();
|
||||
|
||||
NamedDecl *PrevDecl
|
||||
= SemaRef.LookupQualifiedName(Owner, Method->getDeclName(),
|
||||
Sema::LookupOrdinaryName, true);
|
||||
// In C++, the previous declaration we find might be a tag type
|
||||
// (class or enum). In this case, the new declaration will hide the
|
||||
// tag type. Note that this does does not apply if we're declaring a
|
||||
// typedef (C++ [dcl.typedef]p4).
|
||||
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
PrevDecl = 0;
|
||||
NamedDecl *PrevDecl = 0;
|
||||
|
||||
if (!FunctionTemplate) {
|
||||
PrevDecl = SemaRef.LookupQualifiedName(Owner, Name,
|
||||
Sema::LookupOrdinaryName, true);
|
||||
|
||||
// In C++, the previous declaration we find might be a tag type
|
||||
// (class or enum). In this case, the new declaration will hide the
|
||||
// tag type. Note that this does does not apply if we're declaring a
|
||||
// typedef (C++ [dcl.typedef]p4).
|
||||
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
PrevDecl = 0;
|
||||
}
|
||||
|
||||
bool Redeclaration = false;
|
||||
bool OverloadableAttrRequired = false;
|
||||
SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
|
||||
|
@ -528,60 +548,16 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
|||
&TemplateArgs,
|
||||
InsertPos);
|
||||
else if (!Method->isInvalidDecl() || !PrevDecl)
|
||||
Owner->addDecl(Method);
|
||||
Owner->addDecl(Method);
|
||||
|
||||
return Method;
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
|
||||
// FIXME: Look for existing, explicit specializations.
|
||||
Sema::LocalInstantiationScope Scope(SemaRef);
|
||||
|
||||
llvm::SmallVector<ParmVarDecl *, 4> Params;
|
||||
QualType T = InstantiateFunctionType(D, Params);
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
// Build the instantiated method declaration.
|
||||
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
|
||||
QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
|
||||
DeclarationName Name
|
||||
= SemaRef.Context.DeclarationNames.getCXXConstructorName(
|
||||
SemaRef.Context.getCanonicalType(ClassTy));
|
||||
CXXConstructorDecl *Constructor
|
||||
= CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(),
|
||||
Name, T, D->getDeclaratorInfo(),
|
||||
D->isExplicit(), D->isInline(), false);
|
||||
Constructor->setInstantiationOfMemberFunction(D);
|
||||
|
||||
// Attach the parameters
|
||||
for (unsigned P = 0; P < Params.size(); ++P)
|
||||
Params[P]->setOwningFunction(Constructor);
|
||||
Constructor->setParams(SemaRef.Context, Params.data(), Params.size());
|
||||
|
||||
if (InitMethodInstantiation(Constructor, D))
|
||||
Constructor->setInvalidDecl();
|
||||
|
||||
NamedDecl *PrevDecl
|
||||
= SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true);
|
||||
|
||||
// In C++, the previous declaration we find might be a tag type
|
||||
// (class or enum). In this case, the new declaration will hide the
|
||||
// tag type. Note that this does does not apply if we're declaring a
|
||||
// typedef (C++ [dcl.typedef]p4).
|
||||
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
PrevDecl = 0;
|
||||
bool Redeclaration = false;
|
||||
bool OverloadableAttrRequired = false;
|
||||
SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration,
|
||||
/*FIXME:*/OverloadableAttrRequired);
|
||||
|
||||
Record->addedConstructor(SemaRef.Context, Constructor);
|
||||
Owner->addDecl(Constructor);
|
||||
return Constructor;
|
||||
return VisitCXXMethodDecl(D);
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
|
||||
// FIXME: Look for existing, explicit specializations.
|
||||
Sema::LocalInstantiationScope Scope(SemaRef);
|
||||
|
||||
llvm::SmallVector<ParmVarDecl *, 4> Params;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
struct X0 { // expected-note{{candidate}}
|
||||
X0(int); // expected-note{{candidate}}
|
||||
template<typename T> X0(T);
|
||||
template<typename T, typename U> X0(T*, U*);
|
||||
};
|
||||
|
||||
void accept_X0(X0);
|
||||
|
||||
void test_X0(int i, float f) {
|
||||
X0 x0a(i);
|
||||
X0 x0b(f);
|
||||
X0 x0c = i;
|
||||
X0 x0d = f;
|
||||
accept_X0(i);
|
||||
accept_X0(&i);
|
||||
accept_X0(f);
|
||||
accept_X0(&f);
|
||||
X0 x0e(&i, &f);
|
||||
X0 x0f(&f, &i);
|
||||
|
||||
X0 x0g(f, &i); // expected-error{{no matching constructor}}
|
||||
}
|
|
@ -27,4 +27,4 @@ void test_X_f1(X x, int i, float f) {
|
|||
int &ir1 = x.f1(i);
|
||||
int &ir2 = x.f1(f, i);
|
||||
int &ir3 = x.f1(i, i);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue