]> granicus.if.org Git - clang/commitdiff
Slightly improve cross-module merging for function templates.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 24 Jun 2013 04:45:28 +0000 (04:45 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 24 Jun 2013 04:45:28 +0000 (04:45 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184689 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Serialization/ASTReaderDecl.cpp
test/Modules/Inputs/cxx-templates-a.h [new file with mode: 0644]
test/Modules/Inputs/cxx-templates-b.h [new file with mode: 0644]
test/Modules/Inputs/module.map
test/Modules/cxx-templates.cpp [new file with mode: 0644]

index ffbff3882b2b5ade6d0d85a0e7dce7dc739c1e57..3d64fa51d9ed3ba7e4c7345c2a58f140726d4ff4 100644 (file)
@@ -1815,10 +1815,10 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
        (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class ||
         TagY->getTagKind() == TTK_Interface));
   }
-  
+
   // Functions with the same type and linkage match.
-  // FIXME: This needs to cope with function templates, merging of 
-  //prototyped/non-prototyped functions, etc.
+  // FIXME: This needs to cope with function template specializations,
+  // merging of prototyped/non-prototyped functions, etc.
   if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
     FunctionDecl *FuncY = cast<FunctionDecl>(Y);
     return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) &&
@@ -1831,16 +1831,21 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
     return (VarX->getLinkageInternal() == VarY->getLinkageInternal()) &&
       VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType());
   }
-  
+
   // Namespaces with the same name and inlinedness match.
   if (NamespaceDecl *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
     NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
     return NamespaceX->isInline() == NamespaceY->isInline();
   }
 
-  // Identical template names and kinds match.
-  if (isa<TemplateDecl>(X))
-    return true;
+  // Identical template names and kinds match if their template parameter lists
+  // and patterns match.
+  if (TemplateDecl *TemplateX = dyn_cast<TemplateDecl>(X)) {
+    TemplateDecl *TemplateY = dyn_cast<TemplateDecl>(Y);
+    // FIXME: Check template parameter lists.
+    return isSameEntity(TemplateX->getTemplatedDecl(),
+                        TemplateY->getTemplatedDecl());
+  }
 
   // FIXME: Many other cases to implement.
   return false;
diff --git a/test/Modules/Inputs/cxx-templates-a.h b/test/Modules/Inputs/cxx-templates-a.h
new file mode 100644 (file)
index 0000000..52bc3a2
--- /dev/null
@@ -0,0 +1,6 @@
+template<typename T> T f() { return T(); }
+template<typename T> T f(T);
+namespace N {
+  template<typename T> T f() { return T(); }
+  template<typename T> T f(T);
+}
diff --git a/test/Modules/Inputs/cxx-templates-b.h b/test/Modules/Inputs/cxx-templates-b.h
new file mode 100644 (file)
index 0000000..3cc940c
--- /dev/null
@@ -0,0 +1,6 @@
+template<typename T> T f();
+template<typename T> T f(T t) { return t; }
+namespace N {
+  template<typename T> T f();
+  template<typename T> T f(T t) { return t; }
+}
index 65c75fdc1c67d26810714b4214a53be83c6375c4..d2ed75830b82c161f1cae17f198c456c4d651ee6 100644 (file)
@@ -188,6 +188,14 @@ module cxx_linkage_cache {
   header "cxx-linkage-cache.h"
 }
 
+module cxx_templates_a {
+  header "cxx-templates-a.h"
+}
+
+module cxx_templates_b {
+  header "cxx-templates-b.h"
+}
+
 module config {
   header "config.h"
   config_macros [exhaustive] WANT_FOO, WANT_BAR
diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp
new file mode 100644 (file)
index 0000000..bc96772
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+
+@import cxx_templates_a;
+@import cxx_templates_b;
+
+void g() {
+  f(0);
+  f<double>(1.0);
+  f<int>();
+  f(); // expected-error {{no matching function}}
+  // expected-note@Inputs/cxx-templates-b.h:1 {{couldn't infer template argument}}
+  // expected-note@Inputs/cxx-templates-b.h:2 {{requires single argument}}
+
+  N::f(0);
+  N::f<double>(1.0);
+  N::f<int>();
+  N::f(); // expected-error {{no matching function}}
+  // expected-note@Inputs/cxx-templates-a.h:4 {{couldn't infer template argument}}
+  // expected-note@Inputs/cxx-templates-a.h:5 {{requires 1 argument, but 0 were provided}}
+}
+
+// FIXME: There should only be two 'f's here.
+// CHECK-GLOBAL:      DeclarationName 'f'
+// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-GLOBAL-NEXT: `-FunctionTemplate {{.*}} 'f'
+
+// FIXME: There should only be two 'f's here.
+// CHECK-NAMESPACE-N:      DeclarationName 'f'
+// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-NAMESPACE-N-NEXT: `-FunctionTemplate {{.*}} 'f'