Author: sepavloff Date: Thu Jun 8 01:07:07 2017 New Revision: 304964 URL: http://llvm.org/viewvc/llvm-project?rev=304964&view=rev Log: Improve diagnostics if friend function redefines file-level function.
Clang makes check for function redefinition after it merged the new declaration with the existing one. As a result, it produces poor diagnostics in the case of a friend function defined inline, as in the code: ``` void func() {} class C { friend void func() {} }; ``` Error message in this case states that `inline declaration of 'func' follows non-inline definition`, which is misleading, as `func` does not have explicit `inline` specifier. With this changes compiler reports function redefinition if the new function is a friend defined inline and it does not have explicit `inline` specifier. Differential Revision: https://reviews.llvm.org/D26065 Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=304964&r1=304963&r2=304964&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jun 8 01:07:07 2017 @@ -638,7 +638,12 @@ bool Sema::MergeCXXFunctionDecl(Function Diag(Old->getLocation(), diag::note_previous_declaration); Invalid = true; } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() && - Old->isDefined(Def)) { + Old->isDefined(Def) && + // If a friend function is inlined but does not have 'inline' + // specifier, it is a definition. Do not report attribute conflict + // in this case, redefinition will be diagnosed later. + (New->isInlineSpecified() || + New->getFriendObjectKind() == Decl::FOK_None)) { // C++11 [dcl.fcn.spec]p4: // If the definition of a function appears in a translation unit before its // first declaration as inline, the program is ill-formed. Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp?rev=304964&r1=304963&r2=304964&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp (original) +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp Thu Jun 8 01:07:07 2017 @@ -4,3 +4,31 @@ void f0() { // expected-note {{previous } inline void f0(); // expected-error {{inline declaration of 'f0' follows non-inline definition}} + +void func_01() {} // expected-note{{previous definition is here}} +struct C01 { + friend void func_01() {} // expected-error{{redefinition of 'func_01'}} +}; + +void func_02() {} // expected-note{{previous definition is here}} +struct C02 { + friend inline void func_02(); // expected-error{{inline declaration of 'func_02' follows non-inline definition}} +}; + +void func_03() {} // expected-note{{previous definition is here}} +struct C03 { + friend inline void func_03() {} // expected-error{{inline declaration of 'func_03' follows non-inline definition}} +}; + +void func_04() {} // expected-note{{previous definition is here}} +inline void func_04() {} // expected-error{{inline declaration of 'func_04' follows non-inline definition}} + +void func_06() {} // expected-note{{previous definition is here}} +template<typename T> struct C06 { + friend inline void func_06() {} // expected-error{{inline declaration of 'func_06' follows non-inline definition}} +}; + +void func_07() {} // expected-note{{previous definition is here}} +template<typename T> struct C07 { + friend inline void func_07(); // expected-error{{inline declaration of 'func_07' follows non-inline definition}} +}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits