diff options
author | Nathan Sidwell <nathan@acm.org> | 2021-02-12 06:55:49 -0800 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2021-02-12 13:50:03 -0800 |
commit | 0c27fe96f812df76ca07272d3c68765bd1f9dc08 (patch) | |
tree | 674ead99157d3d8382dd112f2bd4fd8c519972aa | |
parent | 8f93e1b892850b00bf6b9cbc5711a7d5bc367967 (diff) | |
download | gcc-0c27fe96f812df76ca07272d3c68765bd1f9dc08.zip gcc-0c27fe96f812df76ca07272d3c68765bd1f9dc08.tar.gz gcc-0c27fe96f812df76ca07272d3c68765bd1f9dc08.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/module.cc | 20 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 92 | ||||
-rw-r--r-- | gcc/cp/name-lookup.h | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/pr99040_a.C | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/pr99040_b.C | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/pr99040_c.C | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/pr99040_d.C | 2 |
7 files changed, 82 insertions, 58 deletions
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; |