Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1733,6 +1733,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: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8568,6 +8568,39 @@ 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) { + DeclContext *LexicalDC = D->getLexicalDeclContext(); + if (!LexicalDC->isDependentContext()) + return true; + DeclContext *SemanticDC = D->getDeclContext(); + if (SemanticDC->isDependentContext()) + return false; + // Get here only for out-of-line declarations: lexical context is dependent, + // semantic is not. + + if (!isa(D) && !isa(D)) + return true; + + // Case of friend methods. + if (SemanticDC->isRecord()) + return true; + + // A file level function may be defined inline in friend declarations. These + // definitions cannot be used until the containing template class is + // instantiated. So do not put such declaration into redeclaration chains + // while the template is processed. + return !LexicalDC->isRecord(); +} + /// \brief Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration @@ -8751,11 +8784,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: test/SemaCXX/PR25848.cpp =================================================================== --- /dev/null +++ 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: test/SemaCXX/friend2.cpp =================================================================== --- /dev/null +++ test/SemaCXX/friend2.cpp @@ -0,0 +1,145 @@ +// 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}} +}; + + +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(); +} + +}