From: Douglas Gregor Date: Wed, 24 Jun 2009 16:50:40 +0000 (+0000) Subject: Implement matching of function templates, so that one can declare overloaded function... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=34d1dc9f0ca8f5b0528a8cd29f1addfe096361b8;p=clang Implement matching of function templates, so that one can declare overloaded function templates. C++ [temp.over.link] paragraphs 4-8. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74079 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 11cd5107fc..6217e6d57a 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -301,6 +301,15 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, // This function overloads every function in the overload set. return true; } else if (FunctionDecl* Old = dyn_cast(OldD)) { + FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate(); + FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate(); + + // C++ [temp.fct]p2: + // A function template can be overloaded with other function templates + // and with normal (non-template) functions. + if ((OldTemplate == 0) != (NewTemplate == 0)) + return true; + // Is the function New an overload of the function Old? QualType OldQType = Context.getCanonicalType(Old->getType()); QualType NewQType = Context.getCanonicalType(New->getType()); @@ -315,8 +324,8 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, isa(NewQType.getTypePtr())) return false; - FunctionProtoType* OldType = cast(OldQType.getTypePtr()); - FunctionProtoType* NewType = cast(NewQType.getTypePtr()); + FunctionProtoType* OldType = cast(OldQType); + FunctionProtoType* NewType = cast(NewQType); // The signature of a function includes the types of its // parameters (C++ 1.3.10), which includes the presence or absence @@ -328,6 +337,22 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, NewType->arg_type_begin()))) return true; + // C++ [temp.over.link]p4: + // The signature of a function template consists of its function + // signature, its return type and its template parameter list. The names + // of the template parameters are significant only for establishing the + // relationship between the template parameters and the rest of the + // signature. + // + // We check the return type and template parameter lists for function + // templates first; the remaining checks follow. + if (NewTemplate && + (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), + OldTemplate->getTemplateParameters(), + false, false, SourceLocation()) || + OldType->getResultType() != NewType->getResultType())) + return true; + // If the function is a class member, its signature includes the // cv-qualifiers (if any) on the function itself. // diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 63696a13d3..e456287293 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1874,15 +1874,17 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, OldParmEnd = Old->end(), NewParm = New->begin(); OldParm != OldParmEnd; ++OldParm, ++NewParm) { if ((*OldParm)->getKind() != (*NewParm)->getKind()) { - unsigned NextDiag = diag::err_template_param_different_kind; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_param_different_kind; - } - Diag((*NewParm)->getLocation(), NextDiag) + if (Complain) { + unsigned NextDiag = diag::err_template_param_different_kind; + if (TemplateArgLoc.isValid()) { + Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_param_different_kind; + } + Diag((*NewParm)->getLocation(), NextDiag) << IsTemplateTemplateParm; - Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration) + Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration) << IsTemplateTemplateParm; + } return false; } diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp new file mode 100644 index 0000000000..b482955818 --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp @@ -0,0 +1,27 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template void f0(T) { } // expected-note{{previous}} +template void f0(U) { } // expected-error{{redefinition}} + +template void f0() { } // expected-note{{previous}} +template void f0() { } // expected-error{{redefinition}} + +typedef int INT; + +template class X> + void f0() { } // expected-note{{previous}} +template class> + void f0() { } // expected-error{{redefinition}} + +template +struct MetaFun; + +template + typename MetaFun::type f0(const T&) { } // expected-note{{previous}} +template + typename MetaFun::type f0(const U&) { } // expected-error{{redefinition}} + +// FIXME: We need canonicalization of expressions for this to work +// template struct A { }; +// template void f0(A) { } // Xpected-note{{previous}} +// template void f0(A) { } // Xpected-error{{redefinition}} \ No newline at end of file diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp new file mode 100644 index 0000000000..de1a883bcd --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp @@ -0,0 +1,13 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// All of these function templates are distinct. +template void f0(T) { } +template void f0(T) { } +template void f0(U) { } +void f0(); +template void f0(T*); +void f0(int); +template void f0(); +template void f0(); + +