aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/module.cc')
-rw-r--r--gcc/cp/module.cc636
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