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:
Douglas Gregor 2009-08-21 18:42:58 +00:00
parent cb7444342b
commit 5ed5ae476e
8 changed files with 127 additions and 92 deletions

View File

@ -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(); }

View File

@ -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());

View File

@ -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;

View File

@ -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

View File

@ -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)) {

View File

@ -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;

View File

@ -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}}
}

View File

@ -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);
}
}