mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-21 19:35:28 -05:00
c++: modules and #pragma diagnostic
To respect the #pragma diagnostic lines in libstdc++ headers when compiling with module std, we need to represent them in the module. I think it's reasonable to give serializers direct access to the underlying data, as here with get_classification_history. This is a different approach from how Jakub made PCH streaming members of diagnostic_option_classifier, but it seems to me that modules handling belongs in module.cc. libcpp/ChangeLog: * line-map.cc (linemap_location_from_module_p): Add. * include/line-map.h: Declare it. gcc/ChangeLog: * diagnostic.h (diagnostic_option_classifier): Friend diagnostic_context. (diagnostic_context::get_classification_history): New. gcc/cp/ChangeLog: * module.cc (module_state::write_diagnostic_classification): New. (module_state::write_begin): Call it. (module_state::read_diagnostic_classification): New. (module_state::read_initial): Call it. (dk_string, dump_dc_change): New. gcc/testsuite/ChangeLog: * g++.dg/modules/warn-spec-3_a.C: New test. * g++.dg/modules/warn-spec-3_b.C: New test. * g++.dg/modules/warn-spec-3_c.C: New test.
This commit is contained in:
177
gcc/cp/module.cc
177
gcc/cp/module.cc
@@ -3879,6 +3879,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;
|
||||
@@ -18167,6 +18171,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)
|
||||
{
|
||||
@@ -19853,6 +20019,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);
|
||||
@@ -19998,7 +20166,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);
|
||||
|
||||
@@ -20071,6 +20242,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);
|
||||
|
||||
|
||||
@@ -307,6 +307,9 @@ private:
|
||||
diagnostic. */
|
||||
vec<diagnostic_classification_change_t> m_classification_history;
|
||||
|
||||
/* For diagnostic_context::get_classification_history, declared later. */
|
||||
friend class diagnostic_context;
|
||||
|
||||
/* For pragma push/pop. */
|
||||
vec<int> m_push_list;
|
||||
};
|
||||
@@ -830,6 +833,13 @@ public:
|
||||
m_abort_on_error = val;
|
||||
}
|
||||
|
||||
/* Accessor for use in serialization, e.g. by C++ modules. */
|
||||
auto &
|
||||
get_classification_history ()
|
||||
{
|
||||
return m_option_classifier.m_classification_history;
|
||||
}
|
||||
|
||||
private:
|
||||
void error_recursion () ATTRIBUTE_NORETURN;
|
||||
|
||||
|
||||
20
gcc/testsuite/g++.dg/modules/warn-spec-3_a.C
Normal file
20
gcc/testsuite/g++.dg/modules/warn-spec-3_a.C
Normal file
@@ -0,0 +1,20 @@
|
||||
// { dg-do compile { target c++20 } }
|
||||
// { dg-additional-options -fmodules }
|
||||
// { dg-module-cmi M }
|
||||
|
||||
module;
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
export module M;
|
||||
|
||||
#pragma GCC diagnostic ignored "-Winit-list-lifetime"
|
||||
|
||||
template <class T>
|
||||
struct myspan {
|
||||
const T* p; unsigned s;
|
||||
myspan (std::initializer_list<T> il)
|
||||
: p (il.begin()), s (il.size()) { }
|
||||
};
|
||||
|
||||
export void f(myspan<int>);
|
||||
7
gcc/testsuite/g++.dg/modules/warn-spec-3_b.C
Normal file
7
gcc/testsuite/g++.dg/modules/warn-spec-3_b.C
Normal file
@@ -0,0 +1,7 @@
|
||||
// { dg-additional-options "-fmodules -fdump-lang-module" }
|
||||
|
||||
// Test that we don't re-export the changes from M.
|
||||
// { dg-final { scan-lang-dump {Diagnostic changes: 0} module } }
|
||||
|
||||
export module N;
|
||||
import M;
|
||||
12
gcc/testsuite/g++.dg/modules/warn-spec-3_c.C
Normal file
12
gcc/testsuite/g++.dg/modules/warn-spec-3_c.C
Normal file
@@ -0,0 +1,12 @@
|
||||
// { dg-additional-options "-fmodules -fdump-lang-module" }
|
||||
|
||||
// Test that we clean up the unpopped change in M.
|
||||
// { dg-final { scan-lang-dump {Adding final pop} module } }
|
||||
|
||||
import N;
|
||||
import M;
|
||||
|
||||
int main()
|
||||
{
|
||||
f({24,42});
|
||||
}
|
||||
@@ -1111,6 +1111,10 @@ extern location_t linemap_module_loc
|
||||
extern void linemap_module_reparent
|
||||
(line_maps *, location_t loc, location_t new_parent);
|
||||
|
||||
/* TRUE iff the location comes from a module import. */
|
||||
extern bool linemap_location_from_module_p
|
||||
(const line_maps *, location_t);
|
||||
|
||||
/* Restore the linemap state such that the map at LWM-1 continues.
|
||||
Return start location of the new map. */
|
||||
extern location_t linemap_module_restore
|
||||
|
||||
@@ -767,6 +767,17 @@ linemap_module_restore (line_maps *set, line_map_uint_t lwm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TRUE iff the location comes from a module import. */
|
||||
|
||||
bool
|
||||
linemap_location_from_module_p (const line_maps *set, location_t loc)
|
||||
{
|
||||
const line_map_ordinary *map = linemap_ordinary_map_lookup (set, loc);
|
||||
while (map && map->reason != LC_MODULE)
|
||||
map = linemap_included_from_linemap (set, map);
|
||||
return !!map;
|
||||
}
|
||||
|
||||
/* Returns TRUE if the line table set tracks token locations across
|
||||
macro expansion, FALSE otherwise. */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user