[v2,3/6] c++/modules: Support anonymous namespaces in header units

Message ID 66f6499c.170a0220.1abf25.5cf3@mx.google.com
State New
Headers
Series c++/modules: Implement P1815 "Translation-unit-local entities" |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed

Commit Message

Nathaniel Shead Sept. 27, 2024, 5:58 a.m. UTC
  Bootstrapped and regtested on x86_64-pc-linux-gnu and aarch64-unknown-linux-gnu,
OK for trunk?

-- >8 --

A header unit may contain anonymous namespaces, and those declarations
are exported (as with any declaration in a header unit).  This patch
ensures that such declarations are correctly handled.

The change to 'make_namespace_finish' is required so that if an
anonymous namespace is first seen by an import it is correctly handled
within 'add_imported_namespace'.  I don't see any particular reason why
handling of anonymous namespaces here had to be handled separately
outside that function since these are the only two callers.

gcc/cp/ChangeLog:

	* module.cc (depset::hash::add_binding_entity): Also walk
	anonymous namespaces.
	(module_state::write_namespaces): Adjust assertion.
	* name-lookup.cc (push_namespace): Move anon using-directive
	handling to...
	(make_namespace_finish): ...here.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/internal-8_a.H: New test.
	* g++.dg/modules/internal-8_b.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/module.cc                            |  7 +++--
 gcc/cp/name-lookup.cc                       |  8 +++---
 gcc/testsuite/g++.dg/modules/internal-8_a.H | 28 ++++++++++++++++++++
 gcc/testsuite/g++.dg/modules/internal-8_b.C | 29 +++++++++++++++++++++
 4 files changed, 63 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-8_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-8_b.C
  

Comments

Jason Merrill Sept. 27, 2024, 4:12 p.m. UTC | #1
On 9/27/24 1:58 AM, Nathaniel Shead wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu and aarch64-unknown-linux-gnu,
> OK for trunk?
> 
> -- >8 --
> 
> A header unit may contain anonymous namespaces, and those declarations
> are exported (as with any declaration in a header unit).  This patch
> ensures that such declarations are correctly handled.
> 
> The change to 'make_namespace_finish' is required so that if an
> anonymous namespace is first seen by an import it is correctly handled
> within 'add_imported_namespace'.  I don't see any particular reason why
> handling of anonymous namespaces here had to be handled separately
> outside that function since these are the only two callers.

Please add a rationale comment to that hunk; OK with that change.

