Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -1760,6 +1760,7 @@ bool CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization); + bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); Decl *ActOnParamDeclarator(Scope *S, Declarator &D); Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -8664,6 +8664,32 @@ return NewFD; } +/// \brief Checks if the new declaration declared in dependent context must be +/// put in the same redeclaration chain as the specified declaration. +/// +/// \param D Declaration that is checked. +/// \param PrevDecl Previous declaration found with proper lookup method for the +/// same declaration name. +/// \returns True if D must be added to the redeclaration chain which PrevDecl +/// belongs to. +/// +bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) { + // Any declarations should be put into redeclaration chains except for + // friend declaration in a dependent context that names a function in + // namespace scope. + // + // This allows to compile code like: + // + // void func(); + // template class C1 { friend void func() { } }; + // template class C2 { friend void func() { } }; + // + // This code snippet is a valid code unless both templates are instantiated. + return !(D->getLexicalDeclContext()->isDependentContext() && + D->getDeclContext()->isFileContext() && + D->getFriendObjectKind() != Decl::FOK_None); +} + /// \brief Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration @@ -8847,11 +8873,14 @@ } } else { - // This needs to happen first so that 'inline' propagates. - NewFD->setPreviousDeclaration(cast(OldDecl)); - - if (isa(NewFD)) - NewFD->setAccess(OldDecl->getAccess()); + if (shouldLinkDependentDeclWithPrevious(NewFD, OldDecl)) { + // This needs to happen first so that 'inline' propagates. + NewFD->setPreviousDeclaration(cast(OldDecl)); + if (isa(NewFD)) + NewFD->setAccess(OldDecl->getAccess()); + } else { + Redeclaration = false; + } } } Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp @@ -13786,9 +13786,14 @@ // and shall be the only declaration of the function or function // template in the translation unit. if (functionDeclHasDefaultArgument(FD)) { - if (FunctionDecl *OldFD = FD->getPreviousDecl()) { + // We can't look at FD->getPreviousDecl() because it may not have been set + // if we're in a dependent context. If we get this far with a non-empty + // Previous set, we must have a valid previous declaration of this + // function. + if (!Previous.empty()) { Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_redeclared); - Diag(OldFD->getLocation(), diag::note_previous_declaration); + Diag(Previous.getRepresentativeDecl()->getLocation(), + diag::note_previous_declaration); } else if (!D.isFunctionDefinition()) Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_must_be_def); } Index: cfe/trunk/test/SemaCXX/PR25848.cpp =================================================================== --- cfe/trunk/test/SemaCXX/PR25848.cpp +++ cfe/trunk/test/SemaCXX/PR25848.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct A; + +inline int g(); // expected-warning{{inline function 'g' is not defined}} + +template +struct R { + friend int g() { + return M; + } +}; + +void m() { + g(); // expected-note{{used here}} +} Index: cfe/trunk/test/SemaCXX/friend2.cpp =================================================================== --- cfe/trunk/test/SemaCXX/friend2.cpp +++ cfe/trunk/test/SemaCXX/friend2.cpp @@ -0,0 +1,172 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 + +// If a friend function is defined in several non-template classes, +// it is an error. + +void func1(int); +struct C1a { + friend void func1(int) {} // expected-note{{previous definition is here}} +}; +struct C1b { + friend void func1(int) {} // expected-error{{redefinition of 'func1'}} +}; + + +// If a friend function is defined in both non-template and template +// classes it is an error only if the template is instantiated. + +void func2(int); +struct C2a { + friend void func2(int) {} +}; +template struct C2b { + friend void func2(int) {} +}; + +void func3(int); +struct C3a { + friend void func3(int) {} // expected-note{{previous definition is here}} +}; +template struct C3b { + friend void func3(int) {} // expected-error{{redefinition of 'func3'}} +}; +C3b c3; // expected-note{{in instantiation of template class 'C3b' requested here}} + + +// If a friend function is defined in several template classes it is an error +// only if several templates are instantiated. + +void func4(int); +template struct C4a { + friend void func4(int) {} +}; +template struct C4b { + friend void func4(int) {} +}; + + +void func5(int); +template struct C5a { + friend void func5(int) {} +}; +template struct C5b { + friend void func5(int) {} +}; +C5a c5a; + +void func6(int); +template struct C6a { + friend void func6(int) {} // expected-note{{previous definition is here}} +}; +template struct C6b { + friend void func6(int) {} // expected-error{{redefinition of 'func6'}} +}; +C6a c6a; +C6b c6b; // expected-note{{in instantiation of template class 'C6b' requested here}} + +void func7(int); +template struct C7 { + friend void func7(int) {} // expected-error{{redefinition of 'func7'}} + // expected-note@-1{{previous definition is here}} +}; +C7 c7a; +C7 c7b; // expected-note{{in instantiation of template class 'C7' requested here}} + + +// Even if clases are not instantiated and hence friend functions defined in them are not +// available, their declarations can be checked. + +void func8(int); // expected-note{{previous declaration is here}} +template struct C8a { + friend long func8(int); // expected-error{{functions that differ only in their return type cannot be overloaded}} +}; + +void func9(int); // expected-note{{previous declaration is here}} +template struct C9a { + friend int func9(int); // expected-error{{functions that differ only in their return type cannot be overloaded}} +}; + +void func10(int); // expected-note{{previous declaration is here}} +template struct C10a { + friend int func10(int); // expected-error{{functions that differ only in their return type cannot be overloaded}} +}; + +void func_11(); // expected-note{{previous declaration is here}} +template class C11 { + friend int func_11(); // expected-error{{functions that differ only in their return type cannot be overloaded}} +}; + +void func_12(int x); // expected-note{{previous declaration is here}} +template class C12 { + friend void func_12(int x = 0); // expected-error{{friend declaration specifying a default argument must be the only declaration}} +}; + + +namespace pr22307 { + +struct t { + friend int leak(t); +}; + +template +struct m { + friend int leak(t) { return sizeof(v); } // expected-error{{redefinition of 'leak'}} expected-note{{previous definition is here}} +}; + +template struct m; +template struct m; // expected-note{{in instantiation of template class 'pr22307::m' requested here}} + +int main() { + leak(t()); +} + +} + +namespace pr17923 { + +void f(unsigned long long); + +template struct X { + friend void f(unsigned long long) { + T t; + } +}; + +int main() { f(1234); } + +} + +namespace pr17923a { + +int get(); + +template< int value > +class set { + friend int get() + { return value; } // return 0; is OK +}; + +template class set< 5 >; + +int main() { + get(); +} + +} + +namespace pr8035 { + +void Function(); + +int main(int argc, char* argv[]) { + Function(); +} + +template +struct Test { + friend void Function() { } +}; + +template class Test; + +} Index: cfe/trunk/test/SemaCXX/function-redecl-2.cpp =================================================================== --- cfe/trunk/test/SemaCXX/function-redecl-2.cpp +++ cfe/trunk/test/SemaCXX/function-redecl-2.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s + +namespace redecl_in_templ { +template void redecl_in_templ() { + extern void func_1(); // expected-note {{previous declaration is here}} + extern int func_1(); // expected-error {{functions that differ only in their return type cannot be overloaded}} +} + +void g(); +constexpr void (*p)() = g; + +template struct X {}; +template<> struct X { typedef int type; }; + +template void f() { + extern void g(); + X<&g == p>::type n; +} +}