sepavloff updated this revision to Diff 107817.
sepavloff added a comment.
Reworked patch
Used more general way to cope with calculation of instantiation
stack, which is suitable for cases represented in PR26512.
Added new tests.
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
===================================================================
--- /dev/null
+++ test/SemaTemplate/instantiate-friend-function.cpp
@@ -0,0 +1,560 @@
+// 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
+// expected-no-diagnostics
+
+
+// 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_
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3744,7 +3744,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();
@@ -3871,7 +3873,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
@@ -51,17 +51,18 @@
/// used to determine the proper set of template instantiation arguments for
/// friend function template specializations.
MultiLevelTemplateArgumentList
-Sema::getTemplateInstantiationArgs(NamedDecl *D,
+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;
if (Innermost)
Result.addOuterTemplateArguments(Innermost);
-
- DeclContext *Ctx = dyn_cast<DeclContext>(D);
+
+ auto Ctx = dyn_cast<DeclContext>(D);
if (!Ctx) {
Ctx = D->getDeclContext();
@@ -110,8 +111,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))
@@ -126,7 +126,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 &&
@@ -153,19 +153,18 @@
// Add the "injected" template arguments.
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 = 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
@@ -3249,8 +3249,41 @@
}
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())
@@ -3274,19 +3307,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);
+ }
if (FunctionTemplateDecl *TD = getDescribedFunctionTemplate()) {
if (TD->getFriendObjectKind() != FOK_None) {
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -6988,7 +6988,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
@@ -2270,7 +2270,13 @@
/// \brief 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;
/// \brief 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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits