From a92ed39c416b2a92f404d9851fdfea5cae7e6b21 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 9 May 2022 04:47:14 -0700 Subject: [PATCH] [c++] Add module attachment This adds module attachment as a distinct flag to 'in module purview'. A declaration may have neither or both (as before), but can also have just the 'in [named-module] purview', which was previously not representable. This new state allows some cleanup of redeclarations (particularly the builtins), which was a little warty. Some other internal APIs get similarly clarified. gcc/cp/ * cp-tree.h (DECL_MODULE_ATTACH_P): New. (struct lang_decl_base): Add module_attach_p flag. * decl.cc (duplicate_decls): Rework module redeclaration checking. * module.cc (trees_out::lang_decl_bools): Write attach flag. (trees_in::lang_decl_bools): ... and read it back. (trees_out::decl_value): Rework module attachment handling. (trees_in::decl_value): Rename local var to reflect meaning. (trees_in::key_mergeable): Likewise. (get_originating_module): Use DECL_MODULE_ATTACH_P. No need to special-case mangling. (module_may_redeclare): Reimplement. (set_originating_module): Deal with attachment. * name-lookup.cc (maybe_record_mergeable_decl): Deal with attachment. (mergeable_namespace_slots): Likewise. (do_nonmember_using_decl): Likewise. * name-lookup.h (mergeable_namespace_slots): Adjust parm meaning. * ptree.cc (cxx_print_decl): Adjust purview & attach printing. --- gcc/cp/cp-tree.h | 14 +++--- gcc/cp/decl.cc | 23 +++++----- gcc/cp/module.cc | 117 +++++++++++++++++++++++++++++--------------------- gcc/cp/name-lookup.cc | 17 +++++--- gcc/cp/name-lookup.h | 2 +- gcc/cp/ptree.cc | 20 ++++++--- 6 files changed, 114 insertions(+), 79 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cfda833..e16b8d7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1725,6 +1725,11 @@ check_constraint_info (tree t) #define DECL_MODULE_PURVIEW_P(N) \ (DECL_LANG_SPECIFIC (DECL_MODULE_CHECK (N))->u.base.module_purview_p) +/* Attached to the named module it is in the purview of. Decls + attached to the global module will have this false. */ +#define DECL_MODULE_ATTACH_P(N) \ + (DECL_LANG_SPECIFIC (DECL_MODULE_CHECK (N))->u.base.module_attach_p) + /* True if the live version of the decl was imported. */ #define DECL_MODULE_IMPORT_P(NODE) \ (DECL_LANG_SPECIFIC (DECL_MODULE_CHECK (NODE))->u.base.module_import_p) @@ -2827,13 +2832,8 @@ struct GTY(()) lang_decl_base { /* The following apply to VAR, FUNCTION, TYPE, CONCEPT, & NAMESPACE decls. */ - // FIXME: Purview and Attachment are not the same thing, due to - // linkage-declarations. The modules code presumes they are the - // same. (For context, linkage-decl semantics was a very late - // change). We need a module_attachment_p flag, and this will allow - // some simplification of how we handle header unit entities. - // Hurrah! - unsigned module_purview_p : 1; /* in module purview (not GMF) */ + unsigned module_purview_p : 1; // in named-module purview + unsigned module_attach_p : 1; // attached to named module unsigned module_import_p : 1; /* from an import */ unsigned module_entity_p : 1; /* is in the entitity ary & hash. */ diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 4099fde..5654bc75 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -2108,30 +2108,31 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) && TREE_CODE (olddecl) != NAMESPACE_DECL && !hiding) { - if (DECL_ARTIFICIAL (olddecl)) + if (!module_may_redeclare (olddecl)) { - if (module_attach_p ()) + if (DECL_ARTIFICIAL (olddecl)) error ("declaration %qD conflicts with builtin", newdecl); else - DECL_MODULE_EXPORT_P (olddecl) = DECL_MODULE_EXPORT_P (newdecl); - } - else - { - if (!module_may_redeclare (olddecl)) { error ("declaration %qD conflicts with import", newdecl); inform (olddecl_loc, "import declared %q#D here", olddecl); - - return error_mark_node; } - if (DECL_MODULE_EXPORT_P (newdecl) - && !DECL_MODULE_EXPORT_P (olddecl)) + return error_mark_node; + } + + tree not_tmpl = STRIP_TEMPLATE (olddecl); + if (DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_ATTACH_P (not_tmpl)) + { + if (DECL_MODULE_EXPORT_P (STRIP_TEMPLATE (newdecl)) + && !DECL_MODULE_EXPORT_P (not_tmpl)) { error ("conflicting exporting declaration %qD", newdecl); inform (olddecl_loc, "previous declaration %q#D here", olddecl); } } + else if (DECL_MODULE_EXPORT_P (newdecl)) + DECL_MODULE_EXPORT_P (not_tmpl) = true; } /* We have committed to returning OLDDECL at this point. */ diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 27b8f64..547bf36 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -47,10 +47,14 @@ along with GCC; see the file COPYING3. If not see module-local index. Each importable DECL contains several flags. The simple set are - DECL_EXPORT_P, DECL_MODULE_PURVIEW_P and DECL_MODULE_IMPORT_P. The - first indicates whether it is exported, the second whether it is in - the module purview (as opposed to the global module fragment), and - the third indicates whether it was an import into this TU or not. + DECL_MODULE_EXPORT_P, DECL_MODULE_PURVIEW_P, DECL_MODULE_ATTACH_P + and DECL_MODULE_IMPORT_P. The first indicates whether it is + exported, the second whether it is in module or header-unit + purview. The third indicates it is attached to the named module in + whose purview it resides and the fourth indicates whether it was an + import into this TU or not. DECL_MODULE_ATTACH_P will be false for + all decls in a header-unit, and for those in a named module inside + a linkage declaration. The more detailed flags are DECL_MODULE_PARTITION_P, DECL_MODULE_ENTITY_P. The first is set in a primary interface unit @@ -2927,7 +2931,7 @@ private: public: tree decl_container (); tree key_mergeable (int tag, merge_kind, tree decl, tree inner, tree type, - tree container, bool is_mod); + tree container, bool is_attached); unsigned binfo_mergeable (tree *); private: @@ -5529,9 +5533,11 @@ trees_out::lang_decl_bools (tree t) WB (lang->u.base.concept_p); WB (lang->u.base.var_declared_inline_p); WB (lang->u.base.dependent_init_p); - /* When building a header unit, everthing is marked as purview, but - that's the GM purview, so not what the importer will mean */ + /* When building a header unit, everthing is marked as purview, (so + we know which decls to write). But when we import them we do not + want to mark them as in module purview. */ WB (lang->u.base.module_purview_p && !header_module_p ()); + WB (lang->u.base.module_attach_p); if (VAR_OR_FUNCTION_DECL_P (t)) WB (lang->u.base.module_keyed_decls_p); switch (lang->u.base.selector) @@ -5602,6 +5608,7 @@ trees_in::lang_decl_bools (tree t) RB (lang->u.base.var_declared_inline_p); RB (lang->u.base.dependent_init_p); RB (lang->u.base.module_purview_p); + RB (lang->u.base.module_attach_p); if (VAR_OR_FUNCTION_DECL_P (t)) RB (lang->u.base.module_keyed_decls_p); switch (lang->u.base.selector) @@ -7535,14 +7542,14 @@ trees_out::decl_value (tree decl, depset *dep) or a module entity. This bool merges into the next block of bools. Sneaky. */ tree o = get_originating_module_decl (decl); - bool is_mod = false; + bool is_attached = false; tree not_tmpl = STRIP_TEMPLATE (o); if (DECL_LANG_SPECIFIC (not_tmpl) - && DECL_MODULE_PURVIEW_P (not_tmpl)) - is_mod = true; + && DECL_MODULE_ATTACH_P (not_tmpl)) + is_attached = true; - b (is_mod); + b (is_attached); } b (dep && dep->has_defn ()); } @@ -7791,7 +7798,7 @@ tree trees_in::decl_value () { int tag = 0; - bool is_mod = false; + bool is_attached = false; bool has_defn = false; unsigned mk_u = u (); if (mk_u >= MK_hwm || !merge_kind_name[mk_u]) @@ -7812,7 +7819,7 @@ trees_in::decl_value () { if (!(mk & MK_template_mask) && !state->is_header ()) /* See note in trees_out about where this bool is sequenced. */ - is_mod = b (); + is_attached = b (); has_defn = b (); } @@ -7916,7 +7923,8 @@ trees_in::decl_value () if (TREE_CODE (inner) == FUNCTION_DECL) parm_tag = fn_parms_init (inner); - tree existing = key_mergeable (tag, mk, decl, inner, type, container, is_mod); + tree existing = key_mergeable (tag, mk, decl, inner, type, container, + is_attached); tree existing_inner = existing; if (existing) { @@ -10652,7 +10660,7 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key) tree trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, - tree type, tree container, bool is_mod) + tree type, tree container, bool is_attached) { const char *kind = "new"; tree existing = NULL_TREE; @@ -10792,14 +10800,15 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, } } } - else if (is_mod && !(state->is_module () || state->is_partition ())) + else if (is_attached + && !(state->is_module () || state->is_partition ())) kind = "unique"; else { gcc_checking_assert (mk == MK_named || mk == MK_enum); tree mvec; tree *vslot = mergeable_namespace_slots (container, name, - !is_mod, &mvec); + is_attached, &mvec); existing = check_mergeable_decl (mk, decl, *vslot, key); if (!existing) add_mergeable_namespace_entity (vslot, decl); @@ -10807,7 +10816,7 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, { /* Note that we now have duplicates to deal with in name lookup. */ - if (is_mod) + if (is_attached) BINDING_VECTOR_PARTITION_DUPS_P (mvec) = true; else BINDING_VECTOR_GLOBAL_DUPS_P (mvec) = true; @@ -10824,7 +10833,7 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, break; case TYPE_DECL: - if (is_mod && !(state->is_module () || state->is_partition ()) + if (is_attached && !(state->is_module () || state->is_partition ()) /* Implicit member functions can come from anywhere. */ && !(DECL_ARTIFICIAL (decl) @@ -18389,14 +18398,11 @@ get_originating_module (tree decl, bool for_mangle) if (!DECL_LANG_SPECIFIC (not_tmpl)) return for_mangle ? -1 : 0; - if (for_mangle && !DECL_MODULE_PURVIEW_P (not_tmpl)) + if (for_mangle && !DECL_MODULE_ATTACH_P (not_tmpl)) return -1; int mod = !DECL_MODULE_IMPORT_P (not_tmpl) ? 0 : get_importing_module (owner); - - if (for_mangle && (*modules)[mod]->is_header ()) - return -1; - + gcc_checking_assert (!for_mangle || !(*modules)[mod]->is_header ()); return mod; } @@ -18416,9 +18422,34 @@ get_importing_module (tree decl, bool flexible) bool module_may_redeclare (tree decl) { + for (;;) + { + tree ctx = CP_DECL_CONTEXT (decl); + if (TREE_CODE (ctx) == NAMESPACE_DECL) + // Found the namespace-scope decl. + break; + if (!CLASS_TYPE_P (ctx)) + // We've met a non-class scope. Such a thing is not + // reopenable, so we must be ok. + return true; + decl = TYPE_NAME (ctx); + } + + tree not_tmpl = STRIP_TEMPLATE (decl); + + int use_tpl = 0; + if (node_template_info (not_tmpl, use_tpl) && use_tpl) + // Specializations of any kind can be redeclared anywhere. + // FIXME: Should we be checking this in more places on the scope chain? + return true; + + if (!DECL_LANG_SPECIFIC (not_tmpl) || !DECL_MODULE_ATTACH_P (not_tmpl)) + // Decl is attached to global module. Current scope needs to be too. + return !module_attach_p (); + module_state *me = (*modules)[0]; module_state *them = me; - tree not_tmpl = STRIP_TEMPLATE (decl); + if (DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_IMPORT_P (not_tmpl)) { /* We can be given the TEMPLATE_RESULT. We want the @@ -18446,30 +18477,14 @@ module_may_redeclare (tree decl) them = import_entity_module (index); } - if (them->is_header ()) - { - if (!header_module_p ()) - return !module_purview_p (); - - if (DECL_SOURCE_LOCATION (decl) == BUILTINS_LOCATION) - /* This is a builtin, being declared in header-unit. We - now need to mark it as an export. */ - DECL_MODULE_EXPORT_P (decl) = true; - - /* If it came from a header, it's in the global module. */ - return true; - } + // Decl is attached to named module. Current scope needs to be + // attaching to the same module. + if (!module_attach_p ()) + return false; + // Both attached to named module. if (me == them) - return ((DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_PURVIEW_P (not_tmpl)) - == module_purview_p ()); - - if (!me->name) - me = me->parent; - - /* We can't have found a GMF entity from a named module. */ - gcc_checking_assert (DECL_LANG_SPECIFIC (not_tmpl) - && DECL_MODULE_PURVIEW_P (not_tmpl)); + return true; return me && get_primary (them) == get_primary (me); } @@ -18554,11 +18569,17 @@ set_originating_module (tree decl, bool friend_p ATTRIBUTE_UNUSED) { set_instantiating_module (decl); - if (TREE_CODE (CP_DECL_CONTEXT (decl)) != NAMESPACE_DECL) + if (!DECL_NAMESPACE_SCOPE_P (decl)) return; gcc_checking_assert (friend_p || decl == get_originating_module_decl (decl)); + if (module_attach_p ()) + { + retrofit_lang_decl (decl); + DECL_MODULE_ATTACH_P (decl) = true; + } + if (!module_exporting_p ()) return; diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index a05244d..6bed9da 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -3493,11 +3493,13 @@ maybe_record_mergeable_decl (tree *slot, tree name, tree decl) /* Internal linkage. */ return; - bool partition = named_module_p (); + bool is_attached = (DECL_LANG_SPECIFIC (not_tmpl) + && DECL_MODULE_ATTACH_P (not_tmpl)); tree *gslot = get_fixed_binding_slot - (slot, name, partition ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, true); + (slot, name, is_attached ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, + true); - if (!partition) + if (!is_attached) { binding_slot &orig = BINDING_VECTOR_CLUSTER (*slot, 0).slots[BINDING_SLOT_CURRENT]; @@ -3841,11 +3843,12 @@ pushdecl (tree decl, bool hiding) GMF slot or a module-specific one. */ tree * -mergeable_namespace_slots (tree ns, tree name, bool is_global, tree *vec) +mergeable_namespace_slots (tree ns, tree name, bool is_attached, tree *vec) { tree *mslot = find_namespace_slot (ns, name, true); tree *vslot = get_fixed_binding_slot - (mslot, name, is_global ? BINDING_SLOT_GLOBAL : BINDING_SLOT_PARTITION, true); + (mslot, name, is_attached ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, + true); gcc_checking_assert (TREE_CODE (*mslot) == BINDING_VECTOR); *vec = *mslot; @@ -4832,10 +4835,10 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, if (exporting) { /* If the using decl is exported, the things it refers - to must also be exported (or not in module purview). */ + to must also be exported (or not habve module attachment). */ if (!DECL_MODULE_EXPORT_P (new_fn) && (DECL_LANG_SPECIFIC (new_fn) - && DECL_MODULE_PURVIEW_P (new_fn))) + && DECL_MODULE_ATTACH_P (new_fn))) { error ("%q#D does not have external linkage", new_fn); inform (DECL_SOURCE_LOCATION (new_fn), diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index fa03902..999db33 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -471,7 +471,7 @@ extern void pop_from_top_level (void); extern void push_using_decl_bindings (tree, tree); /* Lower level interface for modules. */ -extern tree *mergeable_namespace_slots (tree ns, tree name, bool is_global, +extern tree *mergeable_namespace_slots (tree ns, tree name, bool is_attached, tree *mvec); extern void add_mergeable_namespace_entity (tree *slot, tree decl); extern tree lookup_class_binding (tree ctx, tree name); diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc index 540f1e4..53ce06c 100644 --- a/gcc/cp/ptree.cc +++ b/gcc/cp/ptree.cc @@ -79,12 +79,22 @@ cxx_print_decl (FILE *file, tree node, int indent) need_indent = false; } - if (DECL_LANG_SPECIFIC (ntnode) && DECL_MODULE_PURVIEW_P (ntnode)) + if (DECL_LANG_SPECIFIC (ntnode)) { - if (need_indent) - indent_to (file, indent + 3); - fprintf (file, " purview"); - need_indent = false; + if (DECL_MODULE_PURVIEW_P (ntnode)) + { + if (need_indent) + indent_to (file, indent + 3); + fprintf (file, " purview"); + need_indent = false; + } + if (DECL_MODULE_ATTACH_P (ntnode)) + { + if (need_indent) + indent_to (file, indent + 3); + fprintf (file, " attached"); + need_indent = false; + } } } -- 2.7.4