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.cc366
1 files changed, 285 insertions, 81 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index e9cacf1..0610ee5 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:
@@ -13908,11 +13929,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);
@@ -14078,8 +14103,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;
@@ -14128,8 +14153,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;
@@ -14182,6 +14207,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 will be emitted
+ from named modules. */
+ if (!VAR_OR_FUNCTION_DECL_P (decl))
+ 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;
+
+ tree origin = get_originating_module_decl (decl);
+ if (!DECL_LANG_SPECIFIC (origin)
+ || !DECL_MODULE_IMPORT_P (origin))
+ 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 (origin);
+ 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.
@@ -14335,8 +14417,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> ();
}
}
@@ -14426,11 +14514,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)
@@ -14453,11 +14543,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
@@ -14581,7 +14680,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. */
@@ -15342,6 +15441,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
@@ -15366,30 +15587,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)
@@ -15414,42 +15626,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;