]> granicus.if.org Git - clang/commitdiff
Implement matching of function templates, so that one can declare overloaded function...
authorDouglas Gregor <dgregor@apple.com>
Wed, 24 Jun 2009 16:50:40 +0000 (16:50 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 24 Jun 2009 16:50:40 +0000 (16:50 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74079 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp [new file with mode: 0644]
test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp [new file with mode: 0644]

index 11cd5107fc63c947e10c1d7f95cadb4113469640..6217e6d57af343e051618b9f542e112db339caa7 100644 (file)
@@ -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<FunctionDecl>(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<FunctionNoProtoType>(NewQType.getTypePtr()))
       return false;
 
-    FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType.getTypePtr());
-    FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType.getTypePtr());
+    FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType);
+    FunctionProtoType* NewType = cast<FunctionProtoType>(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.
     //
index 63696a13d3e0b5dd9bc128b6cef7f3e81a1241dd..e4562872933f4145e1cd42b064924896412779e6 100644 (file)
@@ -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 (file)
index 0000000..b482955
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> void f0(T) { } // expected-note{{previous}}
+template<class U> void f0(U) { } // expected-error{{redefinition}}
+
+template<int I> void f0() { } // expected-note{{previous}}
+template<int> void f0() { } // expected-error{{redefinition}}
+
+typedef int INT;
+
+template<template<class T, T Value1, INT> class X> 
+  void f0() { } // expected-note{{previous}}
+template<template<typename T, T Value1, int> class> 
+  void f0() { } // expected-error{{redefinition}}
+
+template<typename T>
+struct MetaFun;
+
+template<typename T>
+  typename MetaFun<T*>::type f0(const T&) { } // expected-note{{previous}}
+template<class U>
+  typename MetaFun<U*>::type f0(const U&) { } // expected-error{{redefinition}}
+
+// FIXME: We need canonicalization of expressions for this to work
+// template<int> struct A { };
+// template<int I> void f0(A<I>) { } // Xpected-note{{previous}}
+// template<int J> void f0(A<J>) { } // 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 (file)
index 0000000..de1a883
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// All of these function templates are distinct.
+template<typename T> void f0(T) { }
+template<typename T, typename U> void f0(T) { }
+template<typename T, typename U> void f0(U) { }
+void f0();
+template<typename T> void f0(T*);
+void f0(int);
+template<int I> void f0();
+template<typename T> void f0();
+
+