c++: Register streamed-in decls when new [PR 99040]
authorNathan Sidwell <nathan@acm.org>
Fri, 12 Feb 2021 14:55:49 +0000 (06:55 -0800)
committerNathan Sidwell <nathan@acm.org>
Fri, 12 Feb 2021 21:50:03 +0000 (13:50 -0800)
With modules one can have using-decls refering to their own scope.  This
is the way to export things from the GMF or from an import.  The
problem was I was using current_ns == CP_DECL_CONTEXT (decl) to
determine whether a decl should be registered in a namespace level or
not.  But that's an inadequate check and we ended up reregistering
decls and creating a circular list.  We should be registering the decl
when first encountered -- whether we bind it is orthogonal to that.

PR c++/99040
gcc/cp/
* module.cc (trees_in::decl_value): Call add_module_namespace_decl
for new namespace-scope entities.
(module_state::read_cluster): Don't call add_module_decl here.
* name-lookup.h (add_module_decl): Rename to ...
(add_module_namespace_decl): ... this.
* name-lookup.c (newbinding_bookkeeping): Move into ...
(do_pushdecl): ... here.  Its only remaining caller.
(add_module_decl): Rename to ...
(add_module_namespace_decl): ... here.  Add checking-assert for
circularity. Don't call newbinding_bookkeeping, just extern_c
checking and incomplete var checking.
gcc/testsuite/
* g++.dg/modules/pr99040_a.C: New.
* g++.dg/modules/pr99040_b.C: New.
* g++.dg/modules/pr99040_c.C: New.
* g++.dg/modules/pr99040_d.C: New.

gcc/cp/module.cc
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/testsuite/g++.dg/modules/pr99040_a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99040_b.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99040_c.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99040_d.C [new file with mode: 0644]

index 0749db8fe94654b00b9e957bde1fbeacfbf90ea0..37ccddc74a578586d550aacf455dddf5d91072e0 100644 (file)
@@ -8162,6 +8162,12 @@ trees_in::decl_value ()
        /* Set the TEMPLATE_DECL's type.  */
        TREE_TYPE (decl) = TREE_TYPE (inner);
 
+      if (NAMESPACE_SCOPE_P (decl)
+         && (mk == MK_named || mk == MK_unique
+             || mk == MK_enum || mk == MK_friend_spec)
+         && !(VAR_OR_FUNCTION_DECL_P (decl) && DECL_LOCAL_DECL_P (decl)))
+       add_module_namespace_decl (CP_DECL_CONTEXT (decl), decl);
+
       /* The late insertion of an alias here or an implicit member
          (next block), is ok, because we ensured that all imports were
          loaded up before we started this cluster.  Thus an insertion
@@ -14893,20 +14899,6 @@ module_state::read_cluster (unsigned snum)
                                     : 0,
                                     decls, type, visible))
              sec.set_overrun ();
-
-           if (type
-               && CP_DECL_CONTEXT (type) == ns
-               && !sec.is_duplicate (type))
-             add_module_decl (ns, name, type);
-
-           for (ovl_iterator iter (decls); iter; ++iter)
-             if (!iter.using_p ())
-               {
-                 tree decl = *iter;
-                 if (CP_DECL_CONTEXT (decl) == ns
-                     && !sec.is_duplicate (decl))
-                   add_module_decl (ns, name, decl);
-               }
          }
          break;
 
index 8aa490db6340aab05ae679fff0bad0f1c9c8543c..5aa206d40d4671321c0f6811d93c360b334a3775 100644 (file)
@@ -382,7 +382,8 @@ add_decl_to_level (cp_binding_level *b, tree decl)
 
   /* Make sure we don't create a circular list.  xref_tag can end
      up pushing the same artificial decl more than once.  We
-     should have already detected that in update_binding.  */
+     should have already detected that in update_binding.  (This isn't a
+     complete verification of non-circularity.)  */
   gcc_assert (b->names != decl);
 
   /* We build up the list in reverse order, and reverse it later if
@@ -3496,41 +3497,6 @@ implicitly_export_namespace (tree ns)
     }
 }
 
-/* DECL has just been bound at LEVEL.  finish up the bookkeeping.  */
-
-static void
-newbinding_bookkeeping (tree name, tree decl, cp_binding_level *level)
-{
-  if (TREE_CODE (decl) == TYPE_DECL)
-    {
-      tree type = TREE_TYPE (decl);
-
-      if (type != error_mark_node)
-       {
-         if (TYPE_NAME (type) != decl)
-           set_underlying_type (decl);
-
-         set_identifier_type_value_with_scope (name, decl, level);
-
-         if (level->kind != sk_namespace
-             && !instantiating_current_function_p ())
-           /* This is a locally defined typedef in a function that
-              is not a template instantation, record it to implement
-              -Wunused-local-typedefs.  */
-           record_locally_defined_typedef (decl);
-       }
-    }
-  else
-    {
-      if (VAR_P (decl) && !DECL_LOCAL_DECL_P (decl))
-       maybe_register_incomplete_var (decl);
-
-      if (VAR_OR_FUNCTION_DECL_P (decl)
-         && DECL_EXTERN_C_P (decl))
-       check_extern_c_conflict (decl);
-    }
-}
-
 /* DECL is a global or module-purview entity.  If it has non-internal
    linkage, and we have a module vector, record it in the appropriate
    slot.  We have already checked for duplicates.  */