> gcc/cp/ChangeLog:
> 
> 	* module.cc (depset::hash::add_binding_entity): Also walk
> 	anonymous namespaces.
> 	(module_state::write_namespaces): Adjust assertion.
> 	* name-lookup.cc (push_namespace): Move anon using-directive
> 	handling to...
> 	(make_namespace_finish): ...here.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/modules/internal-8_a.H: New test.
> 	* g++.dg/modules/internal-8_b.C: New test.
> 
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
>   gcc/cp/module.cc                            |  7 +++--
>   gcc/cp/name-lookup.cc                       |  8 +++---
>   gcc/testsuite/g++.dg/modules/internal-8_a.H | 28 ++++++++++++++++++++
>   gcc/testsuite/g++.dg/modules/internal-8_b.C | 29 +++++++++++++++++++++
>   4 files changed, 63 insertions(+), 9 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/modules/internal-8_a.H
>   create mode 100644 gcc/testsuite/g++.dg/modules/internal-8_b.C
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 5d7f4941b2a..df407c1fd55 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -13723,15 +13723,15 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
>         return (flags & WMB_Using
>   	      ? flags & WMB_Export : DECL_MODULE_EXPORT_P (decl));
>       }
> -  else if (DECL_NAME (decl) && !data->met_namespace)
> +  else if (!data->met_namespace)
>       {
>         /* Namespace, walk exactly once.  */
> -      gcc_checking_assert (TREE_PUBLIC (decl));
>         data->met_namespace = true;
>         if (data->hash->add_namespace_entities (decl, data->partitions))
>   	{
>   	  /* It contains an exported thing, so it is exported.  */
>   	  gcc_checking_assert (DECL_MODULE_PURVIEW_P (decl));
> +	  gcc_checking_assert (TREE_PUBLIC (decl) || header_module_p ());
>   	  DECL_MODULE_EXPORT_P (decl) = true;
>   	}
>   
> @@ -16126,8 +16126,7 @@ module_state::write_namespaces (elf_out *to, vec<depset *> spaces,
>         tree ns = b->get_entity ();
>   
>         gcc_checking_assert (TREE_CODE (ns) == NAMESPACE_DECL);
> -      /* P1815 may have something to say about this.  */
> -      gcc_checking_assert (TREE_PUBLIC (ns));
> +      gcc_checking_assert (TREE_PUBLIC (ns) || header_module_p ());
>   
>         unsigned flags = 0;
>         if (TREE_PUBLIC (ns))
> diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> index eb365b259d9..fe2eb2e0917 100644
> --- a/gcc/cp/name-lookup.cc
> +++ b/gcc/cp/name-lookup.cc
> @@ -9098,6 +9098,9 @@ make_namespace_finish (tree ns, tree *slot, bool from_import = false)
>   
>     if (DECL_NAMESPACE_INLINE_P (ns) || !DECL_NAME (ns))
>       emit_debug_info_using_namespace (ctx, ns, true);
> +
> +  if (!DECL_NAMESPACE_INLINE_P (ns) && !DECL_NAME (ns))
> +    add_using_namespace (NAMESPACE_LEVEL (ctx)->using_directives, ns);
>   }
>   
>   /* Push into the scope of the NAME namespace.  If NAME is NULL_TREE,
> @@ -9234,11 +9237,6 @@ push_namespace (tree name, bool make_inline)
>   	      gcc_checking_assert (slot);
>   	    }
>   	  make_namespace_finish (ns, slot);
> -
> -	  /* Add the anon using-directive here, we don't do it in
> -	     make_namespace_finish.  */
> -	  if (!DECL_NAMESPACE_INLINE_P (ns) && !name)
> -	    add_using_namespace (current_binding_level->using_directives, ns);
>   	}
>       }
>   
> diff --git a/gcc/testsuite/g++.dg/modules/internal-8_a.H b/gcc/testsuite/g++.dg/modules/internal-8_a.H
> new file mode 100644
> index 00000000000..57fe60bb3c0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/internal-8_a.H
> @@ -0,0 +1,28 @@
> +// { dg-additional-options "-fmodule-header" }
> +// { dg-module-cmi {} }
> +
> +static int x = 123;
> +static void f() {}
> +template <typename T> static void t() {}
> +
> +namespace {
> +  int y = 456;
> +  void g() {};
> +  template <typename T> void u() {}
> +
> +  namespace ns { int in_ns = 456; }
> +
> +  struct A {};
> +  template <typename T> struct B {};
> +
> +  enum E { X };
> +  enum class F { Y };
> +
> +  template <typename T> using U = int;
> +
> +#if __cplusplus >= 202002L
> +  template <typename T> concept C = true;
> +#endif
> +}
> +
> +namespace ns2 = ns;
> diff --git a/gcc/testsuite/g++.dg/modules/internal-8_b.C b/gcc/testsuite/g++.dg/modules/internal-8_b.C
> new file mode 100644
> index 00000000000..a2d74a87473
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/internal-8_b.C
> @@ -0,0 +1,29 @@
> +// { dg-additional-options "-fmodules-ts" }
> +
> +import "internal-8_a.H";
> +
> +int main() {
> +  auto x2 = x;
> +  f();
> +  t<int>();
> +
> +  auto y2 = y;
> +  g();
> +  u<int>();
> +
> +  int val1 = ns::in_ns;
> +
> +  A a;
> +  B<int> b;
> +
> +  E e = X;
> +  F f = F::Y;
> +
> +  U<int> temp;
> +
> +#if __cplusplus >= 202002L
> +  static_assert(C<int>);
> +#endif
> +
> +  int val2 = ns2::in_ns;
> +}
  

