c++: #pragma doesn't disable -Wunused-label [PR113582]

Message ID 20240126013817.70203-1-polacek@redhat.com
State Accepted
Headers
Series c++: #pragma doesn't disable -Wunused-label [PR113582] |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Marek Polacek Jan. 26, 2024, 1:38 a.m. UTC
  Low prio and not a regression.  Feel free to ignore till GCC 15.

Bootstrapped/regtested on x86_64-pc-linux-gnu.

-- >8 --
The PR complains that

  void do_something(){
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wunused-label"
    start:;
    #pragma GCC diagnostic pop
  } #1

doesn't work.  That's because we warn_for_unused_label only while we're
in finish_function, meaning we're at #1 where we're outside the #pragma
region.  We can use suppress_warning + warning_suppressed_p to fix this.

Note that I'm not using TREE_USED.  Propagating it in tsubst_stmt/LABEL_EXPR
from decl to label would mean that we don't warn in do_something2, but
I think we want the warning there: we're in a template and the goto is
a discarded statement.

	PR c++/113582

gcc/c-family/ChangeLog:

	* c-warn.cc (warn_for_unused_label): Don't warn if -Wunused-label has
	been suppressed for the label.

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_label_for_labeled_statement): suppress_warning
	if it's not enabled at input_location.
	* pt.cc (tsubst_stmt): Call copy_warning.

gcc/testsuite/ChangeLog:

	* g++.dg/warn/Wunused-label-4.C: New test.
---
 gcc/c-family/c-warn.cc                      |  4 ++-
 gcc/cp/parser.cc                            |  6 ++++-
 gcc/cp/pt.cc                                |  9 ++++---
 gcc/testsuite/g++.dg/warn/Wunused-label-4.C | 29 +++++++++++++++++++++
 4 files changed, 42 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/warn/Wunused-label-4.C


base-commit: f22a7ae8a96f7e5e330b12bd5045424619aa4926
  

Comments

Jason Merrill Jan. 26, 2024, 9:06 p.m. UTC | #1
On 1/25/24 20:38, Marek Polacek wrote:
> Low prio and not a regression.  Feel free to ignore till GCC 15.

OK for stage 1.

