https://gcc.gnu.org/g:44ba7bcb752a40ec7490dea53d3a472ce633371d

commit r14-9561-g44ba7bcb752a40ec7490dea53d3a472ce633371d
Author: Lewis Hyatt <lhy...@gmail.com>
Date:   Wed Nov 8 16:13:14 2023 -0500

    diagnostics: Fix behavior of permerror options after diagnostic pop 
[PR111918]
    
    When a diagnostic pragma changes the classification of a given diagnostic,
    the global options flags (such as warn_narrowing, etc.) may get changed too.
    Specifically, if a warning was not enabled initially and was later enabled
    by a pragma, then the corresponding global flag will change from false to
    true when the pragma is processed. That change is permanent and is not
    undone by a subsequent `#pragma GCC diagnostic pop'; the warning flag needs
    to remain enabled since a diagnostic could be generated later on for a
    source location prior to the pop.
    
    So in order to support popping to the initial classification, given that the
    global options flags no longer reflect that state, the diagnostic_context
    object itself remembers the way things were before it changed anything. The
    current implementation works fine for diagnostics that are always errors or
    always warnings, but it doesn't do the right thing for diagnostics that
    could be either, such as -Wnarrowing. The classification of that diagnostic
    (or any permerror diagnostic) depends on the state of -fpermissive; for the
    particular case of -Wnarrowing it also matters whether a compile-time or
    run-time narrowing is being diagnosed.
    
    The problem is that the current implementation insists on recording whether
    an enabled diagnostic should be a DK_WARNING or a DK_ERROR, and then, after
    popping to the initial state, it overrides it always to that type only. Fix
    that up by adding a new internal diagnostic type DK_ANY. This just indicates
    that the diagnostic is enabled without mandating exactly what type of
    diagnostic it should be. Then the diagnostic can be emitted with whatever
    type the frontend asks for.
    
    Incidentally, while making this change, I noticed that classify_diagnostic()
    spends some time computing a return value (the old classification kind) that
    is not used anywhere. The computed value seems to have some problems, mainly
    that it does not take into account `#pragma GCC diagnostic pop' at all, and
    so the returned value doesn't seem like it could make sense in many
    contexts. Given it would also not be desirable to leak the new internal-only
    DK_ANY type to outside callers, I think it would make sense in a subsequent
    cleanup patch to remove the return value altogether.
    
    gcc/ChangeLog:
    
            PR c++/111918
            * diagnostic-core.h (enum diagnostic_t): Add DK_ANY special flag.
            * diagnostic.cc (diagnostic_option_classifier::classify_diagnostic):
            Make use of DK_ANY to indicate a diagnostic was initially enabled.
            (diagnostic_context::diagnostic_enabled): Do not change the type of
            a diagnostic if the saved classification is type DK_ANY.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/111918
            * g++.dg/cpp0x/Wnarrowing21a.C: New test.
            * g++.dg/cpp0x/Wnarrowing21b.C: New test.
            * g++.dg/cpp0x/Wnarrowing21c.C: New test.
            * g++.dg/cpp0x/Wnarrowing21d.C: New test.

Diff:
---
 gcc/diagnostic-core.h                      |  5 ++++-
 gcc/diagnostic.cc                          | 13 ++++++++++---
 gcc/testsuite/g++.dg/cpp0x/Wnarrowing21a.C | 14 ++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/Wnarrowing21b.C |  9 +++++++++
 gcc/testsuite/g++.dg/cpp0x/Wnarrowing21c.C |  9 +++++++++
 gcc/testsuite/g++.dg/cpp0x/Wnarrowing21d.C |  9 +++++++++
 6 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index f5e1e500dc3..8071cc1f69b 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -33,7 +33,10 @@ typedef enum
   DK_LAST_DIAGNOSTIC_KIND,
   /* This is used for tagging pragma pops in the diagnostic
      classification history chain.  */
