https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115913
Lewis Hyatt <lhyatt at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |lhyatt at gcc dot gnu.org, | |marxin at gcc dot gnu.org Summary|[11/12/13/14/15 Regression] |[11/12/13/14/15 Regression] |ICE with pragma GCC |ICE with pragma GCC |pop_options with diagnostic |pop_options with diagnostic | |since r11-1141 See Also| |https://gcc.gnu.org/bugzill | |a/show_bug.cgi?id=92860 --- Comment #6 from Lewis Hyatt <lhyatt at gcc dot gnu.org> --- Started with r11-1141 (which added the checking assert in the first place). I think this check is ensuring that after this sequence: #pragma GCC push_options #pragma GCC optimize ... #pragma GCC pop_options all the options have been restored to their previous values. But it doesn't consider that the options might have been deliberately changed by another pragma, in which case they are not expected to retain their previous values. I think the fix in the spirit of this check is to disable the check while a diagnostic pragma is in force. This untested patch resolves it that way, if the approach seems reasonable I could prepare it? diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index 25251c2b69f..0080bac99bf 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -866,6 +866,9 @@ pragma_diagnostic_lex (pragma_diagnostic_data *result) result->valid = true; } +static void +options_stack_disable_checking (); + /* Handle #pragma GCC diagnostic. Early mode is used by frontends (such as C++) that do not process the deferred pragma while they are consuming tokens; they can use early mode to make sure diagnostics affecting the preprocessor itself @@ -1020,6 +1023,7 @@ handle_pragma_diagnostic_impl () input_location, lang_mask, &handlers, &global_options, &global_options_set, global_dc); + options_stack_disable_checking (); } static void @@ -1192,10 +1196,18 @@ struct GTY(()) opt_stack { tree optimize_binary; tree optimize_strings; gcc_options * GTY ((skip)) saved_global_options; + bool disable_checking; }; static GTY(()) struct opt_stack * options_stack; +static void +options_stack_disable_checking () +{ + if (options_stack) + options_stack->disable_checking = true; +} + /* Handle #pragma GCC push_options to save the current target and optimization options. */ @@ -1212,7 +1224,7 @@ handle_pragma_push_options (cpp_reader *) return; } - opt_stack *p = ggc_alloc<opt_stack> (); + opt_stack *p = ggc_cleared_alloc<opt_stack> (); p->prev = options_stack; options_stack = p; @@ -1260,6 +1272,14 @@ handle_pragma_pop_options (cpp_reader *) p = options_stack; options_stack = p->prev; + if (flag_checking && p->disable_checking) + { + XDELETEVEC (p->saved_global_options); + p->saved_global_options = nullptr; + if (p->prev) + p->prev->disable_checking = true; + } + if (p->target_binary != target_option_current_node) { (void) targetm.target_option.pragma_parse (NULL_TREE, p->target_binary); @@ -1279,7 +1299,7 @@ handle_pragma_pop_options (cpp_reader *) p->optimize_binary); optimization_current_node = p->optimize_binary; } - if (flag_checking && !seen_error ()) + if (flag_checking && p->saved_global_options && !seen_error ()) { cl_optimization_compare (p->saved_global_options, &global_options); free (p->saved_global_options);