Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1691,7 +1691,8 @@ // Returns true if the function declaration is a redeclaration bool CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, - bool IsExplicitSpecialization); + bool IsExplicitSpecialization, + bool IsDefinition); 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 @@ -8034,7 +8034,7 @@ if (!NewFD->isInvalidDecl()) D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, - isExplicitSpecialization)); + isExplicitSpecialization, D.isFunctionDefinition())); else if (!Previous.empty()) // Recover gracefully from an invalid redeclaration. D.setRedeclaration(true); @@ -8175,7 +8175,7 @@ if (!NewFD->isInvalidDecl()) D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, - isExplicitSpecialization)); + isExplicitSpecialization, D.isFunctionDefinition())); else if (!Previous.empty()) // Recover gracefully from an invalid redeclaration. D.setRedeclaration(true); @@ -8450,7 +8450,8 @@ /// \returns true if the function declaration is a redeclaration. bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, - bool IsExplicitSpecialization) { + bool IsExplicitSpecialization, + bool IsDefinition) { assert(!NewFD->getReturnType()->isVariablyModifiedType() && "Variably modified return types are not handled here"); @@ -8607,8 +8608,16 @@ } } else { - // This needs to happen first so that 'inline' propagates. - NewFD->setPreviousDeclaration(cast(OldDecl)); + if (NewFD->isOutOfLine() && + NewFD->getLexicalDeclContext()->isDependentContext() && + IsDefinition) + // Do not put friend function definitions found in template classes to + // redeclaration chains. There may be several such definitions in + // different classes, they would cause redefinition errors otherwise. + Redeclaration = false; + else + // This needs to happen first so that 'inline' propagates. + NewFD->setPreviousDeclaration(cast(OldDecl)); if (isa(NewFD)) NewFD->setAccess(OldDecl->getAccess()); @@ -10939,6 +10948,13 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, const FunctionDecl *EffectiveDefinition, SkipBodyInfo *SkipBody) { + // Don't complain if the given declaration corresponds to the friend function + // declared in a template class. Such declaration defines the function only if + // the template is instantiated, in the latter case the definition must be + // found in corresponding class instantiation. + if (FD->isOutOfLine() && FD->getLexicalDeclContext()->isDependentContext()) + return; + // Don't complain if we're in GNU89 mode and the previous definition // was an extern inline function. const FunctionDecl *Definition = EffectiveDefinition; Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -12660,6 +12660,18 @@ Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class); } + // If a friend non-dependent function is declared in a dependent context, do + // not put it into redeclaration chain of corresponding file level + // declarations. Such function will be available when the template will be + // instantiated. + } else if (CurContext->isDependentContext() && + (D.getName().getKind() != UnqualifiedId::IK_TemplateId) && + (SS.isInvalid() || !SS.isSet())) { + DC = CurContext; + while (!DC->isFileContext()) + DC = DC->getParent(); + LookupName(Previous, S); + // - There's no scope specifier, in which case we just go to the // appropriate scope and look for a function or function template // there as appropriate. Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1599,7 +1599,7 @@ } SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous, - isExplicitSpecialization); + isExplicitSpecialization, D->isThisDeclarationADefinition()); NamedDecl *PrincipalDecl = (TemplateParams ? cast(FunctionTemplate) @@ -1896,7 +1896,8 @@ } if (!IsClassScopeSpecialization) - SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, false); + SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, false, + D->isThisDeclarationADefinition()); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); Index: test/SemaCXX/PR25848.cpp =================================================================== --- /dev/null +++ test/SemaCXX/PR25848.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct A; +typedef int A::* P; + +inline P g(); // expected-warning{{inline function 'g' is not defined}} + +template

+struct R { + friend P 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 must 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(); +} + +}