From 52838831258d2adf33a0ae765f5025d481db15b6 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 8 Apr 2015 00:04:47 +0000 Subject: [PATCH] Use the most recent previous decl to check if inline is added after a definition This affects this test case: void foo(); template class C { friend inline void foo(); }; inline void foo() {} C c; Here, we instantiate the foo friend decl and add it to foo's redecl chain. However, our previous decl pointer happens to reference the first declaration of foo, which is not marked inline. When we check to see if foo was already defined, we implicitly search all previous decls. We should do the same for the inline check, instead of just checking this particular previous decl. Reviewers: rsmith Differential Revision: http://reviews.llvm.org/D8872 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@234374 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDeclCXX.cpp | 3 ++- test/SemaTemplate/friend.cpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 7b2848bf60..b0e6acaedb 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -615,7 +615,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, << 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. diff --git a/test/SemaTemplate/friend.cpp b/test/SemaTemplate/friend.cpp index e78a067ef8..ef1aed50e6 100644 --- a/test/SemaTemplate/friend.cpp +++ b/test/SemaTemplate/friend.cpp @@ -31,3 +31,19 @@ namespace PR6770 { 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; +} -- 2.40.0