https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111918
--- Comment #1 from Florian Weimer <fw at gcc dot gnu.org> --- diagnostic_classify_diagnostic overwrites DK_UNSPECIFIED in context->classify_diagnostic[OPT_Wnarrowing] with DK_WARNING here: /* Record the command-line status, so we can reset it back on DK_POP. */ if (old_kind == DK_UNSPECIFIED) { old_kind = !context->option_enabled (option_index, context->lang_mask, context->option_state) ? DK_IGNORED : (context->warning_as_error_requested ? DK_ERROR : DK_WARNING); context->classify_diagnostic[option_index] = old_kind; } In diagnostic_enabled, we use that to switch the diagnostic kind to DK_WARNING because update_effective_level_from_pragmas return DK_UNSPECIFIED: /* This tests for #pragma diagnostic changes. */ diagnostic_t diag_class = update_effective_level_from_pragmas (context, diagnostic); /* This tests if the user provided the appropriate -Werror=foo option. */ if (diag_class == DK_UNSPECIFIED && (context->classify_diagnostic[diagnostic->option_index] != DK_UNSPECIFIED)) diagnostic->kind = context->classify_diagnostic[diagnostic->option_index]; We cannot treat permerrors differently in either function because they are an emerging property, not associated with the warning option itself. This fixes the test case, though: /* This tests if the user provided the appropriate -Werror=foo option. */ if (diag_class == DK_UNSPECIFIED && (context->classify_diagnostic[diagnostic->option_index] == DK_ERROR)) diagnostic->kind = DK_ERROR; I see what it does to the test suite.