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(DC)); } 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/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: 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(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(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(getLexicalDeclContext())) + if (HostForFriend) + *HostForFriend = DC; return getDefinitionOrSelf(MFD); + } if (FunctionTemplateDecl *TD = getDescribedFunctionTemplate()) { if (TD->getFriendObjectKind() != FOK_None) { 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(D); + + auto Ctx = dyn_cast(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(Ctx)) { + if (auto Spec = dyn_cast(Ctx)) { // We're done when we hit an explicit specialization. if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa(Spec)) @@ -126,7 +126,7 @@ break; } // Add template arguments from a function template specialization. - else if (FunctionDecl *Function = dyn_cast(Ctx)) { + else if (auto Function = dyn_cast(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(HostForFriend); + RelativeToPrimary = false; + continue; + } } - } else if (CXXRecordDecl *Rec = dyn_cast(Ctx)) { + } else if (auto *Rec = dyn_cast(Ctx)) { if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { QualType T = ClassTemplate->getInjectedClassNameSpecialization(); const TemplateSpecializationType *TST = 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: 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 struct C01 { + template friend void func_01(C01 &, T1); + template friend void func_01a(C01 &, T2); +}; + +C01 c01; + +void f_01() { + func_01(c01, 0.0); + func_01a(c01, 0.0); +} + +template void func_01(C01 &, T1) {} +template void func_01a(C01 &, T2) {} + +// void func_01(C01&, double) +// CHECK: define linkonce_odr void @_Z7func_01IdEvR3C01IiET_ +// +// void func_01a(C01&, double) +// CHECK: define linkonce_odr void @_Z8func_01aIidEvR3C01IT_ET0_ + + +template struct C02 { + template friend void func_02(const C02 &, T1) { T var; } + template friend void func_02a(const C02 &, T2) { T var; } + template friend constexpr unsigned func_02b(const C02 &, const T1 x) { return sizeof(T1); } +}; + +const C02 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(C02 const&, double) +// CHECK: define linkonce_odr void @_Z7func_02IdEvRK3C02IiET_ +// +// void func_02a(C02 const&, double) +// CHECK: define linkonce_odr void @_Z8func_02aIidEvRK3C02IT_ET0_ + + +template struct C03 { + template friend void func_03(C03 &, T1); + template friend void func_03a(C03 &, T2); +}; + +C03 c03; + +void f_03() { + func_03(c03, 0.0); + func_03a(c03, 0.0); +} + +template struct C03A { + template friend void func_03(C03 &, T1) { } +}; +template struct C03B { + template friend void func_03a(C03 &, T2) { T var; } +}; + +C03A c03a; +C03B c03b; + +// void func_03(C03&, double) +// CHECK: define linkonce_odr void @_Z7func_03IdEvR3C03IiET_ +// +// void func_03a(C03&, double) +// CHECK: define linkonce_odr void @_Z8func_03aIidEvR3C03IT_ET0_ + + +// File level declaration, friend pattern. + + +template void func_10(T1 *x); +template void func_10a(T1 *x, T2 *y); +template constexpr unsigned func_10b(const T1 x); +template constexpr unsigned func_10c(const T1 x); + +template +struct C10 { + template friend void func_10(T1 *x) { T var; } + template friend void func_10a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_10b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_10c(const T1 x) { return sizeof(T); } +}; + +C10 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*) +// CHECK: define linkonce_odr void @_Z7func_10IiEvPT_ +// +// void func_10a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_10aIiPiEvPT_PT0_ + + +template +struct C11 { + template friend void func_11(T1 *x) { T var; } + template friend void func_11a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_11b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_11c(const T1 x) { return sizeof(T); } +}; + +C11 v11; + +template void func_11(T *x); +template void func_11a(T1 *x, T2 *y); +template constexpr unsigned func_11b(const T1 x); +template 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*) +// CHECK: define linkonce_odr void @_Z7func_11IiEvPT_ +// +// void func_11a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_11aIiPiEvPT_PT0_ + + +template +struct C12 { + template friend void func_12(T1 *x) { T var; } + template friend void func_12a(T1 *x, T2 *y) { T var; } +}; + +template void func_12(T *x); +template void func_12a(T1 *x, T2 *y); + +void use_12(int *x) { + func_12(x); + func_12a(x, &x); +} + +C12 v12; + +// void func_12(int*) +// CHECK: define linkonce_odr void @_Z7func_12IiEvPT_ +// +// void func_12a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_12aIiPiEvPT_PT0_ + + +template void func_13(T1 *x); +template void func_13a(T1 *x, T2 *y); + +template +struct C13 { + template friend void func_13(T1 *x) { T var; } + template friend void func_13a(T1 *x, T2 *y) { T var; } +}; + +void use_13(int *x) { + func_13(x); + func_13a(x, &x); +} + +C13 v13; + +// void func_13(int*) +// CHECK: define linkonce_odr void @_Z7func_13IiEvPT_ +// +// void func_13a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_13aIiPiEvPT_PT0_ + + +template void func_14(T1 *x); +template void func_14a(T1 *x, T2 *y); + +void use_14(int *x) { + func_14(x); + func_14a(x, &x); +} + +template +struct C14 { + template friend void func_14(T1 *x) { T var; } + template friend void func_14a(T1 *x, T2 *y) { T var; } +}; + +C14 v14; + +// void func_14(int*) +// CHECK: define linkonce_odr void @_Z7func_14IiEvPT_ +// +// void func_14a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_14aIiPiEvPT_PT0_ + + +template +struct C15 { + template friend void func_15(T1 *x) { T var; } + template friend void func_15a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_15b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_15c(const T1 x) { return sizeof(T); } +}; + +template void func_15(T1 *x); +template void func_15a(T1 *x, T2 *y); +template constexpr unsigned func_15b(const T1 x); +template constexpr unsigned func_15c(const T1 x); + +C15 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*) +// CHECK: define linkonce_odr void @_Z7func_15IiEvPT_ +// +// void func_15a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_15aIiPiEvPT_PT0_ + + +// File level declaration, friend pattern and declaration. + + +template void func_16(T1 *x); +template void func_16a(T1 *x, T2 *y); +template constexpr unsigned func_16b(const T1 x); +template constexpr unsigned func_16c(const T1 x); + +template +struct C16a { + template friend void func_16(T1 *x) { T var; } + template friend void func_16a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_16b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_16c(const T1 x) { return sizeof(T); } +}; + +C16a v16a; + +template +struct C16b { + template friend void func_16(T1 *x); + template friend void func_16a(T1 *x, T2 *y); + template friend constexpr unsigned func_16b(const T1 x); + template friend constexpr unsigned func_16c(const T1 x); +}; + +C16b 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*) +// CHECK: define linkonce_odr void @_Z7func_16IiEvPT_ +// +// void func_16a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_16aIiPiEvPT_PT0_ + + +template void func_17(T1 *x); +template void func_17a(T1 *x, T2 *y); + +template +struct C17b { + template friend void func_17(T1 *x); + template friend void func_17a(T1 *x, T2 *y); +}; + +C17b v17b; + +void use_17(int *x) { + func_17(x); + func_17a(x, &x); +} + +template +struct C17a { + template friend void func_17(T1 *x) { T var; } + template friend void func_17a(T1 *x, T2 *y) { T var; } +}; + +C17a v17a; + +// void func_17(int*) +// CHECK: define linkonce_odr void @_Z7func_17IiEvPT_ +// +// void func_17a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_17aIiPiEvPT_PT0_ + + +template void func_18(T1 *x); +template void func_18a(T1 *x, T2 *y); +template constexpr unsigned func_18b(const T1 x); +template constexpr unsigned func_18c(const T1 x); + +template +struct C18b { + template friend void func_18(T1 *x); + template friend void func_18a(T1 *x, T2 *y); + template friend constexpr unsigned func_18b(const T1 x); + template friend constexpr unsigned func_18c(const T1 x); + struct Inner { + template friend void func_18(T1 *x) { T var; } + template friend void func_18a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_18b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_18c(const T1 x) { return sizeof(T); } + }; +}; + +C18b::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*) +// CHECK: define linkonce_odr void @_Z7func_18IiEvPT_ +// +// void func_18a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_18aIiPiEvPT_PT0_ + + +template void func_19(T1 *x); +template void func_19a(T1 *x, T2 *y); +template constexpr unsigned func_19b(const T1 x); +template constexpr unsigned func_19c(const T1 x); + +template +struct C19b { + struct Inner { + template friend void func_19(T1 *x) { T var; } + template friend void func_19a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_19b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_19c(const T1 x) { return sizeof(T); } + }; + template friend void func_19(T1 *x); + template friend void func_19a(T1 *x, T2 *y); + template friend constexpr unsigned func_19b(const T1 x); + template friend constexpr unsigned func_19c(const T1 x); +}; + +C19b::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*) +// CHECK: define linkonce_odr void @_Z7func_19IiEvPT_ +// +// void func_19a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_19aIiPiEvPT_PT0_ + + +template void func_20(T1 *x); +template void func_20a(T1 *x, T2 *y); +template constexpr unsigned func_20b(const T1 x); +template constexpr unsigned func_20c(const T1 x); + +template +struct C20b { + struct Inner { + template friend void func_20(T1 *x); + template friend void func_20a(T1 *x, T2 *y); + template friend constexpr unsigned func_20b(const T1 x); + template friend constexpr unsigned func_20c(const T1 x); + }; + template friend void func_20(T1 *x) { T var; } + template friend void func_20a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_20b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_20c(const T1 x) { return sizeof(T); } +}; + +C20b::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*) +// CHECK: define linkonce_odr void @_Z7func_20IiEvPT_ +// +// void func_20a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_20aIiPiEvPT_PT0_ + + +template void func_21(T1 *x); +template void func_21a(T1 *x, T2 *y); +template constexpr unsigned func_21b(const T1 x); +template constexpr unsigned func_21c(const T1 x); + +template +struct C21b { + template friend void func_21(T1 *x) { T var; } + template friend void func_21a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_21b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_21c(const T1 x) { return sizeof(T); } + struct Inner { + template friend void func_21(T1 *x); + template friend void func_21a(T1 *x, T2 *y); + template friend constexpr unsigned func_21b(const T1 x); + template friend constexpr unsigned func_21c(const T1 x); + }; +}; + +C21b 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*) +// CHECK: define linkonce_odr void @_Z7func_21IiEvPT_ +// +// void func_21a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_21aIiPiEvPT_PT0_ + + +template void func_22(T1 *x); +template void func_22a(T1 *x, T2 *y); +template constexpr unsigned func_22b(const T1 x); +template constexpr unsigned func_22c(const T1 x); +template constexpr unsigned func_22d(const T1 x); + +template +struct C22b { + template friend void func_22(T1 *x); + template friend void func_22a(T1 *x, T2 *y); + template friend constexpr unsigned func_22b(const T1 x); + template friend constexpr unsigned func_22c(const T1 x); + template friend constexpr unsigned func_22d(const T1 x); + template + struct Inner { + template friend void func_22(T1 *x) { T var; } + template friend void func_22a(T1 *x, T2 *y) { T var; } + template friend constexpr unsigned func_22b(const T1 x) { return sizeof(T1); } + template friend constexpr unsigned func_22c(const T1 x) { return sizeof(T); } + template friend constexpr unsigned func_22d(const T1 x) { return sizeof(TT); } + }; +}; + +C22b::Inner 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*) +// CHECK: define linkonce_odr void @_Z7func_22IiEvPT_ +// +// void func_22a(int*, int**) +// CHECK: define linkonce_odr void @_Z8func_22aIiPiEvPT_PT0_ + + +namespace pr26512 { +struct A { + template class B { + template + friend void advance(B &, + distance_type); + }; + template + friend void advance(B &, distance_type) { + distance_type a; + } +}; +void main() { + A::B b; + advance(b, 0); +} +} + +// void pr26512::advance(pr26512::A::B&, int) +// CHECK: define linkonce_odr void @_ZN7pr265127advanceIiLb0EiEEvRNS_1A1BIT_XT0_EEET1_ + + +namespace pr19095 { +template void f(T); + +template class C { + template friend void f(T) { + C c; + c.i = 3; + } + +public: + void g() { + f(3.0); + } + int i; +}; + +void main () { + f(7); + C c; + c.g(); +} +} + +// void pr19095::f(double) +// CHECK: define linkonce_odr void @_ZN7pr190951fIdEEvT_