From 0c27fe96f812df76ca07272d3c68765bd1f9dc08 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 12 Feb 2021 06:55:49 -0800 Subject: [PATCH] c++: Register streamed-in decls when new [PR 99040] 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 | 20 +++---- gcc/cp/name-lookup.c | 92 +++++++++++++++++--------------- gcc/cp/name-lookup.h | 2 +- gcc/testsuite/g++.dg/modules/pr99040_a.C | 9 ++++ gcc/testsuite/g++.dg/modules/pr99040_b.C | 5 ++ gcc/testsuite/g++.dg/modules/pr99040_c.C | 10 ++++ gcc/testsuite/g++.dg/modules/pr99040_d.C | 2 + 7 files changed, 82 insertions(+), 58 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/pr99040_a.C create mode 100644 gcc/testsuite/g++.dg/modules/pr99040_b.C create mode 100644 gcc/testsuite/g++.dg/modules/pr99040_c.C create mode 100644 gcc/testsuite/g++.dg/modules/pr99040_d.C diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 0749db8..37ccddc 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -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; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 8aa490d..5aa206d 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -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 diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index e159942..cb75566 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -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 index 0000000..50c61bb --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99040_a.C @@ -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 index 0000000..e9e485d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99040_b.C @@ -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 index 0000000..a675d72 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99040_c.C @@ -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 index 0000000..ed66690 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99040_d.C @@ -0,0 +1,2 @@ +// { dg-additional-options {-fmodules-ts -fno-module-lazy} } +module hello; -- 2.7.4