c++/modules: Support exporting using-decls in same namespace as target

Message ID 65e503b6.170a0220.22d59.01d0@mx.google.com
State Unresolved
Headers
Series c++/modules: Support exporting using-decls in same namespace as target |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Nathaniel Shead March 3, 2024, 11:11 p.m. UTC
  Came across this issue while working on another PR.

Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
Or otherwise for GCC 15?

-- >8 --

Currently a using-declaration bringing a name into its own namespace is
a no-op, except for functions. This prevents people from being able to
redeclare a name brought in from the GMF as exported, however, which
this patch fixes.

Apart from marking declarations as exported they are also now marked as
effectively being in the module purview (due to the using-decl) so that
they are properly processed, as 'add_binding_entity' assumes that
declarations not in the module purview cannot possibly be exported.

gcc/cp/ChangeLog:

	* name-lookup.cc (walk_module_binding): Remove completed FIXME.
	(do_nonmember_using_decl): Mark redeclared entities as exported
	when needed. Check for re-exporting internal linkage types.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/using-12.C: New test.
	* g++.dg/modules/using-13.h: New test.
	* g++.dg/modules/using-13_a.C: New test.
	* g++.dg/modules/using-13_b.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/name-lookup.cc                     | 50 +++++++++++++---
 gcc/testsuite/g++.dg/modules/using-12.C   | 73 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/modules/using-13.h   | 16 +++++
 gcc/testsuite/g++.dg/modules/using-13_a.C | 15 +++++
 gcc/testsuite/g++.dg/modules/using-13_b.C | 20 +++++++
 5 files changed, 166 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/using-12.C
 create mode 100644 gcc/testsuite/g++.dg/modules/using-13.h
 create mode 100644 gcc/testsuite/g++.dg/modules/using-13_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/using-13_b.C
  

Patch

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 6444db3f0eb..dce4caf8981 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -4189,7 +4189,7 @@  walk_module_binding (tree binding, bitmap partitions,
 		     void *data)
 {
   // FIXME: We don't quite deal with using decls naming stat hack
-  // type.  Also using decls exporting something from the same scope.
+  // type.
   tree current = binding;
   unsigned count = 0;
 
@@ -5238,13 +5238,36 @@  do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
     }
   else if (insert_p)
     {
-      value = lookup.value;
-      if (revealing_p && module_exporting_p ())
-	check_can_export_using_decl (value);
+      if (revealing_p
+	  && module_exporting_p ()
+	  && check_can_export_using_decl (lookup.value)
+	  && lookup.value == value
+	  && !DECL_MODULE_EXPORT_P (value))
+	{
+	  /* We're redeclaring the same value, but this time as
+	     newly exported: make sure to mark it as such.  */
+	  if (TREE_CODE (value) == TEMPLATE_DECL)
+	    {
+	      DECL_MODULE_EXPORT_P (value) = true;
+
+	      tree result = DECL_TEMPLATE_RESULT (value);
+	      retrofit_lang_decl (result);
+	      DECL_MODULE_PURVIEW_P (result) = true;
+	      DECL_MODULE_EXPORT_P (result) = true;
+	    }
+	  else
+	    {
+	      retrofit_lang_decl (value);
+	      DECL_MODULE_PURVIEW_P (value) = true;
+	      DECL_MODULE_EXPORT_P (value) = true;
+	    }
+	}
+      else
+	value = lookup.value;
     }
   
   /* Now the type binding.  */
-  if (lookup.type && lookup.type != type)
+  if (lookup.type)
     {
       if (type && !decls_match (lookup.type, type))
 	{
@@ -5253,9 +5276,20 @@  do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
 	}
       else if (insert_p)
 	{
-	  type = lookup.type;
-	  if (revealing_p && module_exporting_p ())
-	    check_can_export_using_decl (type);
+	  if (revealing_p
+	      && module_exporting_p ()
+	      && check_can_export_using_decl (lookup.type)
+	      && lookup.type == type
+	      && !DECL_MODULE_EXPORT_P (type))
+	    {
+	      /* We're redeclaring the same type, but this time as
+		 newly exported: make sure to mark it as such.  */
+	      retrofit_lang_decl (type);
+	      DECL_MODULE_PURVIEW_P (type) = true;
+	      DECL_MODULE_EXPORT_P (type) = true;
+	    }
+	  else
+	    type = lookup.type;
 	}
     }
 
