[modules] Don't diagnose "redefinition" of a friend with a pending definition
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 1 Mar 2018 22:20:13 +0000 (22:20 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 1 Mar 2018 22:20:13 +0000 (22:20 +0000)
if the other definition is a merged copy of the same function.

llvm-svn: 326496

clang/lib/Sema/SemaDecl.cpp
clang/test/Modules/friend-definition.cpp [new file with mode: 0644]

index 62fd020..b358b04 100644 (file)
@@ -12303,6 +12303,15 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
       if (I != FD && !I->isInvalidDecl() &&
           I->getFriendObjectKind() != Decl::FOK_None) {
         if (FunctionDecl *Original = I->getInstantiatedFromMemberFunction()) {
+          if (FunctionDecl *OrigFD = FD->getInstantiatedFromMemberFunction()) {
+            // A merged copy of the same function, instantiated as a member of
+            // the same class, is OK.
+            if (declaresSameEntity(OrigFD, Original) &&
+                declaresSameEntity(cast<Decl>(I->getLexicalDeclContext()),
+                                   cast<Decl>(FD->getLexicalDeclContext())))
+              continue;
+          }
+
           if (Original->isThisDeclarationADefinition()) {
             Definition = I;
             break;
diff --git a/clang/test/Modules/friend-definition.cpp b/clang/test/Modules/friend-definition.cpp
new file mode 100644 (file)
index 0000000..8588cbd
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fmodules -std=c++14 %s -verify
+// expected-no-diagnostics
+
+#pragma clang module build A
+module A {}
+#pragma clang module contents
+#pragma clang module begin A
+template<typename T> struct A {
+  friend A operator+(const A&, const A&) { return {}; }
+};
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build B
+module B {}
+#pragma clang module contents
+#pragma clang module begin B
+#pragma clang module import A
+inline void f() { A<int> a; }
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build C
+module C {}
+#pragma clang module contents
+#pragma clang module begin C
+#pragma clang module import A
+inline void g() { A<int> a; }
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import A
+#pragma clang module import B
+#pragma clang module import C
+
+void h() {
+  A<int> a;
+  a + a;
+}