Hello again,

This is part one of a patchset to add an optional warning for long distance
(cross module) friendship when the friendship has no useful/sensical meaning.

Attached is a patch to error when trying to define a member function of a type
owned by a different module. This also fixes an issue where a friend decl lets
a user define a function owned by a different module.


2020-08-14  Jeff Chapman II  <jchap...@lock3software.com>

gcc/cp/
        * decl.c (duplicate_decls): Return original decl when
        attempting to redeclare a function owned by another module
        instead of clobbering the original decl.
        (grokfndecl): Error on member declarations of types owned by
        another module.

gcc/testsuite/
        * g++.dg/modules/redecl-1_[ab].C: New test.
        * g++.dg/modules/redecl-2_[ab].C: Ditto.
        * g++.dg/modules/redecl-3_[ab].C: Ditto.


Please let me know if there are any questions,
Jeff Chapman II
From fc95c562ec87520f66388a35009649c4b020a843 Mon Sep 17 00:00:00 2001
From: Jeff Chapman II <jchap...@lock3software.com>
Date: Thu, 19 Dec 2019 09:43:16 -0500
Subject: [PATCH 1/2] c++: Fix cross module member redecl

2020-08-14  Jeff Chapman II  <jchap...@lock3software.com>

gcc/cp/
	* decl.c (duplicate_decls): Return original decl when
	attempting to redeclare a function owned by another module
	instead of clobbering the original decl.
	(grokfndecl): Error on member declarations of types owned by
	another module.

gcc/testsuite/
	* g++.dg/modules/redecl-1_[ab].C: New test.
	* g++.dg/modules/redecl-2_[ab].C: Ditto.
	* g++.dg/modules/redecl-3_[ab].C: Ditto.
---
 gcc/cp/decl.c                             | 14 ++++++++++++++
 gcc/testsuite/g++.dg/modules/redecl-1_a.C |  9 +++++++++
 gcc/testsuite/g++.dg/modules/redecl-1_b.C |  8 ++++++++
 gcc/testsuite/g++.dg/modules/redecl-2_a.C | 10 ++++++++++
 gcc/testsuite/g++.dg/modules/redecl-2_b.C |  7 +++++++
 gcc/testsuite/g++.dg/modules/redecl-3_a.C |  6 ++++++
 gcc/testsuite/g++.dg/modules/redecl-3_b.C | 13 +++++++++++++
 7 files changed, 67 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/modules/redecl-1_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/redecl-1_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/redecl-2_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/redecl-2_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/redecl-3_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/redecl-3_b.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index decd58791ae..e8637dac7eb 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2031,6 +2031,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 	    }
 	}
     }
+  /* FIXME Is there a better place to handle this? Without this, we end up
+   * potentially merging a decl owned by a separate module with a friend decl
+   * injected in the current module (see modules/redecl-3). Returning olddecl
+   * relies on code higher up handling the issue.  */
+  else if (modules_p () && !module_may_redeclare (olddecl))
+    return olddecl;
 
   /* We have committed to returning OLDDECL at this point.  */
 
@@ -9517,6 +9523,14 @@ grokfndecl (tree ctype,
 
   if (TREE_CODE (type) == METHOD_TYPE)
     {
+      if (modules_p()
+	  && !module_may_redeclare (TYPE_NAME (ctype)))
+	{
+	  error_at (location, "declaration conflicts with import");
+	  inform (location_of (ctype), "import declared %q#T here", ctype);
+	  return NULL_TREE;
+	}
+
       tree parm = build_this_parm (decl, type, quals);
       DECL_CHAIN (parm) = parms;
       parms = parm;
diff --git a/gcc/testsuite/g++.dg/modules/redecl-1_a.C b/gcc/testsuite/g++.dg/modules/redecl-1_a.C
new file mode 100644
index 00000000000..2646adf8327
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/redecl-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export struct Foo
+{
+  int foo();
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/redecl-1_b.C b/gcc/testsuite/g++.dg/modules/redecl-1_b.C
new file mode 100644
index 00000000000..b980bfe290c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/redecl-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+import foo;
+
+int Foo::foo() // { dg-error "conflicts with import" }
+{
+  return 1;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/redecl-2_a.C b/gcc/testsuite/g++.dg/modules/redecl-2_a.C
new file mode 100644
index 00000000000..eea99f2024e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/redecl-2_a.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export struct Foo
+{
+  int foo();
+  friend class Bar;
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/redecl-2_b.C b/gcc/testsuite/g++.dg/modules/redecl-2_b.C
new file mode 100644
index 00000000000..9c3b545f6d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/redecl-2_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+import foo;
+
+struct Bar // { dg-error "cannot declare.*in a different module" }
+{
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/redecl-3_a.C b/gcc/testsuite/g++.dg/modules/redecl-3_a.C
new file mode 100644
index 00000000000..17993d26ef3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/redecl-3_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export int foo();
+
diff --git a/gcc/testsuite/g++.dg/modules/redecl-3_b.C b/gcc/testsuite/g++.dg/modules/redecl-3_b.C
new file mode 100644
index 00000000000..35efe7b1d37
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/redecl-3_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+import foo;
+
+struct Bar
+{
+  friend int foo();
+};
+
+int foo() // { dg-error "conflicts with import" }
+{
+  return 0;
+}
+
-- 
2.27.0

Reply via email to