diff --git a/gcc/testsuite/g++.dg/modules/using-12.C b/gcc/testsuite/g++.dg/modules/using-12.C
new file mode 100644
index 00000000000..54eacf7276e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-12.C
@@ -0,0 +1,73 @@ 
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi !bad }
+
+// Like using-10.C, but test exporting names within the same namespace.
+
+export module bad;
+
+// internal linkage
+namespace s {
+  namespace {
+    struct a1 {};  // { dg-message "declared here with internal linkage" }
+
+    template <typename T>
+    struct b1;  // { dg-message "declared here with internal linkage" }
+
+    int x1;  // { dg-message "declared here with internal linkage" }
+
+    template <typename T>
+    T y1;  // { dg-message "declared here with internal linkage" }
+
+    void f1();  // { dg-message "declared here with internal linkage" }
+
+    template <typename T>
+    void g1();  // { dg-message "declared here with internal linkage" }
+
+    export using s::a1;  // { dg-error "does not have external linkage" }
+    export using s::b1;  // { dg-error "does not have external linkage" }
+    export using s::x1;  // { dg-error "does not have external linkage" }
+    export using s::y1;  // { dg-error "does not have external linkage" }
+    export using s::f1;  // { dg-error "does not have external linkage" }
+    export using s::g1;  // { dg-error "does not have external linkage" }
+  }
+}
+
+// module linkage
+namespace m {
+  struct a2 {};  // { dg-message "declared here with module linkage" }
+
+  template <typename T>
+  struct b2;  // { dg-message "declared here with module linkage" }
+
+  int x2;  // { dg-message "declared here with module linkage" }
+
+  template <typename T>
+  T y2;  // { dg-message "declared here with module linkage" }
+
+  void f2();  // { dg-message "declared here with module linkage" }
+
+  template <typename T>
+  void g2();  // { dg-message "declared here with module linkage" }
+
+  export using m::a2;  // { dg-error "does not have external linkage" }
+  export using m::b2;  // { dg-error "does not have external linkage" }
+  export using m::x2;  // { dg-error "does not have external linkage" }
+  export using m::y2;  // { dg-error "does not have external linkage" }
+  export using m::f2;  // { dg-error "does not have external linkage" }
+  export using m::g2;  // { dg-error "does not have external linkage" }
+}
+
+namespace t {
+  using a = int;  // { dg-message "declared here with no linkage" }
+
+  template <typename T>
+  using b = int;  // { dg-message "declared here with no linkage" }
+
+  typedef int c;  // { dg-message "declared here with no linkage" }
+
+  export using t::a;  // { dg-error "does not have external linkage" }
+  export using t::b;  // { dg-error "does not have external linkage" }
+  export using t::c;  // { dg-error "does not have external linkage" }
+}
+
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/using-13.h b/gcc/testsuite/g++.dg/modules/using-13.h
new file mode 100644
index 00000000000..b8ef2a11cc4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-13.h
@@ -0,0 +1,16 @@ 
+// Like using-11.h, but additional kinds of declarations.
+
+struct A {};
+
+template <typename> struct B {};
+template <> struct B<int> { using foo = int; };
+template <typename T> struct B<T*> { using bar = T; };
+
+using C = int;
+
+inline int D = 0;
+
+#if __cpp_concepts >= 201907L
+template <typename>
+concept E = true;
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/using-13_a.C b/gcc/testsuite/g++.dg/modules/using-13_a.C
new file mode 100644
index 00000000000..fed33ac2333
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-13_a.C
@@ -0,0 +1,15 @@ 
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+module;
+#include "using-13.h"
+
+export module M;
+export using ::A;
+export using ::B;
+export using ::C;
+export using ::D;
+
+#if __cpp_concepts >= 201907L
+export using ::E;
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/using-13_b.C b/gcc/testsuite/g++.dg/modules/using-13_b.C
new file mode 100644
index 00000000000..49fa09d39ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-13_b.C
@@ -0,0 +1,20 @@ 
+// { dg-additional-options "-fmodules-ts" }
+
+import M;
+
+int main() {
+  A a;
+
+  // Check all specialisations are correctly exported
+  B<void> b;
+  B<int>::foo b1;
+  B<int*>::bar b2;
+
+  C c;
+
+  auto d = D;
+
+#if __cpp_concepts >= 201907L
+  auto e = E<void>;
+#endif
+}