sepavloff updated this revision to Diff 139758. sepavloff added a comment. Rebased patch
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 @@ -3791,7 +3791,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(); @@ -3922,7 +3924,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 @@ -52,17 +52,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(); @@ -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 && @@ -154,19 +154,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 = 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 @@ -3309,8 +3309,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()) @@ -3334,19 +3367,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 @@ -7068,7 +7068,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 @@ -2390,7 +2390,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 cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits