sepavloff updated this revision to Diff 160290.
sepavloff added a comment.

Rebased the patch, it is still actual.


Repository:
  rC Clang

https://reviews.llvm.org/D21767

Files:
  include/clang/AST/ASTLambda.h
  include/clang/AST/Decl.h
  include/clang/Sema/Sema.h
  lib/AST/Decl.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaTemplate/instantiate-friend-function.cpp

Index: test/SemaTemplate/instantiate-friend-function.cpp
===================================================================
--- test/SemaTemplate/instantiate-friend-function.cpp
+++ test/SemaTemplate/instantiate-friend-function.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -S -triple %itanium_abi_triple -std=c++11 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -S -triple %itanium_abi_triple -std=c++11 -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s
 // expected-no-diagnostics
 
 namespace PR10856 {
@@ -47,3 +47,572 @@
 
 // bool PR10856_Root::g<PR10856_Root::MyClass<int>, void>(PR10856_Root::MyClass<int>)
 // CHECK: call {{.*}} @_ZN12PR10856_Root1gINS_7MyClassIiEEvEEbT_
+
+// Instantiate friend function, pattern is at file level.
+
+
+template<typename T> struct C01 {
+  template<typename T1> friend void func_01(C01<T> &, T1);
+  template<typename T1, typename T2> friend void func_01a(C01<T1> &, T2);
+};
+
+C01<int> c01;
+
+void f_01() {
+  func_01(c01, 0.0);
+  func_01a(c01, 0.0);
+}
+
+template<typename T1> void func_01(C01<int> &, T1) {}
+template<typename T1, typename T2> void func_01a(C01<T1> &, T2) {}
+
+// void func_01<double>(C01<int>&, double)
+// CHECK: define linkonce_odr void @_Z7func_01IdEvR3C01IiET_
+//
+// void func_01a<int, double>(C01<int>&, double)
+// CHECK: define linkonce_odr void @_Z8func_01aIidEvR3C01IT_ET0_
+
+
+template<typename T> struct C02 {
+  template<typename T1> friend void func_02(const C02<T> &, T1) { T var; }
+  template<typename T1, typename T2> friend void func_02a(const C02<T1> &, T2) { T var; }
+  template<typename T1> friend constexpr unsigned func_02b(const C02<T> &, const T1 x) { return sizeof(T1); }
+};
+
+const C02<int> c02;
+
+void f_02() {
+  func_02(c02, 0.0);
+  func_02a(c02, 0.0);
+  static_assert(func_02b(c02, short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_02b(c02, 122L) == sizeof(long), "Invalid calculation");
+}
+
+// void func_02<double>(C02<int> const&, double)
+// CHECK: define linkonce_odr void @_Z7func_02IdEvRK3C02IiET_
+//
+// void func_02a<int, double>(C02<int> const&, double)
+// CHECK: define linkonce_odr void @_Z8func_02aIidEvRK3C02IT_ET0_
+
+
+template<typename T> struct C03 {
+  template<typename T1> friend void func_03(C03<T> &, T1);
+  template<typename T1, typename T2> friend void func_03a(C03<T1> &, T2);
+};
+
+C03<int> c03;
+
+void f_03() {
+  func_03(c03, 0.0);
+  func_03a(c03, 0.0);
+}
+
+template<typename T> struct C03A {
+  template<typename T1> friend void func_03(C03<T> &, T1) { }
+};
+template<typename T> struct C03B {
+  template<typename T1, typename T2> friend void func_03a(C03<T1> &, T2) { T var; }
+};
+
+C03A<int> c03a;
+C03B<int> c03b;
+
+// void func_03<double>(C03<int>&, double)
+// CHECK: define linkonce_odr void @_Z7func_03IdEvR3C03IiET_
+//
+// void func_03a<int, double>(C03<int>&, double)
+// CHECK: define linkonce_odr void @_Z8func_03aIidEvR3C03IT_ET0_
+
+
+// File level declaration, friend pattern.
+
+
+template<typename T1> void func_10(T1 *x);
+template<typename T1, typename T2> void func_10a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_10b(const T1 x);
+template<typename T1> constexpr unsigned func_10c(const T1 x);
+
+template<typename T>
+struct C10 {
+  template<typename T1> friend void func_10(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_10a(T1 *x, T2 *y) { T var; }
+  template<typename T1> friend constexpr unsigned func_10b(const T1 x) { return sizeof(T1); }
+  template<typename T1> friend constexpr unsigned func_10c(const T1 x) { return sizeof(T); }
+};
+
+C10<int> v10;
+
+void use_10(int *x) {
+  func_10(x);
+  func_10a(x, &x);
+  static_assert(func_10b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_10b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_10c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_10c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_10<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_10IiEvPT_
+//
+// void func_10a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_10aIiPiEvPT_PT0_
+
+
+template<typename T>
+struct C11 {
+  template<typename T1> friend void func_11(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_11a(T1 *x, T2 *y) { T var; }
+  template<typename T1> friend constexpr unsigned func_11b(const T1 x) { return sizeof(T1); }
+  template<typename T1> friend constexpr unsigned func_11c(const T1 x) { return sizeof(T); }
+};
+
+C11<int> v11;
+
+template<typename T> void func_11(T *x);
+template<typename T1, typename T2> void func_11a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_11b(const T1 x);
+template<typename T1> constexpr unsigned func_11c(const T1 x);
+
+void use_11(int *x) {
+  func_11(x);
+  func_11a(x, &x);
+  static_assert(func_11b(short(123)) == sizeof(short), "Invalid calculation");
+  static_assert(func_11b(123L) == sizeof(long), "Invalid calculation");
+  static_assert(func_11c(short(123)) == sizeof(int), "Invalid calculation");
+  static_assert(func_11c(123L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_11<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_11IiEvPT_
+//
+// void func_11a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_11aIiPiEvPT_PT0_
+
+
+template<typename T>
+struct C12 {
+  template<typename T1> friend void func_12(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_12a(T1 *x, T2 *y) { T var; }
+};
+
+template<typename T> void func_12(T *x);
+template<typename T1, typename T2> void func_12a(T1 *x, T2 *y);
+
+void use_12(int *x) {
+  func_12(x);
+  func_12a(x, &x);
+}
+
+C12<int> v12;
+
+// void func_12<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_12IiEvPT_
+//
+// void func_12a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_12aIiPiEvPT_PT0_
+
+
+template<typename T1> void func_13(T1 *x);
+template<typename T1, typename T2> void func_13a(T1 *x, T2 *y);
+
+template<typename T>
+struct C13 {
+  template<typename T1> friend void func_13(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_13a(T1 *x, T2 *y) { T var; }
+};
+
+void use_13(int *x) {
+  func_13(x);
+  func_13a(x, &x);
+}
+
+C13<int> v13;
+
+// void func_13<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_13IiEvPT_
+//
+// void func_13a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_13aIiPiEvPT_PT0_
+
+
+template<typename T1> void func_14(T1 *x);
+template<typename T1, typename T2> void func_14a(T1 *x, T2 *y);
+
+void use_14(int *x) {
+  func_14(x);
+  func_14a(x, &x);
+}
+
+template<typename T>
+struct C14 {
+  template<typename T1> friend void func_14(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_14a(T1 *x, T2 *y) { T var; }
+};
+
+C14<int> v14;
+
+// void func_14<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_14IiEvPT_
+//
+// void func_14a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_14aIiPiEvPT_PT0_
+
+
+template<typename T>
+struct C15 {
+  template<typename T1> friend void func_15(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_15a(T1 *x, T2 *y) { T var; }
+  template<typename T1> friend constexpr unsigned func_15b(const T1 x) { return sizeof(T1); }
+  template<typename T1> friend constexpr unsigned func_15c(const T1 x) { return sizeof(T); }
+};
+
+template<typename T1> void func_15(T1 *x);
+template<typename T1, typename T2> void func_15a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_15b(const T1 x);
+template<typename T1> constexpr unsigned func_15c(const T1 x);
+
+C15<int> v15;
+
+void use_15(int *x) {
+  func_15(x);
+  func_15a(x, &x);
+  static_assert(func_15b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_15b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_15c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_15c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_15<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_15IiEvPT_
+//
+// void func_15a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_15aIiPiEvPT_PT0_
+
+
+// File level declaration, friend pattern and declaration.
+
+
+template<typename T1> void func_16(T1 *x);
+template<typename T1, typename T2> void func_16a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_16b(const T1 x);
+template<typename T1> constexpr unsigned func_16c(const T1 x);
+
+template<typename T>
+struct C16a {
+  template<typename T1> friend void func_16(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_16a(T1 *x, T2 *y) { T var; }
+  template<typename T1> friend constexpr unsigned func_16b(const T1 x) { return sizeof(T1); }
+  template<typename T1> friend constexpr unsigned func_16c(const T1 x) { return sizeof(T); }
+};
+
+C16a<int> v16a;
+
+template<typename T>
+struct C16b {
+  template<typename T1> friend void func_16(T1 *x);
+  template<typename T1, typename T2> friend void func_16a(T1 *x, T2 *y);
+  template<typename T1> friend constexpr unsigned func_16b(const T1 x);
+  template<typename T1> friend constexpr unsigned func_16c(const T1 x);
+};
+
+C16b<int> v16b;
+
+void use_16(int *x) {
+  func_16(x);
+  func_16a(x, &x);
+  static_assert(func_16b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_16b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_16c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_16c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_16<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_16IiEvPT_
+//
+// void func_16a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_16aIiPiEvPT_PT0_
+
+
+template<typename T1> void func_17(T1 *x);
+template<typename T1, typename T2> void func_17a(T1 *x, T2 *y);
+
+template<typename T>
+struct C17b {
+  template<typename T1> friend void func_17(T1 *x);
+  template<typename T1, typename T2> friend void func_17a(T1 *x, T2 *y);
+};
+
+C17b<int> v17b;
+
+void use_17(int *x) {
+  func_17(x);
+  func_17a(x, &x);
+}
+
+template<typename T>
+struct C17a {
+  template<typename T1> friend void func_17(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_17a(T1 *x, T2 *y) { T var; }
+};
+
+C17a<int> v17a;
+
+// void func_17<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_17IiEvPT_
+//
+// void func_17a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_17aIiPiEvPT_PT0_
+
+
+template<typename T1> void func_18(T1 *x);
+template<typename T1, typename T2> void func_18a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_18b(const T1 x);
+template<typename T1> constexpr unsigned func_18c(const T1 x);
+
+template<typename T>
+struct C18b {
+  template<typename T1> friend void func_18(T1 *x);
+  template<typename T1, typename T2> friend void func_18a(T1 *x, T2 *y);
+  template<typename T1> friend constexpr unsigned func_18b(const T1 x);
+  template<typename T1> friend constexpr unsigned func_18c(const T1 x);
+  struct Inner {
+    template<typename T1> friend void func_18(T1 *x) { T var; }
+    template<typename T1, typename T2> friend void func_18a(T1 *x, T2 *y) { T var; }
+    template<typename T1> friend constexpr unsigned func_18b(const T1 x) { return sizeof(T1); }
+    template<typename T1> friend constexpr unsigned func_18c(const T1 x) { return sizeof(T); }
+  };
+};
+
+C18b<int>::Inner v18b;
+
+void use_18(int *x) {
+  func_18(x);
+  func_18a(x, &x);
+  static_assert(func_18b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_18b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_18c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_18c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_18<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_18IiEvPT_
+//
+// void func_18a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_18aIiPiEvPT_PT0_
+
+
+template<typename T1> void func_19(T1 *x);
+template<typename T1, typename T2> void func_19a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_19b(const T1 x);
+template<typename T1> constexpr unsigned func_19c(const T1 x);
+
+template<typename T>
+struct C19b {
+  struct Inner {
+    template<typename T1> friend void func_19(T1 *x) { T var; }
+    template<typename T1, typename T2> friend void func_19a(T1 *x, T2 *y) { T var; }
+    template<typename T1> friend constexpr unsigned func_19b(const T1 x) { return sizeof(T1); }
+    template<typename T1> friend constexpr unsigned func_19c(const T1 x) { return sizeof(T); }
+  };
+  template<typename T1> friend void func_19(T1 *x);
+  template<typename T1, typename T2> friend void func_19a(T1 *x, T2 *y);
+  template<typename T1> friend constexpr unsigned func_19b(const T1 x);
+  template<typename T1> friend constexpr unsigned func_19c(const T1 x);
+};
+
+C19b<int>::Inner v19b;
+
+void use_19(int *x) {
+  func_19(x);
+  func_19a(x, &x);
+  static_assert(func_19b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_19b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_19c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_19c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_19<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_19IiEvPT_
+//
+// void func_19a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_19aIiPiEvPT_PT0_
+
+
+template<typename T1> void func_20(T1 *x);
+template<typename T1, typename T2> void func_20a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_20b(const T1 x);
+template<typename T1> constexpr unsigned func_20c(const T1 x);
+
+template<typename T>
+struct C20b {
+  struct Inner {
+    template<typename T1> friend void func_20(T1 *x);
+    template<typename T1, typename T2> friend void func_20a(T1 *x, T2 *y);
+    template<typename T1> friend constexpr unsigned func_20b(const T1 x);
+    template<typename T1> friend constexpr unsigned func_20c(const T1 x);
+  };
+  template<typename T1> friend void func_20(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_20a(T1 *x, T2 *y) { T var; }
+  template<typename T1> friend constexpr unsigned func_20b(const T1 x) { return sizeof(T1); }
+  template<typename T1> friend constexpr unsigned func_20c(const T1 x) { return sizeof(T); }
+};
+
+C20b<int>::Inner v20b;
+
+void use_20(int *x) {
+  func_20(x);
+  func_20a(x, &x);
+  static_assert(func_20b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_20b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_20c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_20c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_20<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_20IiEvPT_
+//
+// void func_20a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_20aIiPiEvPT_PT0_
+
+
+template<typename T1> void func_21(T1 *x);
+template<typename T1, typename T2> void func_21a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_21b(const T1 x);
+template<typename T1> constexpr unsigned func_21c(const T1 x);
+
+template<typename T>
+struct C21b {
+  template<typename T1> friend void func_21(T1 *x) { T var; }
+  template<typename T1, typename T2> friend void func_21a(T1 *x, T2 *y) { T var; }
+  template<typename T1> friend constexpr unsigned func_21b(const T1 x) { return sizeof(T1); }
+  template<typename T1> friend constexpr unsigned func_21c(const T1 x) { return sizeof(T); }
+  struct Inner {
+    template<typename T1> friend void func_21(T1 *x);
+    template<typename T1, typename T2> friend void func_21a(T1 *x, T2 *y);
+    template<typename T1> friend constexpr unsigned func_21b(const T1 x);
+    template<typename T1> friend constexpr unsigned func_21c(const T1 x);
+  };
+};
+
+C21b<int> v21b;
+
+void use_21(int *x) {
+  func_21(x);
+  func_21a(x, &x);
+  static_assert(func_21b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_21b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_21c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_21c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_21<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_21IiEvPT_
+//
+// void func_21a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_21aIiPiEvPT_PT0_
+
+
+template<typename T1> void func_22(T1 *x);
+template<typename T1, typename T2> void func_22a(T1 *x, T2 *y);
+template<typename T1> constexpr unsigned func_22b(const T1 x);
+template<typename T1> constexpr unsigned func_22c(const T1 x);
+template<typename T1> constexpr unsigned func_22d(const T1 x);
+
+template<typename T>
+struct C22b {
+  template<typename T1> friend void func_22(T1 *x);
+  template<typename T1, typename T2> friend void func_22a(T1 *x, T2 *y);
+  template<typename T1> friend constexpr unsigned func_22b(const T1 x);
+  template<typename T1> friend constexpr unsigned func_22c(const T1 x);
+  template<typename T1> friend constexpr unsigned func_22d(const T1 x);
+  template<typename TT>
+  struct Inner {
+    template<typename T1> friend void func_22(T1 *x) { T var; }
+    template<typename T1, typename T2> friend void func_22a(T1 *x, T2 *y) { T var; }
+    template<typename T1> friend constexpr unsigned func_22b(const T1 x) { return sizeof(T1); }
+    template<typename T1> friend constexpr unsigned func_22c(const T1 x) { return sizeof(T); }
+    template<typename T1> friend constexpr unsigned func_22d(const T1 x) { return sizeof(TT); }
+  };
+};
+
+C22b<int>::Inner<char> v22b;
+
+void use_22(int *x) {
+  func_22(x);
+  func_22a(x, &x);
+  static_assert(func_22b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_22b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_22c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_22c(122L) == sizeof(int), "Invalid calculation");
+  static_assert(func_22d(short(122)) == sizeof(char), "Invalid calculation");
+  static_assert(func_22d(122L) == sizeof(char), "Invalid calculation");
+}
+
+// void func_22<int>(int*)
+// CHECK: define linkonce_odr void @_Z7func_22IiEvPT_
+//
+// void func_22a<int, int*>(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_22aIiPiEvPT_PT0_
+
+
+namespace pr26512 {
+struct A {
+  template <class, bool> class B {
+    template <class r_colony_allocator_type, bool r_is_const,
+              class distance_type>
+    friend void advance(B<r_colony_allocator_type, r_is_const> &,
+                        distance_type);
+  };
+  template <class r_colony_allocator_type, bool r_is_const, class distance_type>
+  friend void advance(B<r_colony_allocator_type, r_is_const> &, distance_type) {
+    distance_type a;
+  }
+};
+void main() {
+  A::B<int, false> b;
+  advance(b, 0);
+}
+}
+
+// void pr26512::advance<int, false, int>(pr26512::A::B<int, false>&, int)
+// CHECK: define linkonce_odr void @_ZN7pr265127advanceIiLb0EiEEvRNS_1A1BIT_XT0_EEET1_
+
+
+namespace pr19095 {
+template <class T> void f(T);
+
+template <class U> class C {
+  template <class T> friend void f(T) {
+     C<U> c;
+     c.i = 3;
+  }
+
+public:
+  void g() {
+    f(3.0);
+  }
+  int i;
+};
+
+void main () {
+  f(7);
+  C<double> c;
+  c.g();
+}
+}
+
+// void pr19095::f<double>(double)
+// CHECK: define linkonce_odr void @_ZN7pr190951fIdEEvT_
+
+
+namespace pr34343 {
+template <typename... e> struct f;
+template <typename> struct g {
+  template <typename... h>
+  friend bool operator==(const g<h...> &, const g<h...> &) noexcept(f<h...>::k);
+};
+template <typename... e>
+bool operator==(const g<e...> &, const g<e...> &) noexcept(f<e...>::k);
+void l(g<int>) {}
+}
+
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3777,7 +3777,9 @@
     return;
 
   // Find the function body that we'll be substituting.
-  const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern();
+  const CXXRecordDecl *HostOfFriend;
+  const FunctionDecl *PatternDecl =
+      Function->getTemplateInstantiationPattern(&HostOfFriend);
   assert(PatternDecl && "instantiating a non-template");
 
   const FunctionDecl *PatternDef = PatternDecl->getDefinition();
@@ -3908,7 +3910,8 @@
     SetDeclDefaulted(Function, PatternDecl->getLocation());
   else {
     MultiLevelTemplateArgumentList TemplateArgs =
-      getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl);
+      getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl,
+                                   HostOfFriend);
 
     // Substitute into the qualifier; we can get a substitution failure here
     // through evil use of alias templates.
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -55,7 +55,8 @@
 Sema::getTemplateInstantiationArgs(NamedDecl *D,
                                    const TemplateArgumentList *Innermost,
                                    bool RelativeToPrimary,
-                                   const FunctionDecl *Pattern) {
+                                   const FunctionDecl *Pattern,
+                                   const CXXRecordDecl *HostForFriend) {
   // Accumulate the set of template argument lists in this structure.
   MultiLevelTemplateArgumentList Result;
 
@@ -111,8 +112,7 @@
 
   while (!Ctx->isFileContext()) {
     // Add template arguments from a class template instantiation.
-    if (ClassTemplateSpecializationDecl *Spec
-          = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
+    if (auto Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
       // We're done when we hit an explicit specialization.
       if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
           !isa<ClassTemplatePartialSpecializationDecl>(Spec))
@@ -127,7 +127,7 @@
         break;
     }
     // Add template arguments from a function template specialization.
-    else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
+    else if (auto Function = dyn_cast<FunctionDecl>(Ctx)) {
       if (!RelativeToPrimary &&
           (Function->getTemplateSpecializationKind() ==
                                                   TSK_ExplicitSpecialization &&
@@ -155,18 +155,17 @@
         Result.addOuterTemplateArguments(FunTmpl->getInjectedTemplateArgs());
       }
 
-      // If this is a friend declaration and it declares an entity at
-      // namespace scope, take arguments from its lexical parent
-      // instead of its semantic parent, unless of course the pattern we're
-      // instantiating actually comes from the file's context!
-      if (Function->getFriendObjectKind() &&
-          Function->getDeclContext()->isFileContext() &&
-          (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
-        Ctx = Function->getLexicalDeclContext();
-        RelativeToPrimary = false;
-        continue;
+      // If instantiated function is at namespace scope, its pattern may be
+      // defined in friend declaration. In this case arguments are taken from
+      // the class containing the friend declaration.
+      if (Function->getDeclContext()->isFileContext()) {
+        if (HostForFriend) {
+          Ctx = const_cast<DeclContext*>(cast<DeclContext>(HostForFriend));
+          RelativeToPrimary = false;
+          continue;
+        }
       }
-    } else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
+    } else if (auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
       if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
         QualType T = ClassTemplate->getInjectedClassNameSpecialization();
         const TemplateSpecializationType *TST =
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3373,7 +3373,40 @@
   llvm_unreachable("All TSK values handled.");
 }
 
-FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
+static FunctionTemplateDecl *getPatternFor(FunctionTemplateDecl *FTD,
+                                           const CXXRecordDecl *&Host) {
+  Host = nullptr;
+  for (auto I : FTD->redecls()) {
+    auto D = cast<FunctionTemplateDecl>(I);
+    // If we have hit a point where the user provided a specialization of
+    // this template, we're done looking.
+    if (D->isMemberSpecialization())
+      return D;
+    if (D->isThisDeclarationADefinition())
+      return D;
+    if (FunctionTemplateDecl *Orig = D->getInstantiatedFromMemberTemplate()) {
+      if (Orig->getFriendObjectKind() != Decl::FOK_None) {
+        if (auto *RDC = dyn_cast<CXXRecordDecl>(D->getLexicalDeclContext()))
+          Host = RDC;
+        else
+          continue;
+      }
+      const CXXRecordDecl *OrigHost;
+      if (FunctionTemplateDecl *Def = getPatternFor(Orig, OrigHost)) {
+        if (OrigHost)
+          Host = OrigHost;
+        return Def;
+      }
+    }
+  }
+  return nullptr;
+}
+
+FunctionDecl *FunctionDecl::getTemplateInstantiationPattern(
+                                    const CXXRecordDecl **HostForFriend) const {
+  if (HostForFriend)
+    *HostForFriend = nullptr;
+
   // Handle class scope explicit specialization special case.
   if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
     if (auto *Spec = getClassScopeSpecializationPattern())
@@ -3397,19 +3430,22 @@
   }
 
   if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
-    while (Primary->getInstantiatedFromMemberTemplate()) {
-      // If we have hit a point where the user provided a specialization of
-      // this template, we're done looking.
-      if (Primary->isMemberSpecialization())
-        break;
-      Primary = Primary->getInstantiatedFromMemberTemplate();
+    const CXXRecordDecl *Host;
+    if (FunctionTemplateDecl *Def = getPatternFor(Primary, Host)) {
+      if (HostForFriend)
+        *HostForFriend = Host;
+      Primary = Def;
     }
-
     return getDefinitionOrSelf(Primary->getTemplatedDecl());
   }
 
-  if (auto *MFD = getInstantiatedFromMemberFunction())
+  if (auto *MFD = getInstantiatedFromMemberFunction()) {
+    if (MFD->getFriendObjectKind() != Decl::FOK_None)
+      if (auto *DC = dyn_cast<CXXRecordDecl>(getLexicalDeclContext()))
+        if (HostForFriend)
+          *HostForFriend = DC;
     return getDefinitionOrSelf(MFD);
+  }
 
   return nullptr;
 }
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -7124,7 +7124,8 @@
   getTemplateInstantiationArgs(NamedDecl *D,
                                const TemplateArgumentList *Innermost = nullptr,
                                bool RelativeToPrimary = false,
-                               const FunctionDecl *Pattern = nullptr);
+                               const FunctionDecl *Pattern = nullptr,
+                               const CXXRecordDecl *HostForFriend = nullptr);
 
   /// A context in which code is being synthesized (where a source location
   /// alone is not sufficient to identify the context). This covers template
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -2437,7 +2437,13 @@
   /// Retrieve the function declaration from which this function could
   /// be instantiated, if it is an instantiation (rather than a non-template
   /// or a specialization, for example).
-  FunctionDecl *getTemplateInstantiationPattern() const;
+  ///
+  /// \param[out] HostForFriend If it is not null, the pattern is found and is
+  /// defined in a friend declaration, this parameter is assigned pointer to the
+  /// class containing the friend declaration.
+  ///
+  FunctionDecl *getTemplateInstantiationPattern(
+                           const CXXRecordDecl **HostForFriend = nullptr) const;
 
   /// Retrieve the primary template that this function template
   /// specialization either specializes or was instantiated from.
Index: include/clang/AST/ASTLambda.h
===================================================================
--- include/clang/AST/ASTLambda.h
+++ include/clang/AST/ASTLambda.h
@@ -60,7 +60,7 @@
   return false;
 }
 
-inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) {
+inline bool isGenericLambdaCallOperatorSpecialization(const DeclContext *DC) {
   return isGenericLambdaCallOperatorSpecialization(
                                           dyn_cast<CXXMethodDecl>(DC));
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to