Patch

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 5d7f4941b2a..df407c1fd55 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13723,15 +13723,15 @@  depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
       return (flags & WMB_Using
 	      ? flags & WMB_Export : DECL_MODULE_EXPORT_P (decl));
     }
-  else if (DECL_NAME (decl) && !data->met_namespace)
+  else if (!data->met_namespace)
     {
       /* Namespace, walk exactly once.  */
-      gcc_checking_assert (TREE_PUBLIC (decl));
       data->met_namespace = true;
       if (data->hash->add_namespace_entities (decl, data->partitions))
 	{
 	  /* It contains an exported thing, so it is exported.  */
 	  gcc_checking_assert (DECL_MODULE_PURVIEW_P (decl));
+	  gcc_checking_assert (TREE_PUBLIC (decl) || header_module_p ());
 	  DECL_MODULE_EXPORT_P (decl) = true;
 	}
 
@@ -16126,8 +16126,7 @@  module_state::write_namespaces (elf_out *to, vec<depset *> spaces,
       tree ns = b->get_entity ();
 
       gcc_checking_assert (TREE_CODE (ns) == NAMESPACE_DECL);
-      /* P1815 may have something to say about this.  */
-      gcc_checking_assert (TREE_PUBLIC (ns));
+      gcc_checking_assert (TREE_PUBLIC (ns) || header_module_p ());
 
       unsigned flags = 0;
       if (TREE_PUBLIC (ns))
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index eb365b259d9..fe2eb2e0917 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -9098,6 +9098,9 @@  make_namespace_finish (tree ns, tree *slot, bool from_import = false)
 
   if (DECL_NAMESPACE_INLINE_P (ns) || !DECL_NAME (ns))
     emit_debug_info_using_namespace (ctx, ns, true);
+
+  if (!DECL_NAMESPACE_INLINE_P (ns) && !DECL_NAME (ns))
+    add_using_namespace (NAMESPACE_LEVEL (ctx)->using_directives, ns);
 }
 
 /* Push into the scope of the NAME namespace.  If NAME is NULL_TREE,
@@ -9234,11 +9237,6 @@  push_namespace (tree name, bool make_inline)
 	      gcc_checking_assert (slot);
 	    }
 	  make_namespace_finish (ns, slot);
-
-	  /* Add the anon using-directive here, we don't do it in
-	     make_namespace_finish.  */
-	  if (!DECL_NAMESPACE_INLINE_P (ns) && !name)
-	    add_using_namespace (current_binding_level->using_directives, ns);
 	}
     }
 
diff --git a/gcc/testsuite/g++.dg/modules/internal-8_a.H b/gcc/testsuite/g++.dg/modules/internal-8_a.H
new file mode 100644
index 00000000000..57fe60bb3c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-8_a.H
@@ -0,0 +1,28 @@ 
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+static int x = 123;
+static void f() {}
+template <typename T> static void t() {}
+
+namespace {
+  int y = 456;
+  void g() {};
+  template <typename T> void u() {}
+
+  namespace ns { int in_ns = 456; }
+
+  struct A {};
+  template <typename T> struct B {};
+
+  enum E { X };
+  enum class F { Y };
+
+  template <typename T> using U = int;
+
+#if __cplusplus >= 202002L
+  template <typename T> concept C = true;
+#endif
+}
+
+namespace ns2 = ns;
diff --git a/gcc/testsuite/g++.dg/modules/internal-8_b.C b/gcc/testsuite/g++.dg/modules/internal-8_b.C
new file mode 100644
index 00000000000..a2d74a87473
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-8_b.C
@@ -0,0 +1,29 @@ 
+// { dg-additional-options "-fmodules-ts" }
+
+import "internal-8_a.H";
+
+int main() {
+  auto x2 = x;
+  f();
+  t<int>();
+
+  auto y2 = y;
+  g();
+  u<int>();
+
+  int val1 = ns::in_ns;
+
+  A a;
+  B<int> b;
+
+  E e = X;
+  F f = F::Y;
+
+  U<int> temp;
+
+#if __cplusplus >= 202002L
+  static_assert(C<int>);
+#endif
+
+  int val2 = ns2::in_ns;
+}