diff options
Diffstat (limited to 'gcc/cp/module.cc')
| -rw-r--r-- | gcc/cp/module.cc | 636 |
1 files changed, 485 insertions, 151 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index e0b9efa..5c70e9b 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2365,10 +2365,11 @@ private: DB_KIND_BITS = EK_BITS, DB_DEFN_BIT = DB_KIND_BIT + DB_KIND_BITS, DB_IS_PENDING_BIT, /* Is a maybe-pending entity. */ - DB_TU_LOCAL_BIT, /* It is a TU-local entity. */ - DB_REFS_TU_LOCAL_BIT, /* Refers to a TU-local entity (but is not - necessarily an exposure.) */ - DB_EXPOSURE_BIT, /* Exposes a TU-local entity. */ + DB_TU_LOCAL_BIT, /* Is a TU-local entity. */ + DB_REF_GLOBAL_BIT, /* Refers to a GMF TU-local entity. */ + DB_REF_PURVIEW_BIT, /* Refers to a purview TU-local entity. */ + DB_EXPOSE_GLOBAL_BIT, /* Exposes a GMF TU-local entity. */ + DB_EXPOSE_PURVIEW_BIT, /* Exposes a purview TU-local entity. */ DB_IMPORTED_BIT, /* An imported entity. */ DB_UNREACHED_BIT, /* A yet-to-be reached entity. */ DB_MAYBE_RECURSIVE_BIT, /* An entity maybe in a recursive cluster. */ @@ -2458,19 +2459,40 @@ public: || (get_entity_kind () == EK_DECL && get_flag_bit<DB_IS_PENDING_BIT> ())); } + public: - bool is_tu_local () const + /* Only consider global module entities as being TU-local + when STRICT is set; otherwise, as an extension we support + emitting declarations referencing TU-local GMF entities + (and only check purview entities), to assist in migration. */ + bool is_tu_local (bool strict = false) const { - return get_flag_bit<DB_TU_LOCAL_BIT> (); + /* Non-strict is only intended for migration purposes, so + for simplicity's sake we only care about whether this is + a non-purview variable or function at namespace scope; + these are the most common cases (coming from C), and + that way we don't have to care about diagnostics for + nested types and so forth. */ + tree inner = STRIP_TEMPLATE (get_entity ()); + return (get_flag_bit<DB_TU_LOCAL_BIT> () + && (strict + || !VAR_OR_FUNCTION_DECL_P (inner) + || !NAMESPACE_SCOPE_P (inner) + || (DECL_LANG_SPECIFIC (inner) + && DECL_MODULE_PURVIEW_P (inner)))); } - bool refs_tu_local () const + bool refs_tu_local (bool strict = false) const { - return get_flag_bit<DB_REFS_TU_LOCAL_BIT> (); + return (get_flag_bit<DB_REF_PURVIEW_BIT> () + || (strict && get_flag_bit <DB_REF_GLOBAL_BIT> ())); } - bool is_exposure () const + bool is_exposure (bool strict = false) const { - return get_flag_bit<DB_EXPOSURE_BIT> (); + return (get_flag_bit<DB_EXPOSE_PURVIEW_BIT> () + || (strict && get_flag_bit <DB_EXPOSE_GLOBAL_BIT> ())); } + +public: bool is_import () const { return get_flag_bit<DB_IMPORTED_BIT> (); @@ -2642,11 +2664,6 @@ public: void add_namespace_context (depset *, tree ns); private: - bool has_tu_local_tmpl_arg (tree decl, tree args, bool explain); - bool is_tu_local_entity (tree decl, bool explain = false); - bool is_tu_local_value (tree decl, tree expr, bool explain = false); - - private: static bool add_binding_entity (tree, WMB_Flags, void *); public: @@ -2662,6 +2679,10 @@ public: void find_dependencies (module_state *); bool finalize_dependencies (); vec<depset *> connect (); + + private: + bool diagnose_bad_internal_ref (depset *dep, bool strict = false); + bool diagnose_template_names_tu_local (depset *dep, bool strict = false); }; public: @@ -3850,7 +3871,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state { private: void write_config (elf_out *to, struct module_state_config &, unsigned crc); - bool read_config (struct module_state_config &); + bool read_config (struct module_state_config &, bool = true); static void write_counts (elf_out *to, unsigned [MSC_HWM], unsigned *crc_ptr); bool read_counts (unsigned *); @@ -3877,6 +3898,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state { unsigned write_cluster (elf_out *to, depset *depsets[], unsigned size, depset::hash &, unsigned *counts, unsigned *crc_ptr); bool read_cluster (unsigned snum); + bool open_slurp (cpp_reader *); private: unsigned write_inits (elf_out *to, depset::hash &, unsigned *crc_ptr); @@ -3938,6 +3960,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state { public: void set_filename (const Cody::Packet &); bool do_import (cpp_reader *, bool outermost); + bool check_importable (cpp_reader *); }; /* Hash module state by name. This cannot be a member of @@ -4918,8 +4941,13 @@ maybe_add_cmi_prefix (const char *to, size_t *len_p = NULL) static void create_dirs (char *path) { + char *base = path; + /* Skip past initial slashes of absolute path. */ + while (IS_DIR_SEPARATOR (*base)) + base++; + /* Try and create the missing directories. */ - for (char *base = path; *base; base++) + for (; *base; base++) if (IS_DIR_SEPARATOR (*base)) { char sep = *base; @@ -6214,11 +6242,6 @@ trees_out::lang_type_bools (tree t, bits_out& bits) gcc_checking_assert (!lang->erroneous); WB (lang->non_pod_aggregate); WB (lang->non_aggregate_pod); - WB (lang->trivially_relocatable); - WB (lang->trivially_relocatable_computed); - - WB (lang->replaceable); - WB (lang->replaceable_computed); #undef WB } @@ -6292,11 +6315,6 @@ trees_in::lang_type_bools (tree t, bits_in& bits) gcc_checking_assert (!lang->erroneous); RB (lang->non_pod_aggregate); RB (lang->non_aggregate_pod); - RB (lang->trivially_relocatable); - RB (lang->trivially_relocatable_computed); - - RB (lang->replaceable); - RB (lang->replaceable_computed); #undef RB return !get_overrun (); } @@ -6442,13 +6460,19 @@ trees_out::core_vals (tree t) if (has_warning_spec (t)) u (get_warning_spec (t)); - /* Walk in forward order, as (for instance) REQUIRES_EXPR has a - bunch of unscoped parms on its first operand. It's safer to - create those in order. */ bool vl = TREE_CODE_CLASS (code) == tcc_vl_exp; - for (unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t) - : TREE_OPERAND_LENGTH (t)), - ix = unsigned (vl); ix != limit; ix++) + unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t) + : TREE_OPERAND_LENGTH (t)); + unsigned ix = unsigned (vl); + if (code == REQUIRES_EXPR) + { + /* The first operand of a REQUIRES_EXPR is a tree chain + of PARM_DECLs. We need to stream this separately as + otherwise we would only stream the first one. */ + chained_decls (REQUIRES_EXPR_PARMS (t)); + ++ix; + } + for (; ix != limit; ix++) WT (TREE_OPERAND (t, ix)); } else @@ -7027,9 +7051,15 @@ trees_in::core_vals (tree t) put_warning_spec (t, u ()); bool vl = TREE_CODE_CLASS (code) == tcc_vl_exp; - for (unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t) - : TREE_OPERAND_LENGTH (t)), - ix = unsigned (vl); ix != limit; ix++) + unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t) + : TREE_OPERAND_LENGTH (t)); + unsigned ix = unsigned (vl); + if (code == REQUIRES_EXPR) + { + REQUIRES_EXPR_PARMS (t) = chained_decls (); + ++ix; + } + for (; ix != limit; ix++) RTU (TREE_OPERAND (t, ix)); } @@ -7494,6 +7524,12 @@ trees_out::lang_decl_vals (tree t) WT (access); } + /* A friend template specialisation stashes its owning class on its + DECL_CHAIN; we need to reconstruct this, but it needs to happen + after we stream the template_info so readers can know this is such + an entity. */ + if (decl_specialization_friend_p (t)) + WT (t->common.chain); break; case lds_ns: /* lang_decl_ns. */ @@ -7563,6 +7599,8 @@ trees_in::lang_decl_vals (tree t) lds_min: RT (lang->u.min.template_info); RT (lang->u.min.access); + if (decl_specialization_friend_p (t)) + RT (t->common.chain); break; case lds_ns: /* lang_decl_ns. */ @@ -8996,11 +9034,14 @@ trees_in::decl_value () dump (dumper::TREE) && dump ("CDTOR %N is %scloned", decl, cloned_p ? "" : "not "); if (cloned_p) - build_cdtor_clones (decl, flags & 2, flags & 4, - /* Update the member vec, if there is - one (we're in a different cluster - to the class defn). */ - CLASSTYPE_MEMBER_VEC (DECL_CONTEXT (decl))); + { + /* Update the member vec, if there is one (we're in a different + cluster to the class defn) and this isn't a primary template + specialization (as in tsubst_function_decl). */ + bool up = (CLASSTYPE_MEMBER_VEC (DECL_CONTEXT (decl)) + && !primary_template_specialization_p (decl)); + build_cdtor_clones (decl, flags & 2, flags & 4, up); + } } } @@ -10179,9 +10220,10 @@ trees_out::tree_node (tree t) break; case PARM_DECL: - /* REQUIRES_EXPRs have a tree list of uncontexted - PARM_DECLS. It'd be nice if they had a - distinguishing flag to double check. */ + /* REQUIRES_EXPRs have a chain of uncontexted PARM_DECLS, + and an implicit this parm in an NSDMI has no context. */ + gcc_checking_assert (CONSTRAINT_VAR_P (t) + || DECL_NAME (t) == this_identifier); break; case TYPE_DECL: @@ -11478,7 +11520,8 @@ trees_out::get_merge_kind (tree decl, depset *dep) } if (TREE_CODE (decl) == TEMPLATE_DECL - && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) + ? DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl) + : decl_specialization_friend_p (decl)) { mk = MK_local_friend; break; @@ -11554,7 +11597,8 @@ trees_out::decl_container (tree decl) tree container = NULL_TREE; if (TREE_CODE (decl) == TEMPLATE_DECL - && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) + ? DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl) + : decl_specialization_friend_p (decl)) container = DECL_CHAIN (decl); else container = CP_DECL_CONTEXT (decl); @@ -11737,7 +11781,8 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, case MK_local_friend: { - /* Find by index on the class's DECL_LIST */ + /* Find by index on the class's DECL_LIST. We set TREE_CHAIN to + point to the class in push_template_decl or grokfndecl. */ unsigned ix = 0; for (tree decls = CLASSTYPE_DECL_LIST (TREE_CHAIN (decl)); decls; decls = TREE_CHAIN (decls)) @@ -12895,6 +12940,16 @@ trees_out::write_function_def (tree decl) && (get_importer_interface (decl) != importer_interface::external)); + /* Make sure DECL_REALLY_EXTERN and DECL_INTERFACE_KNOWN are consistent + on non-templates or we'll crash later in import_export_decl. */ + gcc_checking_assert (flags || DECL_INTERFACE_KNOWN (decl) + || (DECL_LANG_SPECIFIC (decl) + && DECL_LOCAL_DECL_P (decl) + && DECL_OMP_DECLARE_REDUCTION_P (decl)) + || (DECL_LANG_SPECIFIC (decl) + && DECL_TEMPLATE_INFO (decl) + && uses_template_parms (DECL_TI_ARGS (decl)))); + if (f) { flags |= 2; @@ -12971,7 +13026,13 @@ trees_in::read_function_def (tree decl, tree maybe_template) SET_DECL_FRIEND_CONTEXT (decl, context); if (cexpr.decl) register_constexpr_fundef (cexpr); - post_process (pdata); + + if (DECL_LOCAL_DECL_P (decl)) + /* Block-scope OMP UDRs aren't real functions, and don't need a + function structure to be allocated or to be expanded. */ + gcc_checking_assert (DECL_OMP_DECLARE_REDUCTION_P (decl)); + else + post_process (pdata); } else if (maybe_dup) { @@ -13048,8 +13109,10 @@ trees_in::read_var_def (tree decl, tree maybe_template) if (DECL_EXPLICIT_INSTANTIATION (decl) && !DECL_EXTERNAL (decl)) setup_explicit_instantiation_definition_linkage (decl); - /* Class static data members are handled in read_class_def. */ - if (!DECL_CLASS_SCOPE_P (decl) + /* Class non-template static members are handled in read_class_def. + But still handle specialisations of member templates. */ + if ((!DECL_CLASS_SCOPE_P (decl) + || primary_template_specialization_p (decl)) && (DECL_IMPLICIT_INSTANTIATION (decl) || (DECL_EXPLICIT_INSTANTIATION (decl) && !DECL_EXTERNAL (decl)))) @@ -13905,11 +13968,15 @@ depset::hash::find_binding (tree ctx, tree name) return slot ? *slot : NULL; } +static bool is_tu_local_entity (tree decl, bool explain = false); +static bool is_tu_local_value (tree decl, tree expr, bool explain = false); +static bool has_tu_local_tmpl_arg (tree decl, tree args, bool explain); + /* Returns true if DECL is a TU-local entity, as defined by [basic.link]. If EXPLAIN is true, emit an informative note about why DECL is TU-local. */ -bool -depset::hash::is_tu_local_entity (tree decl, bool explain/*=false*/) +static bool +is_tu_local_entity (tree decl, bool explain/*=false*/) { gcc_checking_assert (DECL_P (decl)); location_t loc = DECL_SOURCE_LOCATION (decl); @@ -14075,8 +14142,8 @@ depset::hash::is_tu_local_entity (tree decl, bool explain/*=false*/) /* Helper for is_tu_local_entity. Returns true if one of the ARGS of DECL is TU-local. Emits an explanation if EXPLAIN is true. */ -bool -depset::hash::has_tu_local_tmpl_arg (tree decl, tree args, bool explain) +static bool +has_tu_local_tmpl_arg (tree decl, tree args, bool explain) { if (!args || TREE_CODE (args) != TREE_VEC) return false; @@ -14125,8 +14192,8 @@ depset::hash::has_tu_local_tmpl_arg (tree decl, tree args, bool explain) /* Returns true if EXPR (part of the initializer for DECL) is a TU-local value or object. Emits an explanation if EXPLAIN is true. */ -bool -depset::hash::is_tu_local_value (tree decl, tree expr, bool explain) +static bool +is_tu_local_value (tree decl, tree expr, bool explain/*=false*/) { if (!expr) return false; @@ -14179,6 +14246,63 @@ depset::hash::is_tu_local_value (tree decl, tree expr, bool explain) return false; } +/* Complains if DECL is a TU-local entity imported from a named module. + Returns TRUE if instantiation should fail. */ + +bool +instantiating_tu_local_entity (tree decl) +{ + if (!modules_p ()) + return false; + + if (TREE_CODE (decl) == TU_LOCAL_ENTITY) + { + auto_diagnostic_group d; + error ("instantiation exposes TU-local entity %qD", + TU_LOCAL_ENTITY_NAME (decl)); + inform (TU_LOCAL_ENTITY_LOCATION (decl), "declared here"); + return true; + } + + /* Currently, only TU-local variables and functions, or possibly + templates thereof, will be emitted from named modules. */ + tree inner = STRIP_TEMPLATE (decl); + if (!VAR_OR_FUNCTION_DECL_P (inner)) + return false; + + /* From this point we will only be emitting warnings; if we're not + warning about this case then there's no need to check further. */ + if (!warn_expose_global_module_tu_local + || !warning_enabled_at (DECL_SOURCE_LOCATION (decl), + OPT_Wexpose_global_module_tu_local)) + return false; + + if (!is_tu_local_entity (decl)) + return false; + + if (!DECL_LANG_SPECIFIC (inner) + || !DECL_MODULE_IMPORT_P (inner)) + return false; + + /* Referencing TU-local entities from a header is generally OK. + We don't have an easy way to detect if this declaration came + from a header via a separate named module, but we can just + ignore that case for warning purposes. */ + unsigned index = import_entity_index (decl); + module_state *mod = import_entity_module (index); + if (mod->is_header ()) + return false; + + auto_diagnostic_group d; + warning (OPT_Wexpose_global_module_tu_local, + "instantiation exposes TU-local entity %qD", decl); + inform (DECL_SOURCE_LOCATION (decl), "declared here"); + + /* We treat TU-local entities from the GMF as not actually being + TU-local as an extension, so allow instantation to proceed. */ + return false; +} + /* DECL is a newly discovered dependency. Create the depset, if it doesn't already exist. Add it to the worklist if so. @@ -14332,8 +14456,14 @@ depset::hash::make_dependency (tree decl, entity_kind ek) if (DECL_DECLARED_CONSTEXPR_P (decl) || DECL_INLINE_VAR_P (decl)) /* A constexpr variable initialized to a TU-local value, - or an inline value (PR c++/119996), is an exposure. */ - dep->set_flag_bit<DB_EXPOSURE_BIT> (); + or an inline value (PR c++/119996), is an exposure. + + For simplicity, we don't support "non-strict" TU-local + values: even if the TU-local entity we refer to in the + initialiser is in the GMF, we still won't consider this + valid in constant expressions in other TUs, and so + complain accordingly. */ + dep->set_flag_bit<DB_EXPOSE_PURVIEW_BIT> (); } } @@ -14423,11 +14553,13 @@ depset::hash::make_dependency (tree decl, entity_kind ek) static bool is_exposure_of_member_type (depset *source, depset *ref) { - gcc_checking_assert (source->refs_tu_local () && ref->is_tu_local ()); + gcc_checking_assert (source->refs_tu_local (/*strict=*/true) + && ref->is_tu_local (/*strict=*/true)); tree source_entity = STRIP_TEMPLATE (source->get_entity ()); tree ref_entity = STRIP_TEMPLATE (ref->get_entity ()); - if (source_entity + if (!source->is_tu_local (/*strict=*/true) + && source_entity && ref_entity && DECL_IMPLICIT_TYPEDEF_P (source_entity) && DECL_IMPLICIT_TYPEDEF_P (ref_entity) @@ -14450,11 +14582,20 @@ depset::hash::add_dependency (depset *dep) gcc_checking_assert (current && !is_key_order ()); current->deps.safe_push (dep); - if (dep->is_tu_local ()) + if (dep->is_tu_local (/*strict=*/true)) { - current->set_flag_bit<DB_REFS_TU_LOCAL_BIT> (); + if (dep->is_tu_local ()) + current->set_flag_bit<DB_REF_PURVIEW_BIT> (); + else + current->set_flag_bit<DB_REF_GLOBAL_BIT> (); + if (!ignore_tu_local && !is_exposure_of_member_type (current, dep)) - current->set_flag_bit<DB_EXPOSURE_BIT> (); + { + if (dep->is_tu_local ()) + current->set_flag_bit<DB_EXPOSE_PURVIEW_BIT> (); + else + current->set_flag_bit<DB_EXPOSE_GLOBAL_BIT> (); + } } if (current->get_entity_kind () == EK_USING @@ -14578,7 +14719,7 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) return false; bool internal_decl = false; - if (!header_module_p () && data->hash->is_tu_local_entity (decl)) + if (!header_module_p () && is_tu_local_entity (decl)) { /* A TU-local entity. For ADL we still need to create bindings for internal-linkage functions attached to a named module. */ @@ -15339,6 +15480,128 @@ template_has_explicit_inst (tree tmpl) return false; } +/* Complain about DEP that exposes a TU-local entity. + + If STRICT, DEP only referenced entities from the GMF. Returns TRUE + if we explained anything. */ + +bool +depset::hash::diagnose_bad_internal_ref (depset *dep, bool strict) +{ + tree decl = dep->get_entity (); + + /* Don't need to walk if we're not going to be emitting + any diagnostics anyway. */ + if (strict && !warning_enabled_at (DECL_SOURCE_LOCATION (decl), + OPT_Wexpose_global_module_tu_local)) + return false; + + for (depset *rdep : dep->deps) + if (!rdep->is_binding () && rdep->is_tu_local (strict) + && !is_exposure_of_member_type (dep, rdep)) + { + // FIXME:QOI Better location information? We're + // losing, so it doesn't matter about efficiency. + tree exposed = rdep->get_entity (); + auto_diagnostic_group d; + if (strict) + { + /* Allow suppressing the warning from the point of declaration + of the otherwise-exposed decl, for cases we know that + exposures will never be 'bad'. */ + if (warning_enabled_at (DECL_SOURCE_LOCATION (exposed), + OPT_Wexpose_global_module_tu_local) + && pedwarn (DECL_SOURCE_LOCATION (decl), + OPT_Wexpose_global_module_tu_local, + "%qD exposes TU-local entity %qD", decl, exposed)) + { + bool informed = is_tu_local_entity (exposed, /*explain=*/true); + gcc_checking_assert (informed); + return true; + } + } + else + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qD exposes TU-local entity %qD", decl, exposed); + bool informed = is_tu_local_entity (exposed, /*explain=*/true); + gcc_checking_assert (informed); + if (dep->is_tu_local (/*strict=*/true)) + inform (DECL_SOURCE_LOCATION (decl), + "%qD is also TU-local but has been exposed elsewhere", + decl); + return true; + } + } + + return false; +} + +/* Warn about a template DEP that references a TU-local entity. + + If STRICT, DEP only referenced entities from the GMF. Returns TRUE + if we explained anything. */ + +bool +depset::hash::diagnose_template_names_tu_local (depset *dep, bool strict) +{ + tree decl = dep->get_entity (); + + /* Don't bother walking if we know we won't be emitting anything. */ + if (!warning_enabled_at (DECL_SOURCE_LOCATION (decl), + OPT_Wtemplate_names_tu_local) + /* Only warn strictly if users haven't silenced this warning here. */ + || (strict && !warning_enabled_at (DECL_SOURCE_LOCATION (decl), + OPT_Wexpose_global_module_tu_local))) + return false; + + /* Friend decls in a class body are ignored, but this is harmless: + it should not impact any consumers. */ + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))) + return false; + + /* We should now only be warning about templates. */ + gcc_checking_assert + (TREE_CODE (decl) == TEMPLATE_DECL + && VAR_OR_FUNCTION_DECL_P (DECL_TEMPLATE_RESULT (decl))); + + /* Don't warn if we've seen any explicit instantiation definitions, + the intent might be for importers to only use those. */ + if (template_has_explicit_inst (decl)) + return false; + + for (depset *rdep : dep->deps) + if (!rdep->is_binding () && rdep->is_tu_local (strict)) + { + tree ref = rdep->get_entity (); + auto_diagnostic_group d; + if (strict) + { + if (warning_enabled_at (DECL_SOURCE_LOCATION (ref), + OPT_Wexpose_global_module_tu_local) + && warning_at (DECL_SOURCE_LOCATION (decl), + OPT_Wtemplate_names_tu_local, + "%qD refers to TU-local entity %qD, which may " + "cause issues when instantiating in other TUs", + decl, ref)) + { + is_tu_local_entity (ref, /*explain=*/true); + return true; + } + } + else if (warning_at (DECL_SOURCE_LOCATION (decl), + OPT_Wtemplate_names_tu_local, + "%qD refers to TU-local entity %qD and cannot " + "be instantiated in other TUs", decl, ref)) + { + is_tu_local_entity (ref, /*explain=*/true); + return true; + } + } + + return false; +} + /* Sort the bindings, issue errors about bad internal refs. */ bool @@ -15363,30 +15626,21 @@ depset::hash::finalize_dependencies () if (CHECKING_P) for (depset *entity : dep->deps) gcc_checking_assert (!entity->is_import ()); + continue; } - else if (dep->is_exposure () && !dep->is_tu_local ()) - { - ok = false; - bool explained = false; - tree decl = dep->get_entity (); - for (depset *rdep : dep->deps) - if (!rdep->is_binding () - && rdep->is_tu_local () - && !is_exposure_of_member_type (dep, rdep)) - { - // FIXME:QOI Better location information? We're - // losing, so it doesn't matter about efficiency - tree exposed = rdep->get_entity (); - auto_diagnostic_group d; - error_at (DECL_SOURCE_LOCATION (decl), - "%qD exposes TU-local entity %qD", decl, exposed); - bool informed = is_tu_local_entity (exposed, /*explain=*/true); - gcc_checking_assert (informed); - explained = true; - break; - } + /* Otherwise, we'll check for bad internal refs. + Don't complain about any references from TU-local entities. */ + if (dep->is_tu_local ()) + continue; + if (dep->is_exposure ()) + { + bool explained = diagnose_bad_internal_ref (dep); + + /* A TU-local variable will always be considered an exposure, + so we don't have to worry about strict-only handling. */ + tree decl = dep->get_entity (); if (!explained && VAR_P (decl) && (DECL_DECLARED_CONSTEXPR_P (decl) @@ -15411,42 +15665,34 @@ depset::hash::finalize_dependencies () explained = true; } - /* We should have emitted an error above. */ + /* We should have emitted an error above, unless the warning was + silenced. */ gcc_checking_assert (explained); + ok = false; + continue; } - else if (warn_template_names_tu_local - && dep->refs_tu_local () && !dep->is_tu_local ()) - { - tree decl = dep->get_entity (); - /* Friend decls in a class body are ignored, but this is harmless: - it should not impact any consumers. */ - if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))) - continue; - - /* We should now only be warning about templates. */ - gcc_checking_assert - (TREE_CODE (decl) == TEMPLATE_DECL - && VAR_OR_FUNCTION_DECL_P (DECL_TEMPLATE_RESULT (decl))); + /* In all other cases, we're just warning (rather than erroring). + We don't want to do too much warning, so let's just bail after + the first warning we successfully emit. */ + if (warn_expose_global_module_tu_local + && !dep->is_tu_local (/*strict=*/true) + && dep->is_exposure (/*strict=*/true) + && diagnose_bad_internal_ref (dep, /*strict=*/true)) + continue; - /* Don't warn if we've seen any explicit instantiation definitions, - the intent might be for importers to only use those. */ - if (template_has_explicit_inst (decl)) - continue; + if (warn_template_names_tu_local + && dep->refs_tu_local () + && diagnose_template_names_tu_local (dep)) + continue; - for (depset *rdep : dep->deps) - if (!rdep->is_binding () && rdep->is_tu_local ()) - { - tree ref = rdep->get_entity (); - auto_diagnostic_group d; - if (warning_at (DECL_SOURCE_LOCATION (decl), - OPT_Wtemplate_names_tu_local, - "%qD refers to TU-local entity %qD and cannot " - "be instantiated in other TUs", decl, ref)) - is_tu_local_entity (ref, /*explain=*/true); - break; - } - } + if (warn_template_names_tu_local + && warn_expose_global_module_tu_local + && !dep->is_tu_local (/*strict=*/true) + && dep->refs_tu_local (/*strict=*/true) + && !dep->is_exposure (/*strict=*/true) + && diagnose_template_names_tu_local (dep, /*strict=*/true)) + continue; } return ok; @@ -16101,6 +16347,9 @@ mangle_module (int mod, bool include_partition) /* Set when importing the primary module interface. */ imp = imp->parent; + /* Ensure this is actually a module unit. */ + gcc_checking_assert (imp); + imp->mangle (include_partition); } @@ -17149,11 +17398,7 @@ module_state::read_cluster (unsigned snum) } } - /* Look, function.cc's interface to cfun does too much for us, we - just need to restore the old value. I do not want to go - redesigning that API right now. */ -#undef cfun - cfun = old_cfun; + set_cfun (old_cfun); current_function_decl = old_cfd; comparing_dependent_aliases--; @@ -17246,13 +17491,16 @@ module_state::write_namespaces (elf_out *to, vec<depset *> spaces, flags |= 4; if (DECL_MODULE_EXPORT_P (ns)) flags |= 8; + if (TREE_DEPRECATED (ns)) + flags |= 16; dump () && dump ("Writing namespace:%u %N%s%s%s%s", b->cluster, ns, flags & 1 ? ", public" : "", flags & 2 ? ", inline" : "", flags & 4 ? ", purview" : "", - flags & 8 ? ", export" : ""); + flags & 8 ? ", export" : "", + flags & 16 ? ", deprecated" : ""); sec.u (b->cluster); sec.u (to->name (DECL_NAME (ns))); write_namespace (sec, b->deps[0]); @@ -17328,7 +17576,8 @@ module_state::read_namespaces (unsigned num) flags & 1 ? ", public" : "", flags & 2 ? ", inline" : "", flags & 4 ? ", purview" : "", - flags & 8 ? ", export" : ""); + flags & 8 ? ", export" : "", + flags & 16 ? ", deprecated" : ""); bool visible_p = ((flags & 8) || ((flags & 1) && (flags & 4) @@ -17349,6 +17598,9 @@ module_state::read_namespaces (unsigned num) DECL_MODULE_EXPORT_P (inner) = true; } + if (flags & 16) + TREE_DEPRECATED (inner) = true; + if (tags) DECL_ATTRIBUTES (inner) = tree_cons (get_identifier ("abi_tag"), tags, DECL_ATTRIBUTES (inner)); @@ -17395,7 +17647,16 @@ module_state::write_using_directives (elf_out *to, depset::hash &table, bool exported = DECL_MODULE_EXPORT_P (udir); tree target = USING_DECL_DECLS (udir); depset *target_dep = table.find_dependency (target); - gcc_checking_assert (target_dep); + + /* An using-directive imported from a different module might not + have been walked earlier (PR c++/122915). But importers will + be able to just refer to the decl in that module unless it was + a partition anyway, so we don't have anything to do here. */ + if (!target_dep) + { + gcc_checking_assert (DECL_MODULE_IMPORT_P (udir)); + continue; + } dump () && dump ("Writing using-directive in %N for %N", parent, target); @@ -17444,7 +17705,7 @@ module_state::read_using_directives (unsigned num) dump () && dump ("Read using-directive in %N for %N", parent, target); if (exported || is_module () || is_partition ()) - add_using_namespace (parent, target); + add_imported_using_namespace (parent, target); } dump.outdent (); @@ -19876,7 +20137,7 @@ post_load_processing () DECL_EXTERNAL (decl) = false; } - cfun = old_cfun; + set_cfun (old_cfun); current_function_decl = old_cfd; } @@ -20074,7 +20335,7 @@ module_state::note_cmi_name () } bool -module_state::read_config (module_state_config &config) +module_state::read_config (module_state_config &config, bool complain) { bytes_in cfg; @@ -20103,7 +20364,9 @@ module_state::read_config (module_state_config &config) /* The 'I know what I'm doing' switch. */ && !flag_module_version_ignore); bool inform_p = true; - if (reject_p) + if (!complain) + inform_p = false; + else if (reject_p) { cfg.set_overrun (); error_at (loc, "compiled module is %sversion %s", @@ -20163,7 +20426,9 @@ module_state::read_config (module_state_config &config) unsigned e_crc = crc; crc = cfg.get_crc (); dump () && dump ("Reading CRC=%x", crc); - if (!is_direct () && crc != e_crc) + /* When not complaining we haven't set directness yet, so ignore the + mismatch. */ + if (complain && !is_direct () && crc != e_crc) { error_at (loc, "module %qs CRC mismatch", get_flatname ()); cfg.set_overrun (); @@ -20191,8 +20456,9 @@ module_state::read_config (module_state_config &config) const char *their_dialect = cfg.str (); if (strcmp (their_dialect, config.dialect_str)) { - error_at (loc, "language dialect differs %qs, expected %qs", - their_dialect, config.dialect_str); + if (complain) + error_at (loc, "language dialect differs %qs, expected %qs", + their_dialect, config.dialect_str); cfg.set_overrun (); goto done; } @@ -20606,9 +20872,6 @@ module_state::read_initial (cpp_reader *reader) module_state_config config; bool ok = true; - if (ok && !from ()->begin (loc)) - ok = false; - if (ok && !read_config (config)) ok = false; @@ -21584,6 +21847,42 @@ propagate_defining_module (tree decl, tree orig) } } +/* NEWDECL matched with OLDDECL, transfer defining module information + onto OLDDECL. We've already validated attachment matches. */ + +void +transfer_defining_module (tree olddecl, tree newdecl) +{ + if (!modules_p ()) + return; + + tree old_inner = STRIP_TEMPLATE (olddecl); + tree new_inner = STRIP_TEMPLATE (newdecl); + + if (DECL_LANG_SPECIFIC (new_inner)) + { + gcc_checking_assert (DECL_LANG_SPECIFIC (old_inner)); + if (DECL_MODULE_PURVIEW_P (new_inner)) + DECL_MODULE_PURVIEW_P (old_inner) = true; + if (!DECL_MODULE_IMPORT_P (new_inner)) + DECL_MODULE_IMPORT_P (old_inner) = false; + } + + if (tree *p = imported_temploid_friends->get (newdecl)) + { + tree orig = *p; + tree &slot = imported_temploid_friends->get_or_insert (olddecl); + if (!slot) + slot = orig; + else if (slot != orig) + /* This can happen when multiple classes declare the same + friend function (e.g. g++.dg/modules/tpl-friend-4); + make sure we at least attach to the same module. */ + gcc_checking_assert (get_originating_module (slot) + == get_originating_module (orig)); + } +} + /* DECL is being freed, clear data we don't need anymore. */ void @@ -21650,20 +21949,14 @@ module_state::set_flatname () flatname = IDENTIFIER_POINTER (name); } -/* Read the CMI file for a module. */ +/* Open the GCM file and prepare to read. Return whether that was + successful. */ bool -module_state::do_import (cpp_reader *reader, bool outermost) +module_state::open_slurp (cpp_reader *reader) { - gcc_assert (global_namespace == current_scope () && loadedness == ML_NONE); - - /* If this TU is a partition of the module we're importing, - that module is the primary module interface. */ - if (this_module ()->is_partition () - && this == get_primary (this_module ())) - module_p = true; - - loc = linemap_module_loc (line_table, loc, get_flatname ()); + if (slurp) + return true; if (lazy_open >= lazy_limit) freeze_an_elf (); @@ -21686,14 +21979,50 @@ module_state::do_import (cpp_reader *reader, bool outermost) gcc_checking_assert (!slurp); slurp = new slurping (new elf_in (fd, e)); - bool ok = true; + bool ok = from ()->begin (loc); + if (ok) + { + lazy_open++; + slurp->lru = ++lazy_lru; + } + return ok; +} + +/* Return whether importing this GCM would work without an error in + read_config. */ + +bool +module_state::check_importable (cpp_reader *reader) +{ + if (loadedness > ML_CONFIG) + return true; + if (!open_slurp (reader)) + return false; + module_state_config config; + return read_config (config, /*complain*/false); +} + +/* Read the CMI file for a module. */ + +bool +module_state::do_import (cpp_reader *reader, bool outermost) +{ + gcc_assert (global_namespace == current_scope () && loadedness == ML_NONE); + + /* If this TU is a partition of the module we're importing, + that module is the primary module interface. */ + if (this_module ()->is_partition () + && this == get_primary (this_module ())) + module_p = true; + + loc = linemap_module_loc (line_table, loc, get_flatname ()); + + bool ok = open_slurp (reader); if (!from ()->get_error ()) { announce ("importing"); loadedness = ML_CONFIG; - lazy_open++; ok = read_initial (reader); - slurp->lru = ++lazy_lru; } gcc_assert (slurp->current == ~0u); @@ -22235,7 +22564,7 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, auto packet = mapper->IncludeTranslate (path, Cody::Flags::None, len); enum class xlate_kind { - unknown, text, import, + unknown, text, import, invalid } translate = xlate_kind::unknown; if (packet.GetCode () == Cody::Client::PC_BOOL) @@ -22246,7 +22575,10 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, We may already know about this import, but libcpp doesn't yet. */ module_state *import = get_module (build_string (len, path)); import->set_filename (packet); - translate = xlate_kind::import; + if (import->check_importable (reader)) + translate = xlate_kind::import; + else + translate = xlate_kind::invalid; } else { @@ -22255,7 +22587,7 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, path, packet.GetString ().c_str ()); } - bool note = false; + bool note = (translate == xlate_kind::invalid); if (note_include_translate_yes && translate == xlate_kind::import) note = true; else if (note_include_translate_no && translate == xlate_kind::unknown) @@ -22270,6 +22602,8 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, if (note) inform (loc, translate == xlate_kind::import ? G_("include %qs translated to import") + : translate == xlate_kind::invalid + ? G_("import of %qs failed, falling back to include") : G_("include %qs processed textually"), path); dump () && dump (translate == xlate_kind::import |
