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 /gcc/cp/name-lookup.c | |
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.
Diffstat (limited to 'gcc/cp/name-lookup.c')
-rw-r--r-- | gcc/cp/name-lookup.c | 92 |
1 files changed, 49 insertions, 43 deletions
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 |