aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/name-lookup.c
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2021-02-12 06:55:49 -0800
committerNathan Sidwell <nathan@acm.org>2021-02-12 13:50:03 -0800
commit0c27fe96f812df76ca07272d3c68765bd1f9dc08 (patch)
tree674ead99157d3d8382dd112f2bd4fd8c519972aa /gcc/cp/name-lookup.c
parent8f93e1b892850b00bf6b9cbc5711a7d5bc367967 (diff)
downloadgcc-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.c92
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