]> granicus.if.org Git - clang/commitdiff
Use the most recent previous decl to check if inline is added after a definition
authorReid Kleckner <reid@kleckner.net>
Wed, 8 Apr 2015 00:04:47 +0000 (00:04 +0000)
committerReid Kleckner <reid@kleckner.net>
Wed, 8 Apr 2015 00:04:47 +0000 (00:04 +0000)
This affects this test case:
  void foo();
  template <typename T> class C {
    friend inline void foo();
  };
  inline void foo() {}
  C<int> 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
test/SemaTemplate/friend.cpp

index 7b2848bf60621d882cde1fcc124d61fc429be371..b0e6acaedb965d9d2af642af3b13bb267d319cdd 100644 (file)
@@ -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.
index e78a067ef8faf3be8f9956490f7b84ec3cf0c081..ef1aed50e62661283314ab87324bdb0b1ff3d394 100644 (file)
@@ -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 <typename T>
+class C {
+  friend void foo();
+  friend inline void bar();
+};
+inline void foo() {}
+inline void bar() {}
+C<int> c;
+}