]> granicus.if.org Git - clang/commitdiff
[modules] Fix adding a templated friend functions to a namespace from another module.
authorVassil Vassilev <v.g.vassilev@gmail.com>
Wed, 16 Mar 2016 11:17:04 +0000 (11:17 +0000)
committerVassil Vassilev <v.g.vassilev@gmail.com>
Wed, 16 Mar 2016 11:17:04 +0000 (11:17 +0000)
When clang adds argument dependent lookup candidates, it can perform template
instantiation. For example, it can instantiate a templated friend function and
register it in the enclosing namespace's lookup table.

Fixes https://llvm.org/bugs/show_bug.cgi?id=24954

Reviewed by Richard Smith.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@263634 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Serialization/ASTWriter.cpp
test/Modules/Inputs/PR24954/A.h [new file with mode: 0644]
test/Modules/Inputs/PR24954/B.h [new file with mode: 0644]
test/Modules/Inputs/PR24954/module.modulemap [new file with mode: 0644]
test/Modules/pr24954.cpp [new file with mode: 0644]

index ee475d3cc520fb4e792baaeb0edb926be75d1df7..3e04bc5ad7d4012311df093a0e39cd4a82392d9a 100644 (file)
@@ -5751,8 +5751,16 @@ static bool isImportedDeclContext(ASTReader *Chain, const Decl *D) {
 }
 
 void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
-  // TU and namespaces are handled elsewhere.
-  if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC))
+  // TU is handled elsewhere.
+  if (isa<TranslationUnitDecl>(DC))
+    return;
+
+  // Namespaces are handled elsewhere, except for template instantiations of
+  // FunctionTemplateDecls in namespaces. We are interested in cases where the
+  // local instantiations are added to an imported context. Only happens when
+  // adding ADL lookup candidates, for example templated friends.
+  if (isa<NamespaceDecl>(DC) && D->getFriendObjectKind() == Decl::FOK_None &&
+      !isa<FunctionTemplateDecl>(D))
     return;
 
   // We're only interested in cases where a local declaration is added to an
diff --git a/test/Modules/Inputs/PR24954/A.h b/test/Modules/Inputs/PR24954/A.h
new file mode 100644 (file)
index 0000000..5e5d5bf
--- /dev/null
@@ -0,0 +1,10 @@
+#include "B.h"
+
+template <class T>
+class Expr {
+public:
+   void print(B::basic_ostream<char>& os) {
+     os << B::setw(42);
+     os << B::endl;
+  }
+};
diff --git a/test/Modules/Inputs/PR24954/B.h b/test/Modules/Inputs/PR24954/B.h
new file mode 100644 (file)
index 0000000..a8ddc71
--- /dev/null
@@ -0,0 +1,30 @@
+namespace B {
+
+  template <class _CharT>
+  struct basic_ostream {
+    basic_ostream& operator<<(basic_ostream& (*__pf)());
+  };
+
+
+  template <class _CharT> basic_ostream<_CharT>&
+  endl();
+
+  struct S1 {
+    template <class _CharT> friend void
+    operator<<(basic_ostream<_CharT>& __os, const S1& __x);
+  };
+
+  S1 setw(int __n);
+
+  template <class _CharT> class S2;
+
+  template <class _CharT> void
+  operator<<(basic_ostream<_CharT>& __os, const S2<_CharT>& __x);
+
+  template <class _CharT>
+  struct S2 {
+    template <class _Cp> friend void
+    operator<<(basic_ostream<_Cp>& __os, const S2<_Cp>& __x);
+  };
+
+}
diff --git a/test/Modules/Inputs/PR24954/module.modulemap b/test/Modules/Inputs/PR24954/module.modulemap
new file mode 100644 (file)
index 0000000..4937418
--- /dev/null
@@ -0,0 +1,9 @@
+module A {
+  header "A.h"
+  export *
+}
+
+module B {
+  header "B.h"
+  export *
+}
diff --git a/test/Modules/pr24954.cpp b/test/Modules/pr24954.cpp
new file mode 100644 (file)
index 0000000..407ee06
--- /dev/null
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I%S/Inputs/PR24954 -verify %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I%S/Inputs/PR24954 -verify %s
+
+#include "A.h"
+
+// expected-no-diagnostics