[cfe-commits] r79658 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/Parse/ParseDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/constructor-template.cpp test/SemaTemplate/member-function-template.cpp
Douglas Gregor
dgregor at apple.com
Fri Aug 21 11:42:58 PDT 2009
Author: dgregor
Date: Fri Aug 21 13:42:58 2009
New Revision: 79658
URL: http://llvm.org/viewvc/llvm-project?rev=79658&view=rev
Log:
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.
Added:
cfe/trunk/test/SemaTemplate/constructor-template.cpp
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/SemaTemplate/member-function-template.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=79658&r1=79657&r2=79658&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Aug 21 13:42:58 2009
@@ -161,6 +161,8 @@
OverloadIterator(OverloadedFunctionDecl *Ovl)
: D(Ovl), Iter(Ovl->function_begin()) { }
+ OverloadIterator(NamedDecl *ND);
+
reference operator*() const;
pointer operator->() const { return (**this).get(); }
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=79658&r1=79657&r2=79658&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Aug 21 13:42:58 2009
@@ -712,6 +712,18 @@
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());
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=79658&r1=79657&r2=79658&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Aug 21 13:42:58 2009
@@ -844,7 +844,10 @@
// 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;
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=79658&r1=79657&r2=79658&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Aug 21 13:42:58 2009
@@ -2599,11 +2599,24 @@
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
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=79658&r1=79657&r2=79658&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Aug 21 13:42:58 2009
@@ -1343,11 +1343,27 @@
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 @@
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)) {
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=79658&r1=79657&r2=79658&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Aug 21 13:42:58 2009
@@ -485,10 +485,25 @@
// 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 @@
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 @@
&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;
Added: cfe/trunk/test/SemaTemplate/constructor-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constructor-template.cpp?rev=79658&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/constructor-template.cpp (added)
+++ cfe/trunk/test/SemaTemplate/constructor-template.cpp Fri Aug 21 13:42:58 2009
@@ -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}}
+}
Modified: cfe/trunk/test/SemaTemplate/member-function-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/member-function-template.cpp?rev=79658&r1=79657&r2=79658&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/member-function-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/member-function-template.cpp Fri Aug 21 13:42:58 2009
@@ -27,4 +27,4 @@
int &ir1 = x.f1(i);
int &ir2 = x.f1(f, i);
int &ir3 = x.f1(i, i);
-}
\ No newline at end of file
+}
More information about the cfe-commits
mailing list