summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-08-21 18:42:58 +0000
committerDouglas Gregor <dgregor@apple.com>2009-08-21 18:42:58 +0000
commitdec06664a1c4d8984251083db2215875aea1c80d (patch)
tree09fc85de440d129a44ac8684befc2f947829228d
parenteb0b6d556ff2b4a5053e89fd084eb34e44cea14c (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79658 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclCXX.h2
-rw-r--r--lib/AST/DeclCXX.cpp12
-rw-r--r--lib/Parse/ParseDecl.cpp5
-rw-r--r--lib/Sema/SemaDeclCXX.cpp19
-rw-r--r--lib/Sema/SemaOverload.cpp59
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp96
-rw-r--r--test/SemaTemplate/constructor-template.cpp24
-rw-r--r--test/SemaTemplate/member-function-template.cpp2
8 files changed, 127 insertions, 92 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 327f9ff622..bffedfcd78 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -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(); }
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index b126a09fc4..5c0bbec1ff 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -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());
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index d3d2cf06e3..597d43fb1b 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 15d32b08a7..5de302e174 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 21196d9cfa..f21b38a649 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -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)) {
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 078c32b439..9e05b3231e 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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;
diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp
new file mode 100644
index 0000000000..14df2e2632
--- /dev/null
+++ b/test/SemaTemplate/constructor-template.cpp
@@ -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}}
+}
diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp
index 0f3a37a702..906980ac11 100644
--- a/test/SemaTemplate/member-function-template.cpp
+++ b/test/SemaTemplate/member-function-template.cpp
@@ -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);
-} \ No newline at end of file
+}