When I fixed PR59304, I forgot that a command-line warning can be also an error if -Werror was enabled. This introduced a regression since anything enabled in the command-line together with -Werror would get initially classified as a warning when reaching the first #pragma GCC diagnostic, and this will be the setting after a #pragma pop.
Options that appear as arguments of -W[no-]error= are not affected by this since those are initially classified as errors/warnings even before reaching the first #pragma, thus the pop sets them correctly (before and after this patch). Nonetheless, the tests also check that they work correctly. Boot®tested on x86_64-linux-gnu. OK? gcc/ChangeLog: 2015-07-29 Manuel López-Ibáñez <m...@gcc.gnu.org> PR c/66098 PR c/66711 * diagnostic.c (diagnostic_classify_diagnostic): Take -Werror into account when deciding what was the command-line status. gcc/testsuite/ChangeLog: 2015-07-29 Manuel López-Ibáñez <m...@gcc.gnu.org> PR c/66098 PR c/66711 * gcc.dg/pragma-diag-3.c: New test. * gcc.dg/pragma-diag-4.c: New test.
Index: gcc/diagnostic.c =================================================================== --- gcc/diagnostic.c (revision 226312) +++ gcc/diagnostic.c (working copy) @@ -694,13 +694,14 @@ diagnostic_classify_diagnostic (diagnost int i; /* 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->option_state) - ? DK_WARNING : DK_IGNORED; + old_kind = !context->option_enabled (option_index, + context->option_state) + ? DK_IGNORED : (context->warning_as_error_requested + ? DK_ERROR: DK_WARNING); context->classify_diagnostic[option_index] = old_kind; } for (i = context->n_classification_history - 1; i >= 0; i --) if (context->classification_history[i].option == option_index) Index: gcc/testsuite/gcc.dg/pragma-diag-3.c =================================================================== --- gcc/testsuite/gcc.dg/pragma-diag-3.c (revision 0) +++ gcc/testsuite/gcc.dg/pragma-diag-3.c (revision 0) @@ -0,0 +1,72 @@ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-enum -Wsign-compare -fstrict-overflow -Wstrict-overflow -Werror -Wno-error=switch-enum" } */ +/* PR c/66098 - #pragma diagnostic 'ignored' not fully undone by pop for strict-overflow + PR c/66711 - GCC does not correctly restore diagnostic state after pragma GCC diagnostic pop with -Werror +*/ +/* { dg-message "warnings being treated as errors" "" {target "*-*-*"} 0 } */ + +void testing2() { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-overflow" + int j = 4; + j + 4 < j; +#pragma GCC diagnostic pop +} + +void testing3() { + int k = 4; + k + 4 < k; /* { dg-error "overflow" } */ +} + +int foo() { + testing2(); + testing3(); + + return 0; +} + + +int bar() +{ + unsigned x = 0; + int y = 1; + + /* generates an error - ok */ + x += x < y ? 1 : 0; /* { dg-error "comparison" } */ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" + /* generates no diagnostic - ok */ + x += x < y ? 1 : 0; +#pragma GCC diagnostic pop + + x += x < y ? 1 : 0; /* { dg-error "comparison" } */ + + return x; +} + +enum EE { ONE, TWO }; + +int f (enum EE e) +{ + int r = 0; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch-enum" + + switch (e) + { + case ONE: + r = 1; + break; + } +#pragma GCC diagnostic pop + + switch (e) /* { dg-warning "switch" } */ + { + case ONE: + r = 1; + break; + } + return r; +} Index: gcc/testsuite/gcc.dg/pragma-diag-4.c =================================================================== --- gcc/testsuite/gcc.dg/pragma-diag-4.c (revision 0) +++ gcc/testsuite/gcc.dg/pragma-diag-4.c (revision 0) @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-Wsign-compare -Werror=sign-compare -Werror=switch-enum" } */ +/* { dg-message "warnings being treated as errors" "" {target "*-*-*"} 0 } */ + +int bar() +{ + unsigned x = 0; + int y = 1; + + /* generates an error - ok */ + x += x < y ? 1 : 0; /* { dg-error "comparison" } */ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" + /* generates no diagnostic - ok */ + x += x < y ? 1 : 0; +#pragma GCC diagnostic pop + + x += x < y ? 1 : 0; /* { dg-error "comparison" } */ + + return x; +} + +enum EE { ONE, TWO }; + +int f (enum EE e) +{ + int r = 0; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch-enum" + + switch (e) + { + case ONE: + r = 1; + break; + } +#pragma GCC diagnostic pop + + switch (e) /* { dg-error "switch" } */ + { + case ONE: + r = 1; + break; + } + return r; +}