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.cc550
1 files changed, 480 insertions, 70 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index e778262..c8e79f3 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2811,12 +2811,13 @@ enum tree_tag {
tt_decl, /* By-value mergeable decl. */
tt_tpl_parm, /* Template parm. */
- /* The ordering of the following 4 is relied upon in
+ /* The ordering of the following 5 is relied upon in
trees_out::tree_node. */
tt_id, /* Identifier node. */
tt_conv_id, /* Conversion operator name. */
tt_anon_id, /* Anonymous name. */
tt_lambda_id, /* Lambda name. */
+ tt_internal_id, /* Internal name. */
tt_typedef_type, /* A (possibly implicit) typedefed type. */
tt_derived_type, /* A type derived from another type. */
@@ -3096,6 +3097,9 @@ private:
unsigned section;
bool writing_local_entities; /* Whether we might walk into a TU-local
entity we need to emit placeholders for. */
+ bool walking_bit_field_unit; /* Whether we're walking the underlying
+ storage for a bit field. There's no other
+ great way to detect this. */
#if CHECKING_P
int importedness; /* Checker that imports not occurring
inappropriately. +ve imports ok,
@@ -3262,7 +3266,7 @@ trees_out::trees_out (allocator *mem, module_state *state, depset::hash &deps,
unsigned section)
:parent (mem), state (state), tree_map (500),
dep_hash (&deps), ref_num (0), section (section),
- writing_local_entities (false)
+ writing_local_entities (false), walking_bit_field_unit (false)
{
#if CHECKING_P
importedness = 0;
@@ -3879,6 +3883,10 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
void write_macro_maps (elf_out *to, range_t &, unsigned *crc_ptr);
bool read_macro_maps (line_map_uint_t);
+ void write_diagnostic_classification (elf_out *, diagnostic_context *,
+ unsigned *);
+ bool read_diagnostic_classification (diagnostic_context *);
+
private:
void write_define (bytes_out &, const cpp_macro *);
cpp_macro *read_define (bytes_in &, cpp_reader *) const;
@@ -5546,8 +5554,10 @@ trees_in::start (unsigned code)
enum class importer_interface {
unknown, /* The definition may or may not need to be emitted. */
- always_import, /* The definition can always be found in another TU. */
- always_emit, /* The definition must be emitted in the importer's TU. */
+ external, /* The definition can always be found in another TU. */
+ internal, /* The definition should be emitted in the importer's TU. */
+ always_emit, /* The definition must be emitted in the importer's TU,
+ regardless of if it's used or not. */
};
/* Returns what kind of interface an importer will have of DECL. */
@@ -5558,13 +5568,13 @@ get_importer_interface (tree decl)
/* Internal linkage entities must be emitted in each importer if
there is a definition available. */
if (!TREE_PUBLIC (decl))
- return importer_interface::always_emit;
+ return importer_interface::internal;
- /* Entities that aren't vague linkage are either not definitions or
- will be emitted in this TU, so importers can just refer to an
- external definition. */
+ /* Other entities that aren't vague linkage are either not definitions
+ or will be publicly emitted in this TU, so importers can just refer
+ to an external definition. */
if (!vague_linkage_p (decl))
- return importer_interface::always_import;
+ return importer_interface::external;
/* For explicit instantiations, importers can always rely on there
being a definition in another TU, unless this is a definition
@@ -5574,13 +5584,13 @@ get_importer_interface (tree decl)
&& DECL_EXPLICIT_INSTANTIATION (decl))
return (header_module_p () && !DECL_EXTERNAL (decl)
? importer_interface::always_emit
- : importer_interface::always_import);
+ : importer_interface::external);
/* A gnu_inline function is never emitted in any TU. */
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl)
&& lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)))
- return importer_interface::always_import;
+ return importer_interface::external;
/* Everything else has vague linkage. */
return importer_interface::unknown;
@@ -5723,28 +5733,16 @@ trees_out::core_bools (tree t, bits_out& bits)
== that was a lie, it is here */
bool is_external = t->decl_common.decl_flag_1;
- if (!is_external)
- /* decl_flag_1 is DECL_EXTERNAL. Things we emit here, might
- well be external from the POV of an importer. */
- // FIXME: Do we need to know if this is a TEMPLATE_RESULT --
- // a flag from the caller?
- switch (code)
- {
- default:
- break;
-
- case VAR_DECL:
- if (TREE_PUBLIC (t)
- && DECL_VTABLE_OR_VTT_P (t))
- /* We handle vtable linkage specially. */
- is_external = true;
- gcc_fallthrough ();
- case FUNCTION_DECL:
- if (get_importer_interface (t)
- == importer_interface::always_import)
- is_external = true;
- break;
- }
+ /* maybe_emit_vtables relies on vtables being marked as
+ DECL_EXTERNAL and DECL_NOT_REALLY_EXTERN before processing. */
+ if (!is_external && VAR_P (t) && DECL_VTABLE_OR_VTT_P (t))
+ is_external = true;
+ /* Things we emit here might well be external from the POV of an
+ importer. */
+ if (!is_external
+ && VAR_OR_FUNCTION_DECL_P (t)
+ && get_importer_interface (t) == importer_interface::external)
+ is_external = true;
WB (is_external);
}
@@ -6024,7 +6022,7 @@ trees_out::lang_decl_bools (tree t, bits_out& bits)
WB (lang->u.fn.has_dependent_explicit_spec_p);
WB (lang->u.fn.immediate_fn_p);
WB (lang->u.fn.maybe_deleted);
- /* We do not stream lang->u.fn.implicit_constexpr. */
+ WB (lang->u.fn.implicit_constexpr);
WB (lang->u.fn.escalated_p);
WB (lang->u.fn.xobj_func);
goto lds_min;
@@ -6095,7 +6093,7 @@ trees_in::lang_decl_bools (tree t, bits_in& bits)
RB (lang->u.fn.has_dependent_explicit_spec_p);
RB (lang->u.fn.immediate_fn_p);
RB (lang->u.fn.maybe_deleted);
- /* We do not stream lang->u.fn.implicit_constexpr. */
+ RB (lang->u.fn.implicit_constexpr);
RB (lang->u.fn.escalated_p);
RB (lang->u.fn.xobj_func);
goto lds_min;
@@ -6517,7 +6515,10 @@ trees_out::core_vals (tree t)
case FIELD_DECL:
WT (t->field_decl.offset);
WT (t->field_decl.bit_field_type);
- WT (t->field_decl.qualifier); /* bitfield unit. */
+ {
+ auto ovr = make_temp_override (walking_bit_field_unit, true);
+ WT (t->field_decl.qualifier); /* bitfield unit. */
+ }
WT (t->field_decl.bit_offset);
WT (t->field_decl.fcontext);
WT (t->decl_common.initial);
@@ -8097,18 +8098,37 @@ trees_in::install_entity (tree decl)
gcc_checking_assert (!existed);
slot = ident;
}
- else if (state->is_partition ())
+ else
{
- /* The decl is already in the entity map, but we see it again now from a
- partition: we want to overwrite if the original decl wasn't also from
- a (possibly different) partition. Otherwise, for things like template
- instantiations, make_dependency might not realise that this is also
- provided from a partition and should be considered part of this module
- (and thus always emitted into the primary interface's CMI). */
unsigned *slot = entity_map->get (DECL_UID (decl));
- module_state *imp = import_entity_module (*slot);
- if (!imp->is_partition ())
- *slot = ident;
+
+ /* The entity must be in the entity map already. However, DECL may
+ be the DECL_TEMPLATE_RESULT of an existing partial specialisation
+ if we matched it while streaming another instantiation; in this
+ case we already registered that TEMPLATE_DECL. */
+ if (!slot)
+ {
+ tree type = TREE_TYPE (decl);
+ gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL
+ && CLASS_TYPE_P (type)
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (type));
+ slot = entity_map->get (DECL_UID (CLASSTYPE_TI_TEMPLATE (type)));
+ }
+ gcc_checking_assert (slot);
+
+ if (state->is_partition ())
+ {
+ /* The decl is already in the entity map, but we see it again now
+ from a partition: we want to overwrite if the original decl
+ wasn't also from a (possibly different) partition. Otherwise,
+ for things like template instantiations, make_dependency might
+ not realise that this is also provided from a partition and
+ should be considered part of this module (and thus always
+ emitted into the primary interface's CMI). */
+ module_state *imp = import_entity_module (*slot);
+ if (!imp->is_partition ())
+ *slot = ident;
+ }
}
return true;
@@ -8199,6 +8219,10 @@ trees_out::decl_value (tree decl, depset *dep)
inner = DECL_TEMPLATE_RESULT (decl);
inner_tag = insert (inner, WK_value);
+ /* On stream-in we assume that a template and its result will
+ have the same type. */
+ gcc_checking_assert (TREE_TYPE (decl) == TREE_TYPE (inner));
+
if (streaming_p ())
{
int code = TREE_CODE (inner);
@@ -9353,6 +9377,7 @@ trees_out::type_node (tree type)
tree root = (TYPE_NAME (type)
? TREE_TYPE (TYPE_NAME (type)) : TYPE_MAIN_VARIANT (type));
+ gcc_checking_assert (root);
if (type != root)
{
@@ -9431,6 +9456,8 @@ trees_out::type_node (tree type)
|| TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
{
+ gcc_checking_assert (DECL_P (name));
+
/* We can meet template parms that we didn't meet in the
tpl_parms walk, because we're referring to a derived type
that was previously constructed from equivalent template
@@ -9645,11 +9672,14 @@ trees_out::tree_value (tree t)
if (DECL_P (t))
/* No template, type, var or function, except anonymous
- non-context vars. */
+ non-context vars and types. */
gcc_checking_assert ((TREE_CODE (t) != TEMPLATE_DECL
- && TREE_CODE (t) != TYPE_DECL
+ && (TREE_CODE (t) != TYPE_DECL
+ || (DECL_ARTIFICIAL (t) && !DECL_CONTEXT (t)))
&& (TREE_CODE (t) != VAR_DECL
- || (!DECL_NAME (t) && !DECL_CONTEXT (t)))
+ || ((!DECL_NAME (t)
+ || IDENTIFIER_INTERNAL_P (DECL_NAME (t)))
+ && !DECL_CONTEXT (t)))
&& TREE_CODE (t) != FUNCTION_DECL));
if (streaming_p ())
@@ -9661,7 +9691,7 @@ trees_out::tree_value (tree t)
tree_node_bools (t);
}
- if (TREE_CODE (t) == TREE_BINFO)
+ if (TREE_CODE (t) == TREE_BINFO)
/* Binfos are decl-like and need merging information. */
binfo_mergeable (t);
@@ -9670,8 +9700,57 @@ trees_out::tree_value (tree t)
dump (dumper::TREE)
&& dump ("Writing tree:%d %C:%N", tag, TREE_CODE (t), t);
+ int type_tag = 0;
+ tree type = NULL_TREE;
+ if (TREE_CODE (t) == TYPE_DECL)
+ {
+ type = TREE_TYPE (t);
+
+ /* We only support a limited set of features for uncontexted types;
+ these are typically types created in the language-independent
+ parts of the frontend (such as ubsan). */
+ gcc_checking_assert (RECORD_OR_UNION_TYPE_P (type)
+ && TYPE_MAIN_VARIANT (type) == type
+ && TYPE_NAME (type) == t
+ && TYPE_STUB_DECL (type) == t
+ && !TYPE_VFIELD (type)
+ && !TYPE_BINFO (type)
+ && !CLASS_TYPE_P (type));
+
+ if (streaming_p ())
+ {
+ start (type);
+ tree_node_bools (type);
+ }
+
+ type_tag = insert (type, WK_value);
+ if (streaming_p ())
+ dump (dumper::TREE)
+ && dump ("Writing type: %d %C:%N", type_tag,
+ TREE_CODE (type), type);
+ }
+
tree_node_vals (t);
+ if (type)
+ {
+ tree_node_vals (type);
+ tree_node (TYPE_SIZE (type));
+ tree_node (TYPE_SIZE_UNIT (type));
+ chained_decls (TYPE_FIELDS (type));
+ if (streaming_p ())
+ dump (dumper::TREE)
+ && dump ("Written type:%d %C:%N", type_tag, TREE_CODE (type), type);
+ }
+
+ /* For uncontexted VAR_DECLs we need to stream the definition so that
+ importers can recreate their value. */
+ if (TREE_CODE (t) == VAR_DECL)
+ {
+ gcc_checking_assert (!DECL_NONTRIVIALLY_INITIALIZED_P (t));
+ tree_node (DECL_INITIAL (t));
+ }
+
if (streaming_p ())
dump (dumper::TREE) && dump ("Written tree:%d %C:%N", tag, TREE_CODE (t), t);
}
@@ -9710,14 +9789,55 @@ trees_in::tree_value ()
dump (dumper::TREE)
&& dump ("Reading tree:%d %C", tag, TREE_CODE (t));
- if (!tree_node_vals (t))
+ int type_tag = 0;
+ tree type = NULL_TREE;
+ if (TREE_CODE (t) == TYPE_DECL)
{
+ type = start ();
+ if (!type || !tree_node_bools (type))
+ t = NULL_TREE;
+
+ type_tag = insert (type);
+ if (t)
+ dump (dumper::TREE)
+ && dump ("Reading type:%d %C", type_tag, TREE_CODE (type));
+ }
+
+ if (!t)
+ {
+bail:
back_refs[~tag] = NULL_TREE;
+ if (type_tag)
+ back_refs[~type_tag] = NULL_TREE;
set_overrun ();
- /* Bail. */
return NULL_TREE;
}
+ if (!tree_node_vals (t))
+ goto bail;
+
+ if (type)
+ {
+ if (!tree_node_vals (type))
+ goto bail;
+
+ TYPE_SIZE (type) = tree_node ();
+ TYPE_SIZE_UNIT (type) = tree_node ();
+ TYPE_FIELDS (type) = chained_decls ();
+ if (get_overrun ())
+ goto bail;
+
+ dump (dumper::TREE)
+ && dump ("Read type:%d %C:%N", type_tag, TREE_CODE (type), type);
+ }
+
+ if (TREE_CODE (t) == VAR_DECL)
+ {
+ DECL_INITIAL (t) = tree_node ();
+ if (TREE_STATIC (t))
+ varpool_node::finalize_decl (t);
+ }
+
if (TREE_CODE (t) == LAMBDA_EXPR
&& CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (t)))
{
@@ -9860,10 +9980,13 @@ trees_out::tree_node (tree t)
if (TREE_CODE (t) == IDENTIFIER_NODE)
{
- /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id. */
+ /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id,
+ tt_internal_id. */
int code = tt_id;
if (IDENTIFIER_ANON_P (t))
code = IDENTIFIER_LAMBDA_P (t) ? tt_lambda_id : tt_anon_id;
+ else if (IDENTIFIER_INTERNAL_P (t))
+ code = tt_internal_id;
else if (IDENTIFIER_CONV_OP_P (t))
code = tt_conv_id;
@@ -9878,13 +10001,15 @@ trees_out::tree_node (tree t)
}
else if (code == tt_id && streaming_p ())
str (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t));
+ else if (code == tt_internal_id && streaming_p ())
+ str (prefix_for_internal_label (t));
int tag = insert (t);
if (streaming_p ())
{
- /* We know the ordering of the 4 id tags. */
+ /* We know the ordering of the 5 id tags. */
static const char *const kinds[] =
- {"", "conv_op ", "anon ", "lambda "};
+ {"", "conv_op ", "anon ", "lambda ", "internal "};
dump (dumper::TREE)
&& dump ("Written:%d %sidentifier:%N", tag,
kinds[code - tt_id],
@@ -9961,8 +10086,11 @@ trees_out::tree_node (tree t)
break;
case VAR_DECL:
- /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs. */
- gcc_checking_assert (!DECL_NAME (t)
+ /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs,
+ and internal vars are created by sanitizers and
+ __builtin_source_location. */
+ gcc_checking_assert ((!DECL_NAME (t)
+ || IDENTIFIER_INTERNAL_P (DECL_NAME (t)))
&& DECL_ARTIFICIAL (t));
break;
@@ -9971,7 +10099,18 @@ trees_out::tree_node (tree t)
PARM_DECLS. It'd be nice if they had a
distinguishing flag to double check. */
break;
+
+ case TYPE_DECL:
+ /* Some parts of the compiler need internal struct types;
+ these types may not have an appropriate context to use.
+ Walk the whole type (including its definition) by value. */
+ gcc_checking_assert (DECL_ARTIFICIAL (t)
+ && TYPE_ARTIFICIAL (TREE_TYPE (t))
+ && RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))
+ && !CLASS_TYPE_P (TREE_TYPE (t)));
+ break;
}
+ mark_declaration (t, has_definition (t));
goto by_value;
}
}
@@ -10108,6 +10247,17 @@ trees_in::tree_node (bool is_use)
}
break;
+ case tt_internal_id:
+ /* An internal label. */
+ {
+ const char *prefix = str ();
+ res = generate_internal_label (prefix);
+ int tag = insert (res);
+ dump (dumper::TREE)
+ && dump ("Read internal identifier:%d %N", tag, res);
+ }
+ break;
+
case tt_typedef_type:
res = tree_node ();
if (res)
@@ -10503,7 +10653,8 @@ trees_in::tree_node (bool is_use)
res = lookup_field_ident (ctx, u ());
if (!res
- || TREE_CODE (res) != FIELD_DECL
+ || (TREE_CODE (res) != FIELD_DECL
+ && TREE_CODE (res) != USING_DECL)
|| DECL_CONTEXT (res) != ctx)
res = NULL_TREE;
}
@@ -11110,6 +11261,11 @@ trees_out::get_merge_kind (tree decl, depset *dep)
return MK_local_friend;
gcc_checking_assert (TYPE_P (ctx));
+
+ /* Internal-only types will not need to dedup their members. */
+ if (!DECL_CONTEXT (TYPE_NAME (ctx)))
+ return MK_unique;
+
if (TREE_CODE (decl) == USING_DECL)
return MK_field;
@@ -11122,15 +11278,16 @@ trees_out::get_merge_kind (tree decl, depset *dep)
return MK_named;
}
- if (!DECL_NAME (decl)
- && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
- && !DECL_BIT_FIELD_REPRESENTATIVE (decl))
+ if (walking_bit_field_unit)
{
/* The underlying storage unit for a bitfield. We do not
need to dedup it, because it's only reachable through
the bitfields it represents. And those are deduped. */
// FIXME: Is that assertion correct -- do we ever fish it
// out and put it in an expr?
+ gcc_checking_assert (!DECL_NAME (decl)
+ && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
+ && !DECL_BIT_FIELD_REPRESENTATIVE (decl));
gcc_checking_assert ((TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
? TREE_CODE (TREE_TYPE (TREE_TYPE (decl)))
: TREE_CODE (TREE_TYPE (decl)))
@@ -12179,7 +12336,8 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
{
dump (dumper::MERGE)
&& dump ("Propagating deduced return type to %N", existing);
- FNDECL_USED_AUTO (e_inner) = true;
+ gcc_checking_assert (existing == e_inner);
+ FNDECL_USED_AUTO (existing) = true;
DECL_SAVED_AUTO_RETURN_TYPE (existing) = TREE_TYPE (e_type);
TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
}
@@ -12193,13 +12351,23 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
/* Similarly if EXISTING has undeduced constexpr, but DECL's
is already deduced. */
- if (DECL_MAYBE_DELETED (e_inner) && !DECL_MAYBE_DELETED (d_inner)
- && DECL_DECLARED_CONSTEXPR_P (d_inner))
- DECL_DECLARED_CONSTEXPR_P (e_inner) = true;
- else if (!DECL_MAYBE_DELETED (e_inner) && DECL_MAYBE_DELETED (d_inner))
- /* Nothing to do. */;
+ if (DECL_DECLARED_CONSTEXPR_P (e_inner)
+ == DECL_DECLARED_CONSTEXPR_P (d_inner))
+ /* Already matches. */;
+ else if (DECL_DECLARED_CONSTEXPR_P (d_inner)
+ && (DECL_MAYBE_DELETED (e_inner)
+ || decl_implicit_constexpr_p (d_inner)))
+ /* DECL was deduced, copy to EXISTING. */
+ {
+ DECL_DECLARED_CONSTEXPR_P (e_inner) = true;
+ if (decl_implicit_constexpr_p (d_inner))
+ DECL_LANG_SPECIFIC (e_inner)->u.fn.implicit_constexpr = true;
+ }
else if (DECL_DECLARED_CONSTEXPR_P (e_inner)
- != DECL_DECLARED_CONSTEXPR_P (d_inner))
+ && (DECL_MAYBE_DELETED (d_inner)
+ || decl_implicit_constexpr_p (e_inner)))
+ /* EXISTING was deduced, leave it alone. */;
+ else
{
mismatch_msg = G_("conflicting %<constexpr%> for imported "
"declaration %#qD");
@@ -12641,7 +12809,7 @@ trees_out::write_function_def (tree decl)
/* Whether the importer should emit this definition, if used. */
flags |= 1 * (DECL_NOT_REALLY_EXTERN (decl)
&& (get_importer_interface (decl)
- != importer_interface::always_import));
+ != importer_interface::external));
if (f)
{
@@ -16845,11 +17013,15 @@ module_state::write_namespaces (elf_out *to, vec<depset *> spaces,
bytes_out sec (to);
sec.begin ();
+ hash_map<tree, unsigned> ns_map;
+
for (unsigned ix = 0; ix != num; ix++)
{
depset *b = spaces[ix];
tree ns = b->get_entity ();
+ ns_map.put (ns, ix);
+
/* This could be an anonymous namespace even for a named module,
since we can still emit no-linkage decls. */
gcc_checking_assert (TREE_CODE (ns) == NAMESPACE_DECL);
@@ -16891,6 +17063,31 @@ module_state::write_namespaces (elf_out *to, vec<depset *> spaces,
}
}
+ /* Now write exported using-directives, as a sequence of 1-origin indices in
+ the spaces array (not entity indices): First the using namespace, then the
+ used namespaces. And then a zero terminating the list. :: is
+ represented as index -1. */
+ auto emit_one_ns = [&](unsigned ix, tree ns) {
+ for (auto udir: NAMESPACE_LEVEL (ns)->using_directives)
+ {
+ if (TREE_CODE (udir) != USING_DECL || !DECL_MODULE_EXPORT_P (udir))
+ continue;
+ tree ns2 = USING_DECL_DECLS (udir);
+ dump() && dump ("Writing using-directive in %N for %N",
+ ns, ns2);
+ sec.u (ix);
+ sec.u (*ns_map.get (ns2) + 1);
+ }
+ };
+ emit_one_ns (-1, global_namespace);
+ for (unsigned ix = 0; ix != num; ix++)
+ {
+ depset *b = spaces[ix];
+ tree ns = b->get_entity ();
+ emit_one_ns (ix + 1, ns);
+ }
+ sec.u (0);
+
sec.end (to, to->name (MOD_SNAME_PFX ".nms"), crc_p);
dump.outdent ();
}
@@ -16909,6 +17106,8 @@ module_state::read_namespaces (unsigned num)
dump () && dump ("Reading namespaces");
dump.indent ();
+ tree *ns_map = XALLOCAVEC (tree, num);
+
for (unsigned ix = 0; ix != num; ix++)
{
unsigned entity_index = sec.u ();
@@ -16970,6 +17169,8 @@ module_state::read_namespaces (unsigned num)
DECL_ATTRIBUTES (inner)
= tree_cons (get_identifier ("abi_tag"), tags, DECL_ATTRIBUTES (inner));
+ ns_map[ix] = inner;
+
/* Install the namespace. */
(*entity_ary)[entity_lwm + entity_index] = inner;
if (DECL_MODULE_IMPORT_P (inner))
@@ -16984,6 +17185,44 @@ module_state::read_namespaces (unsigned num)
*slot = entity_lwm + entity_index;
}
}
+
+ /* Read the exported using-directives. */
+ while (unsigned ix = sec.u ())
+ {
+ tree ns;
+ if (ix == (unsigned)-1)
+ ns = global_namespace;
+ else
+ {
+ if (--ix >= num)
+ {
+ sec.set_overrun ();
+ break;
+ }
+ ns = ns_map [ix];
+ }
+ unsigned ix2 = sec.u ();
+ if (--ix2 >= num)
+ {
+ sec.set_overrun ();
+ break;
+ }
+ tree ns2 = ns_map [ix2];
+ if (directness)
+ {
+ dump() && dump ("Reading using-directive in %N for %N",
+ ns, ns2);
+ /* In an export import this will mark the using-directive as
+ exported, so it will be emitted again. */
+ add_using_namespace (ns, ns2);
+ }
+ else
+ /* Ignore using-directives from indirect imports, we only want them
+ from our own imports. */
+ dump() && dump ("Ignoring using-directive in %N for %N",
+ ns, ns2);
+ }
+
dump.outdent ();
if (!sec.end (from ()))
return false;
@@ -18076,6 +18315,168 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info,
dump.outdent ();
}
+/* Return the prefix to use for dumping a #pragma diagnostic change to DK. */
+
+static const char *
+dk_string (diagnostic_t dk)
+{
+ gcc_assert (dk > DK_UNSPECIFIED && dk < DK_LAST_DIAGNOSTIC_KIND);
+ if (dk == DK_IGNORED)
+ /* diagnostic.def has an empty string for ignored. */
+ return "ignored: ";
+ else
+ return get_diagnostic_kind_text (dk);
+}
+
+/* Dump one #pragma GCC diagnostic entry. */
+
+static bool
+dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk)
+{
+ if (dk == DK_POP)
+ return dump (" Index %u: pop from %d", index, opt);
+ else
+ return dump (" Index %u: %s%s", index, dk_string (dk),
+ cl_options[opt].opt_text);
+}
+
+/* Write out any #pragma GCC diagnostic info to the .dgc section. */
+
+void
+module_state::write_diagnostic_classification (elf_out *to,
+ diagnostic_context *dc,
+ unsigned *crc_p)
+{
+ auto &changes = dc->get_classification_history ();
+
+ bytes_out sec (to);
+ if (sec.streaming_p ())
+ {
+ sec.begin ();
+ dump () && dump ("Writing diagnostic change locations");
+ dump.indent ();
+ }
+
+ unsigned len = changes.length ();
+
+ /* We don't want to write out any entries that came from one of our imports.
+ But then we need to adjust the total, and change DK_POP targets to match
+ the index in our actual output. So remember how many lines we had skipped
+ at each step, where -1 means this line itself is skipped. */
+ int skips = 0;
+ auto_vec<int> skips_at (len);
+ skips_at.safe_grow (len);
+
+ for (unsigned i = 0; i < len; ++i)
+ {
+ const auto &c = changes[i];
+ skips_at[i] = skips;
+ if (linemap_location_from_module_p (line_table, c.location))
+ {
+ ++skips;
+ skips_at[i] = -1;
+ continue;
+ }
+ }
+
+ if (sec.streaming_p ())
+ {
+ sec.u (len - skips);
+ dump () && dump ("Diagnostic changes: %u", len - skips);
+ }
+
+ for (unsigned i = 0; i < len; ++i)
+ {
+ if (skips_at[i] == -1)
+ continue;
+
+ const auto &c = changes[i];
+ write_location (sec, c.location);
+ if (sec.streaming_p ())
+ {
+ unsigned opt = c.option;
+ if (c.kind == DK_POP)
+ opt -= skips_at[opt];
+ sec.u (opt);
+ sec.u (c.kind);
+ dump () && dump_dc_change (i - skips_at[i], opt, c.kind);
+ }
+ }
+
+ if (sec.streaming_p ())
+ {
+ sec.end (to, to->name (MOD_SNAME_PFX ".dgc"), crc_p);
+ dump.outdent ();
+ }
+}
+
+/* Read any #pragma GCC diagnostic info from the .dgc section. */
+
+bool
+module_state::read_diagnostic_classification (diagnostic_context *dc)
+{
+ bytes_in sec;
+
+ if (!sec.begin (loc, from (), MOD_SNAME_PFX ".dgc"))
+ return false;
+
+ dump () && dump ("Reading diagnostic change locations");
+ dump.indent ();
+
+ unsigned len = sec.u ();
+ dump () && dump ("Diagnostic changes: %u", len);
+
+ auto &changes = dc->get_classification_history ();
+ int offset = changes.length ();
+ changes.reserve (len + 1);
+ for (unsigned i = 0; i < len; ++i)
+ {
+ location_t loc = read_location (sec);
+ int opt = sec.u ();
+ diagnostic_t kind = (diagnostic_t) sec.u ();
+ if (kind == DK_POP)
+ /* For a pop, opt is the 'changes' index to return to. */
+ opt += offset;
+ changes.quick_push ({ loc, opt, kind });
+ dump () && dump_dc_change (changes.length () - 1, opt, kind);
+ }
+
+ /* Did the import pop all its diagnostic changes? */
+ bool last_was_reset = (len == 0);
+ if (len)
+ for (int i = changes.length () - 1; ; --i)
+ {
+ gcc_checking_assert (i >= offset);
+
+ const auto &c = changes[i];
+ if (c.kind != DK_POP)
+ break;
+ else if (c.option == offset)
+ {
+ last_was_reset = true;
+ break;
+ }
+ else
+ /* As in update_effective_level_from_pragmas, the loop will decrement
+ i so we actually jump to c.option - 1. */
+ i = c.option;
+ }
+ if (!last_was_reset)
+ {
+ /* It didn't, so add a pop at its last location to avoid affecting later
+ imports. */
+ location_t last_loc = ordinary_locs.first + ordinary_locs.second - 1;
+ changes.quick_push ({ last_loc, offset, DK_POP });
+ dump () && dump (" Adding final pop from index %d", offset);
+ }
+
+ dump.outdent ();
+ if (!sec.end (from ()))
+ return false;
+
+ return true;
+}
+
void
module_state::write_macro_maps (elf_out *to, range_t &info, unsigned *crc_p)
{
@@ -19762,6 +20163,8 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
}
ool->qsort (ool_cmp);
+ write_diagnostic_classification (nullptr, global_dc, nullptr);
+
vec<cpp_hashnode *> *macros = nullptr;
if (is_header ())
macros = prepare_macros (reader);
@@ -19907,7 +20310,10 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
/* Write the line maps. */
if (config.ordinary_locs)
- write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc);
+ {
+ write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc);
+ write_diagnostic_classification (to, global_dc, &crc);
+ }
if (config.macro_locs)
write_macro_maps (to, map_info, &crc);
@@ -19980,6 +20386,10 @@ module_state::read_initial (cpp_reader *reader)
else if (!read_ordinary_maps (config.ordinary_locs, config.loc_range_bits))
ok = false;
+ if (ok && have_locs && config.ordinary_locs
+ && !read_diagnostic_classification (global_dc))
+ ok = false;
+
/* Allocate the REMAP vector. */
slurp->alloc_remap (config.num_imports);