> Bootstrapped/regtested on x86_64-pc-linux-gnu.
> 
> -- >8 --
> The PR complains that
> 
>    void do_something(){
>      #pragma GCC diagnostic push
>      #pragma GCC diagnostic ignored "-Wunused-label"
>      start:;
>      #pragma GCC diagnostic pop
>    } #1
> 
> doesn't work.  That's because we warn_for_unused_label only while we're
> in finish_function, meaning we're at #1 where we're outside the #pragma
> region.  We can use suppress_warning + warning_suppressed_p to fix this.
> 
> Note that I'm not using TREE_USED.  Propagating it in tsubst_stmt/LABEL_EXPR
> from decl to label would mean that we don't warn in do_something2, but
> I think we want the warning there: we're in a template and the goto is
> a discarded statement.
> 
> 	PR c++/113582
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-warn.cc (warn_for_unused_label): Don't warn if -Wunused-label has
> 	been suppressed for the label.
> 
> gcc/cp/ChangeLog:
> 
> 	* parser.cc (cp_parser_label_for_labeled_statement): suppress_warning
> 	if it's not enabled at input_location.
> 	* pt.cc (tsubst_stmt): Call copy_warning.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/warn/Wunused-label-4.C: New test.
> ---
>   gcc/c-family/c-warn.cc                      |  4 ++-
>   gcc/cp/parser.cc                            |  6 ++++-
>   gcc/cp/pt.cc                                |  9 ++++---
>   gcc/testsuite/g++.dg/warn/Wunused-label-4.C | 29 +++++++++++++++++++++
>   4 files changed, 42 insertions(+), 6 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/warn/Wunused-label-4.C
> 
> diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
> index 8168696fa45..fdb5338f6f6 100644
> --- a/gcc/c-family/c-warn.cc
> +++ b/gcc/c-family/c-warn.cc
> @@ -2186,7 +2186,9 @@ warn_for_unused_label (tree label)
>   {
>     if (!TREE_USED (label))
>       {
> -      if (DECL_INITIAL (label))
> +      if (warning_suppressed_p (label, OPT_Wunused_label))
> +	/* Don't warn.  */;
> +      else if (DECL_INITIAL (label))
>   	warning (OPT_Wunused_label, "label %q+D defined but not used", label);
>         else
>   	warning (OPT_Wunused_label, "label %q+D declared but not defined", label);
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 3748ccd49ff..224d47f2f90 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -13093,7 +13093,11 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
>         /* Anything else must be an ordinary label.  */
>         label = finish_label_stmt (cp_parser_identifier (parser));
>         if (label && TREE_CODE (label) == LABEL_DECL)
> -	FALLTHROUGH_LABEL_P (label) = fallthrough_p;
> +	{
> +	  FALLTHROUGH_LABEL_P (label) = fallthrough_p;
> +	  if (!warning_enabled_at (input_location, OPT_Wunused_label))
> +	    suppress_warning (label, OPT_Wunused_label);
> +	}
>         break;
>       }
>   
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 74013533b0f..af9fd8f6f03 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -18796,11 +18796,12 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>       case LABEL_EXPR:
>         {
>   	tree decl = LABEL_EXPR_LABEL (t);
> -	tree label;
> -
> -	label = finish_label_stmt (DECL_NAME (decl));
> +	tree label = finish_label_stmt (DECL_NAME (decl));
>   	if (TREE_CODE (label) == LABEL_DECL)
> -	  FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
> +	  {
> +	    FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
> +	    copy_warning (label, decl);
> +	  }
>   	if (DECL_ATTRIBUTES (decl) != NULL_TREE)
>   	  cplus_decl_attributes (&label, DECL_ATTRIBUTES (decl), 0);
>         }
> diff --git a/gcc/testsuite/g++.dg/warn/Wunused-label-4.C b/gcc/testsuite/g++.dg/warn/Wunused-label-4.C
> new file mode 100644
> index 00000000000..d194f043d21
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wunused-label-4.C
> @@ -0,0 +1,29 @@
> +// PR c++/113582
> +// { dg-do compile { target c++17 } }
> +// { dg-options "-Wunused-label" }
> +
> +template<bool B> void
> +do_something ()
> +{
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wunused-label"
> +start:
> +  if constexpr(B)
> +    goto start;
> +#pragma GCC diagnostic pop
> +}
> +
> +template<bool B> void
> +do_something2 ()
> +{
> +start: // { dg-warning "defined but not used" }
> +  if constexpr(B)
> +    goto start;
> +}
> +
> +void
> +g ()
> +{
> +  do_something<0>();
> +  do_something2<0>();
> +}
> 
> base-commit: f22a7ae8a96f7e5e330b12bd5045424619aa4926
  

Patch

diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 8168696fa45..fdb5338f6f6 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -2186,7 +2186,9 @@  warn_for_unused_label (tree label)
 {
   if (!TREE_USED (label))
     {
-      if (DECL_INITIAL (label))
+      if (warning_suppressed_p (label, OPT_Wunused_label))
+	/* Don't warn.  */;
+      else if (DECL_INITIAL (label))
 	warning (OPT_Wunused_label, "label %q+D defined but not used", label);
       else
 	warning (OPT_Wunused_label, "label %q+D declared but not defined", label);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3748ccd49ff..224d47f2f90 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -13093,7 +13093,11 @@  cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
       /* Anything else must be an ordinary label.  */
       label = finish_label_stmt (cp_parser_identifier (parser));
       if (label && TREE_CODE (label) == LABEL_DECL)
-	FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+	{
+	  FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+	  if (!warning_enabled_at (input_location, OPT_Wunused_label))
+	    suppress_warning (label, OPT_Wunused_label);
+	}
       break;
     }
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 74013533b0f..af9fd8f6f03 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18796,11 +18796,12 @@  tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case LABEL_EXPR:
       {
 	tree decl = LABEL_EXPR_LABEL (t);
-	tree label;
-
-	label = finish_label_stmt (DECL_NAME (decl));
+	tree label = finish_label_stmt (DECL_NAME (decl));
 	if (TREE_CODE (label) == LABEL_DECL)
-	  FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
+	  {
+	    FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
+	    copy_warning (label, decl);
+	  }
 	if (DECL_ATTRIBUTES (decl) != NULL_TREE)
 	  cplus_decl_attributes (&label, DECL_ATTRIBUTES (decl), 0);
       }
diff --git a/gcc/testsuite/g++.dg/warn/Wunused-label-4.C b/gcc/testsuite/g++.dg/warn/Wunused-label-4.C
new file mode 100644
index 00000000000..d194f043d21
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wunused-label-4.C
@@ -0,0 +1,29 @@ 
+// PR c++/113582
+// { dg-do compile { target c++17 } }
+// { dg-options "-Wunused-label" }
+
+template<bool B> void
+do_something ()
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-label"
+start:
+  if constexpr(B)
+    goto start;
+#pragma GCC diagnostic pop
+}
+
+template<bool B> void
+do_something2 ()
+{
+start: // { dg-warning "defined but not used" }
+  if constexpr(B)
+    goto start;
+}
+
+void
+g ()
+{
+  do_something<0>();
+  do_something2<0>();
+}