-Wdeprecated-copy was depending only on the state of the warning at the
point where we call the function, making it hard to use #pragma diagnostic
to suppress the warning for a particular implicitly declared function.

But checking whether the warning is enabled at the location of the implicit
declaration turned out to be a bit complicated; option_enabled only tests
whether it was enabled at the start of compilation, the actual test only
existed in the middle of diagnostic_report_diagnostic.  So this patch
factors it out and adds a new warning_enabled function to diagnostic.h.

Tested x86_64-pc-linux-gnu, OK for trunk?

gcc/ChangeLog:

        PR c++/94492
        * diagnostic.h (warning_enabled): Declare.
        * diagnostic.c (diagnostic_enabled): Factor out from...
        (diagnostic_report_diagnostic): ...here.
        (warning_enabled): New.

gcc/cp/ChangeLog:

        PR c++/94492
        * decl2.c (cp_warn_deprecated_use): Check warning_enabled.

gcc/testsuite/ChangeLog:

        PR c++/94492
        * g++.dg/cpp0x/depr-copy4.C: New test.
---
 gcc/diagnostic.h                        |  2 +
 gcc/cp/decl2.c                          |  8 +--
 gcc/diagnostic.c                        | 85 +++++++++++++++++--------
 gcc/testsuite/g++.dg/cpp0x/depr-copy4.C | 16 +++++
 4 files changed, 80 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/depr-copy4.C

diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 9a6eefcf918..caa97da2df9 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -515,4 +515,6 @@ extern int num_digits (int);
 extern json::value *json_from_expanded_location (diagnostic_context *context,
                                                 location_t loc);
 
+extern bool warning_enabled (int, location_t = input_location);
+
 #endif /* ! GCC_DIAGNOSTIC_H */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a82960fb39c..03b7a68aba2 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -5495,10 +5495,10 @@ cp_warn_deprecated_use (tree decl, tsubst_flags_t 
complain)
       && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
       && copy_fn_p (decl))
     {
-      if (warn_deprecated_copy
-         /* Don't warn about system library classes (c++/86342).  */
-         && (!DECL_IN_SYSTEM_HEADER (decl)
-             || global_dc->dc_warn_system_headers))
+      /* Don't warn if the flag was disabled around the class definition
+        (c++/94492).  */
+      if (warning_enabled (OPT_Wdeprecated_copy,
+                          DECL_SOURCE_LOCATION (decl)))
        {
          auto_diagnostic_group d;
          tree ctx = DECL_CONTEXT (decl);
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 246d75256cf..278ec8b706f 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -1122,6 +1122,62 @@ print_option_information (diagnostic_context *context,
     }
 }
 
+/* Returns whether a DIAGNOSTIC should be printed, and adjusts diagnostic->kind
+   as appropriate.  */
+
+static bool
+diagnostic_enabled (diagnostic_context *context,
+                   diagnostic_info *diagnostic)
+{
+  /* Diagnostics with no option or -fpermissive are always enabled.  */
+  if (!diagnostic->option_index
+      || diagnostic->option_index == permissive_error_option (context))
+    return true;
+
+  /* This tests if the user provided the appropriate -Wfoo or
+     -Wno-foo option.  */
+  if (! context->option_enabled (diagnostic->option_index,
+                                context->lang_mask,
+                                context->option_state))
+    return false;
+
+  /* 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];
+
+  /* This allows for future extensions, like temporarily disabling
+     warnings for ranges of source code.  */
+  if (diagnostic->kind == DK_IGNORED)
+    return false;
+
+  return true;
+}
+
+/* Returns whether warning OPT is enabled at LOC.  */
+
+bool
+warning_enabled (int opt, location_t loc)
+{
+  if (!diagnostic_report_warnings_p (global_dc, loc))
+    return false;
+
+  rich_location richloc (line_table, loc);
+  diagnostic_info diagnostic = {};
+  diagnostic.option_index = opt;
+  diagnostic.richloc = &richloc;
+  diagnostic.message.m_richloc = &richloc;
+  diagnostic.kind = DK_WARNING;
+  return diagnostic_enabled (global_dc, &diagnostic);
+}
+
 /* Report a diagnostic message (an error or a warning) as specified by
    DC.  This function is *the* subroutine in terms of which front-ends
    should implement their specific diagnostic handling modules.  The
@@ -1172,33 +1228,8 @@ diagnostic_report_diagnostic (diagnostic_context 
*context,
       && diagnostic->kind == DK_WARNING)
     diagnostic->kind = DK_ERROR;
 
-  if (diagnostic->option_index
-      && diagnostic->option_index != permissive_error_option (context))
-    {
-      /* This tests if the user provided the appropriate -Wfoo or
-        -Wno-foo option.  */
-      if (! context->option_enabled (diagnostic->option_index,
-                                    context->lang_mask,
-                                    context->option_state))
-       return false;
-
-      /* 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];
-
-      /* This allows for future extensions, like temporarily disabling
-        warnings for ranges of source code.  */
-      if (diagnostic->kind == DK_IGNORED)
-       return false;
-    }
+  if (!diagnostic_enabled (context, diagnostic))
+    return false;
 
   if (diagnostic->kind != DK_NOTE && diagnostic->kind != DK_ICE)
     diagnostic_check_max_errors (context);
diff --git a/gcc/testsuite/g++.dg/cpp0x/depr-copy4.C 
b/gcc/testsuite/g++.dg/cpp0x/depr-copy4.C
new file mode 100644
index 00000000000..42852a70558
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/depr-copy4.C
@@ -0,0 +1,16 @@
+// PR c++/94492
+// { dg-additional-options -Wdeprecated-copy }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-copy"
+struct expr
+{
+    int a, b;
+    expr& operator=(const expr&) { return *this; }
+};
+#pragma GCC diagnostic pop
+
+expr foo(expr e)
+{
+    return e;
+}

base-commit: f9d670128f6e6b3631a2db575ddf6f19fa43afdc
-- 
2.27.0

Reply via email to