-  DK_POP
+  DK_POP,
+  /* This is used internally to note that a diagnostic is enabled
+     without mandating any specific type.  */
+  DK_ANY,
 } diagnostic_t;
 
 /* RAII-style class for grouping related diagnostics.  */
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 8e4621f8031..6ffd6236146 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -1136,8 +1136,7 @@ classify_diagnostic (const diagnostic_context *context,
       if (old_kind == DK_UNSPECIFIED)
        {
          old_kind = !context->option_enabled_p (option_index)
-           ? DK_IGNORED : (context->warning_as_error_requested_p ()
-                           ? DK_ERROR : DK_WARNING);
+           ? DK_IGNORED : DK_ANY;
          m_classify_diagnostic[option_index] = old_kind;
        }
 
@@ -1472,7 +1471,15 @@ diagnostic_context::diagnostic_enabled (diagnostic_info 
*diagnostic)
      option.  */
   if (diag_class == DK_UNSPECIFIED
       && !option_unspecified_p (diagnostic->option_index))
-    diagnostic->kind = m_option_classifier.get_current_override 
(diagnostic->option_index);
+    {
+      const diagnostic_t new_kind
+       = m_option_classifier.get_current_override (diagnostic->option_index);
+      if (new_kind != DK_ANY)
+       /* DK_ANY means the diagnostic is not to be ignored, but we don't want
+          to change it specifically to DK_ERROR or DK_WARNING; we want to
+          preserve whatever the caller has specified.  */
+       diagnostic->kind = new_kind;
+    }
 
   /* This allows for future extensions, like temporarily disabling
      warnings for ranges of source code.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21a.C 
b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21a.C
new file mode 100644
index 00000000000..fa865987e5f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21a.C
@@ -0,0 +1,14 @@
+/* PR c++/111918 */
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "" } Suppress default -pedantic-errors so we can test 
permerror functionality.  */
+extern int g ();
+float f1{123456789}; /* { dg-error "-Wnarrowing" } */
+float f2{g ()}; /* { dg-warning "-Wnarrowing" } */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnarrowing"
+float f3{123456789}; /* { dg-bogus "-Wnarrowing" } */
+float f4{g ()}; /* { dg-bogus "-Wnarrowing" } */
+#pragma GCC diagnostic pop
+float f5{123456789}; /* { dg-bogus "warning" "warning in place of error" } */
+                     /* { dg-error "-Wnarrowing" "" { target *-*-* } .-1 } */
+float f6{g ()}; /* { dg-warning "-Wnarrowing" } */
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21b.C 
b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21b.C
new file mode 100644
index 00000000000..b8049358acc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21b.C
@@ -0,0 +1,9 @@
+/* PR c++/111918 */
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-Wno-error=narrowing" } */
+float f1{123456789}; /* { dg-warning "-Wnarrowing" } */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnarrowing"
+float f2{123456789}; /* { dg-bogus "-Wnarrowing" } */
+#pragma GCC diagnostic pop
+float f3{123456789}; /* { dg-warning "-Wnarrowing" } */
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21c.C 
b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21c.C
new file mode 100644
index 00000000000..6a98dd08176
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21c.C
@@ -0,0 +1,9 @@
+/* PR c++/111918 */
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-fpermissive" } */
+float f1{123456789}; /* { dg-warning "-Wnarrowing" } */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnarrowing"
+float f2{123456789}; /* { dg-bogus "-Wnarrowing" } */
+#pragma GCC diagnostic pop
+float f3{123456789}; /* { dg-warning "-Wnarrowing" } */
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21d.C 
b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21d.C
new file mode 100644
index 00000000000..a371e0a964f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing21d.C
@@ -0,0 +1,9 @@
+/* PR c++/111918 */
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-Wno-narrowing" } */
+float f1{123456789}; /* { dg-bogus "-Wnarrowing" } */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wnarrowing"
+float f2{123456789}; /* { dg-warning "-Wnarrowing" } */
+#pragma GCC diagnostic pop
+float f3{123456789}; /* { dg-bogus "-Wnarrowing" } */

Reply via email to