@@ -3839,12 +3805,38 @@ do_pushdecl (tree decl, bool hiding)
        decl = old;
       else
        {
-         newbinding_bookkeeping (name, decl, level);
+         if (TREE_CODE (decl) == TYPE_DECL)
+           {
+             tree type = TREE_TYPE (decl);
+
+             if (type != error_mark_node)
+               {
+                 if (TYPE_NAME (type) != decl)
+                   set_underlying_type (decl);
 
-         if (VAR_OR_FUNCTION_DECL_P (decl)
-             && DECL_LOCAL_DECL_P (decl)
-             && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL)
-           push_local_extern_decl_alias (decl);
+                 set_identifier_type_value_with_scope (name, decl, level);
+
+                 if (level->kind != sk_namespace
+                     && !instantiating_current_function_p ())
+                   /* This is a locally defined typedef in a function that
+                      is not a template instantation, record it to implement
+                      -Wunused-local-typedefs.  */
+                   record_locally_defined_typedef (decl);
+               }
+           }
+         else if (VAR_OR_FUNCTION_DECL_P (decl))
+           {
+             if (DECL_EXTERN_C_P (decl))
+               check_extern_c_conflict (decl);
+
+             if (!DECL_LOCAL_DECL_P (decl)
+                 && VAR_P (decl))
+               maybe_register_incomplete_var (decl);
+
+             if (DECL_LOCAL_DECL_P (decl)
+                 && NAMESPACE_SCOPE_P (decl))
+               push_local_extern_decl_alias (decl);
+           }
 
          if (level->kind == sk_namespace
              && TREE_PUBLIC (level->this_entity))
@@ -4182,11 +4174,25 @@ load_pending_specializations (tree ns, tree name)
 }
 
 void
-add_module_decl (tree ns, tree name, tree decl)
+add_module_namespace_decl (tree ns, tree decl)
 {
   gcc_assert (!DECL_CHAIN (decl));
+  gcc_checking_assert (!(VAR_OR_FUNCTION_DECL_P (decl)
+                        && DECL_LOCAL_DECL_P (decl)));
+  if (CHECKING_P)
+    /* Expensive already-there? check.  */
+    for (auto probe = NAMESPACE_LEVEL (ns)->names; probe;
+        probe = DECL_CHAIN (probe))
+      gcc_assert (decl != probe);
+
   add_decl_to_level (NAMESPACE_LEVEL (ns), decl);
-  newbinding_bookkeeping (name, decl, NAMESPACE_LEVEL (ns));
+
+  if (VAR_P (decl))
+    maybe_register_incomplete_var (decl);
+
+  if (VAR_OR_FUNCTION_DECL_P (decl)
+      && DECL_EXTERN_C_P (decl))
+    check_extern_c_conflict (decl);
 }
 
 /* Enter DECL into the symbol table, if that's appropriate.  Returns
index e159942eda44bbd29c9c674d62ca1f15a294e8e7..cb75566d1aeb27a9c281ad086d61bc32f892db81 100644 (file)
@@ -490,7 +490,7 @@ extern bool import_module_binding (tree ctx, tree name, unsigned mod,
 extern bool set_module_binding (tree ctx, tree name, unsigned mod,
                                int mod_glob_flag,
                                tree value, tree type, tree visible);
-extern void add_module_decl (tree ctx, tree name, tree decl);
+extern void add_module_namespace_decl (tree ns, tree decl);
 
 enum WMB_Flags
 {
diff --git a/gcc/testsuite/g++.dg/modules/pr99040_a.C b/gcc/testsuite/g++.dg/modules/pr99040_a.C
new file mode 100644 (file)
index 0000000..50c61bb
--- /dev/null
@@ -0,0 +1,9 @@
+// PR c++/99040
+// { dg-additional-options -fmodules-ts }
+export  module  format;
+// { dg-module-cmi format }
+
+export namespace NS
+{
+void Format ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/pr99040_b.C b/gcc/testsuite/g++.dg/modules/pr99040_b.C
new file mode 100644 (file)
index 0000000..e9e485d
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodules-ts }
+export  module  hello:check;
+// { dg-module-cmi hello:check }
+
+export namespace NS {}
diff --git a/gcc/testsuite/g++.dg/modules/pr99040_c.C b/gcc/testsuite/g++.dg/modules/pr99040_c.C
new file mode 100644 (file)
index 0000000..a675d72
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+export  module  hello;
+// { dg-module-cmi hello }
+export import :check;
+import  format;
+
+export namespace NS
+{
+using NS::Format;
+}
diff --git a/gcc/testsuite/g++.dg/modules/pr99040_d.C b/gcc/testsuite/g++.dg/modules/pr99040_d.C
new file mode 100644 (file)
index 0000000..ed66690
--- /dev/null
@@ -0,0 +1,2 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy} }
+module  hello;