Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp @@ -615,7 +615,8 @@ << New << New->isConstexpr(); Diag(Old->getLocation(), diag::note_previous_declaration); Invalid = true; - } else if (!Old->isInlined() && New->isInlined() && Old->isDefined(Def)) { + } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() && + Old->isDefined(Def)) { // 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. Index: cfe/trunk/test/SemaTemplate/friend.cpp =================================================================== --- cfe/trunk/test/SemaTemplate/friend.cpp +++ cfe/trunk/test/SemaTemplate/friend.cpp @@ -31,3 +31,19 @@ friend class f1; // expected-error{{'friend' used outside of class}} } } + +namespace friend_redecl_inline { +// We had a bug where instantiating the foo friend declaration would check the +// defined-ness of the most recent decl while checking if the canonical decl was +// inlined. +void foo(); +void bar(); +template +class C { + friend void foo(); + friend inline void bar(); +}; +inline void foo() {} +inline void bar() {} +C c; +}