diff mbox series

avoid issuing -Wredundant-tags in shared C/C++ code in headers (PR 93804)

Message ID 8ea4fe55-4998-4155-8235-b49a20388c8d@gmail.com
State New
Headers show
Series avoid issuing -Wredundant-tags in shared C/C++ code in headers (PR 93804) | expand

Commit Message

Martin Sebor Feb. 19, 2020, 12:02 a.m. UTC
PR 93804 points out that issuing -Wredundant-tags for declarations
in C headers included in C++ isn't helpful because the tags cannot
be removed without breaking C programs that depend on the headers.

Attached is a patch that avoids the warning in these cases tested
on x86_64-linux.  While strictly not a regression (and even though
I initially considered it a GCC 11 enhancement), since most C++
code includes some C headers, without the patch the warning would
likely cause too much noise to be widely useful.

Martin

Comments

Stephan Bergmann Feb. 19, 2020, 1:46 p.m. UTC | #1
On 19/02/2020 01:02, Martin Sebor wrote:
> PR 93804 points out that issuing -Wredundant-tags for declarations
> in C headers included in C++ isn't helpful because the tags cannot
> be removed without breaking C programs that depend on the headers.
> 
> Attached is a patch that avoids the warning in these cases tested
> on x86_64-linux.  While strictly not a regression (and even though
> I initially considered it a GCC 11 enhancement), since most C++
> code includes some C headers, without the patch the warning would
> likely cause too much noise to be widely useful.

Warnings about redundant enum tags in shared C/C++ code should likewise 
be suppressed.  Something like the attached patch.
Jason Merrill Feb. 20, 2020, 12:09 a.m. UTC | #2
On 2/19/20 1:02 AM, Martin Sebor wrote:
> PR 93804 points out that issuing -Wredundant-tags for declarations
> in C headers included in C++ isn't helpful because the tags cannot
> be removed without breaking C programs that depend on the headers.
> 
> Attached is a patch that avoids the warning in these cases tested
> on x86_64-linux.  While strictly not a regression (and even though
> I initially considered it a GCC 11 enhancement), since most C++
> code includes some C headers, without the patch the warning would
> likely cause too much noise to be widely useful.

> +      const line_map_ordinary *map = NULL;
> +      linemap_resolve_location (line_table, key_loc,
> +				LRK_MACRO_DEFINITION_LOCATION,
> +				&map);
> +      if (!MAIN_FILE_P (map))
> +	key_redundant = false;

Checking which file it came from seems like unnecessary complication; 
is it important to still warn in extern "C" blocks in the main source file?

Jason
Martin Sebor Feb. 20, 2020, 10:55 p.m. UTC | #3
On 2/19/20 5:09 PM, Jason Merrill wrote:
> On 2/19/20 1:02 AM, Martin Sebor wrote:
>> PR 93804 points out that issuing -Wredundant-tags for declarations
>> in C headers included in C++ isn't helpful because the tags cannot
>> be removed without breaking C programs that depend on the headers.
>>
>> Attached is a patch that avoids the warning in these cases tested
>> on x86_64-linux.  While strictly not a regression (and even though
>> I initially considered it a GCC 11 enhancement), since most C++
>> code includes some C headers, without the patch the warning would
>> likely cause too much noise to be widely useful.
> 
>> +      const line_map_ordinary *map = NULL;
>> +      linemap_resolve_location (line_table, key_loc,
>> +                LRK_MACRO_DEFINITION_LOCATION,
>> +                &map);
>> +      if (!MAIN_FILE_P (map))
>> +    key_redundant = false;
> 
> Checking which file it came from seems like unnecessary complication; is 
> it important to still warn in extern "C" blocks in the main source file?

It's only important if someone is relying on it to avoid the redundant
tags in all their C++ code, e.g., as part of cleaning up -Wmismatched-
tags.  The latter will complain about mismatches in extern "C" blocks
and suggest either dropping the tag or replacing it, whichever is
appropriate.  I'd view it as a bug if -Wredundant-tags didn't do
the same since that's its one and only job.

I attach a slightly revised patch that also handles enums (as pointed
out by Stephan), and with beefed up tests.  Retested on x86_64-linux.

If you find the linemap code distracting, or even the warning code,
I can factor it out and into a helper function.

Martin
Jason Merrill Feb. 24, 2020, 3:56 p.m. UTC | #4
On 2/20/20 5:55 PM, Martin Sebor wrote:
> On 2/19/20 5:09 PM, Jason Merrill wrote:
>> On 2/19/20 1:02 AM, Martin Sebor wrote:
>>> PR 93804 points out that issuing -Wredundant-tags for declarations
>>> in C headers included in C++ isn't helpful because the tags cannot
>>> be removed without breaking C programs that depend on the headers.
>>>
>>> Attached is a patch that avoids the warning in these cases tested
>>> on x86_64-linux.  While strictly not a regression (and even though
>>> I initially considered it a GCC 11 enhancement), since most C++
>>> code includes some C headers, without the patch the warning would
>>> likely cause too much noise to be widely useful.
>>
>>> +      const line_map_ordinary *map = NULL;
>>> +      linemap_resolve_location (line_table, key_loc,
>>> +                LRK_MACRO_DEFINITION_LOCATION,
>>> +                &map);
>>> +      if (!MAIN_FILE_P (map))
>>> +    key_redundant = false;
>>
>> Checking which file it came from seems like unnecessary complication; 
>> is it important to still warn in extern "C" blocks in the main source 
>> file?
> 
> It's only important if someone is relying on it to avoid the redundant
> tags in all their C++ code, e.g., as part of cleaning up -Wmismatched-
> tags.  The latter will complain about mismatches in extern "C" blocks
> and suggest either dropping the tag or replacing it, whichever is
> appropriate.  I'd view it as a bug if -Wredundant-tags didn't do
> the same since that's its one and only job.
> 
> I attach a slightly revised patch that also handles enums (as pointed
> out by Stephan), and with beefed up tests.  Retested on x86_64-linux.
> 
> If you find the linemap code distracting, or even the warning code,
> I can factor it out and into a helper function.

> +      && current_lang_name != lang_name_cplusplus
> +      && current_namespace == global_namespace)
> +    {
> +      /* Avoid issuing the diagnostic for apparently redundant (unscoped)
> +	 enum tag in shared C/C++ code in files (such as headers) included
> +	 in the main source file.  */
> +      const line_map_ordinary *map = NULL;
> +      linemap_resolve_location (line_table, key_loc,
> +				LRK_MACRO_DEFINITION_LOCATION,
> +				&map);
> +      if (!MAIN_FILE_P (map))
> +	return;

This much is common between the enum and class functions and could be 
factored out, but I don't feel strongly about it.  Also, why 
LRK_MACRO_DEFINITION_LOCATION rather than LRK_SPELLING_LOCATION?

> +  /* Only consider the true class-keys below and ignore typename_type,
> +     etc. that are not C++ class-keys.  */
> +  if (class_key != class_type
> +      && class_key != record_type
> +      && class_key != union_type)
> +    return;
> +
>    /* Only consider the true class-keys below and ignore typename_type,
>       etc. that are not C++ class-keys.  */
>    if (class_key != class_type

This looks like a rebase glitch adding the same code again.  OK without 
this hunk.

Jason
diff mbox series

Patch

PR c++/93804 - exempt extern C headers from -Wredundant-tags

gcc/cp/ChangeLog:

	PR c++/93804
	* parser.c (cp_parser_check_class_key): Avoid issuing -Wredundant-tags
	in shared C/C++ code in headers.

gcc/testsuite/ChangeLog:

	PR c++/93804
	* g++.dg/warn/Wredundant-tags-4.C: New test.
	* g++.dg/warn/Wredundant-tags-5.C: New test.
	* g++.dg/warn/Wredundant-tags-5.h: New test.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e8a536ae22f..2c6f5522bf3 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -30999,15 +30999,32 @@  cp_parser_check_class_key (cp_parser *parser, location_t key_loc,
      neither definitions of it nor declarations, and for which name
      lookup returns just the type itself.  */
   bool key_redundant = !def_p && !decl_p && decl == type_decl;
+
+  if (key_redundant
+      && class_key != class_type
+      && current_lang_name != lang_name_cplusplus
+      && current_namespace == global_namespace)
+    {
+      /* Avoid issuing the diagnostic for apparently redundant struct
+	 and union class-keys in shared C/C++ code in files (such as
+	 headers) included in the main source file.  */
+      const line_map_ordinary *map = NULL;
+      linemap_resolve_location (line_table, key_loc,
+				LRK_MACRO_DEFINITION_LOCATION,
+				&map);
+      if (!MAIN_FILE_P (map))
+	key_redundant = false;
+    }
+
   if (key_redundant)
     {
       gcc_rich_location richloc (key_loc);
       richloc.add_fixit_remove (key_loc);
       warning_at (&richloc, OPT_Wredundant_tags,
-		"redundant class-key %qs in reference to %q#T",
-		class_key == union_type ? "union"
-		: class_key == record_type ? "struct" : "class",
-		type);
+		  "redundant class-key %qs in reference to %q#T",
+		  class_key == union_type ? "union"
+		  : class_key == record_type ? "struct" : "class",
+		  type);
     }
 
   if (seen_as_union || !warn_mismatched_tags)
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-4.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-4.C
new file mode 100644
index 00000000000..1a5833e6994
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wredundant-tags-4.C
@@ -0,0 +1,92 @@ 
+/* PR c++/93804 - exempt extern "C" headers from -Wredundant-tags
+   Verify that -Wredundant-tags is not issued for redundant class-key
+   in extern "C" references in a header file.
+   { dg-do compile }
+   { dg-options "-Wredundant-tags" }  */
+
+# 1 "Wredundant-tags-4.C"
+# 1 "Wredundant-tags-4.h" 1
+extern "C" {
+
+class C1 { };
+struct S1 { };
+union U1 { };
+
+# line 16
+  /* The warning should be issued for the class-key class even in
+     an extern "C" block.  */
+  void f0 (class C1);     // { dg-warning "\\\[-Wredundant-tags" }
+  void f1 (struct S1);    // { dg-bogus "\\\[-Wredundant-tags" }
+  void f2 (union U1);     // { dg-bogus "\\\[-Wredundant-tags" }
+
+  inline int
+  finline1 (class C1)     // { dg-warning "\\\[-Wredundant-tags" }
+  { return sizeof (class C1); }   // { dg-warning "\\\[-Wredundant-tags" }
+
+  inline int
+  finline2 (struct S1)    // { dg-bogus "\\\[-Wredundant-tags" }
+  { return sizeof (struct S1); }
+
+  inline int
+  finline3 (union U1)     // { dg-bogus "\\\[-Wredundant-tags" }
+  { return sizeof (union U1); }
+
+  extern class C1 c1;     // { dg-warning "\\\[-Wredundant-tags" }
+  extern struct S1 s1;    // { dg-bogus "\\\[-Wredundant-tags" }
+  extern union U1 u1;     // { dg-bogus "\\\[-Wredundant-tags" }
+
+  namespace N1 {
+  /* Verify that -Wredundant-tags is issued in a namespace enclosed
+     in an extern "C" block.  (Such code cannot be shared with C.)  */
+  extern class C1 n1c1;   // { dg-warning "\\\[-Wredundant-tags" }
+  extern struct S1 n1s1;  // { dg-warning "\\\[-Wredundant-tags" }
+  extern union U1 n1u1;   // { dg-warning "\\\[-Wredundant-tags" }
+  }
+}
+
+
+extern "C++" {
+
+class C2 { };
+struct S2 { };
+union U2 { };
+
+  void f3 (class C2);     // { dg-warning "\\\[-Wredundant-tags" }
+  void f4 (struct S2);    // { dg-warning "\\\[-Wredundant-tags" }
+  void f5 (union U2);     // { dg-warning "\\\[-Wredundant-tags" }
+
+  extern class C2 c2;     // { dg-warning "\\\[-Wredundant-tags" }
+  extern struct S2 s2;    // { dg-warning "\\\[-Wredundant-tags" }
+  extern union U2 u2;     // { dg-warning "\\\[-Wredundant-tags" }
+}
+
+
+namespace N {
+
+class C3 { };
+struct S3 { };
+union U3 { };
+
+void f6 (class C3);       // { dg-warning "\\\[-Wredundant-tags" }
+void f7 (struct S3);      // { dg-warning "\\\[-Wredundant-tags" }
+void f8 (union U3);       // { dg-warning "\\\[-Wredundant-tags" }
+
+extern class C3 c3;       // { dg-warning "\\\[-Wredundant-tags" }
+extern struct S3 s3;      // { dg-warning "\\\[-Wredundant-tags" }
+extern union U3 u3;       // { dg-warning "\\\[-Wredundant-tags" }
+
+extern "C" {
+
+  /* Verify that -Wredundant-tags is issued in an extern "C" block
+     enclosed within a namespace.  (Such code cannot be shared with
+     C.)  */
+  class C4 { };
+  struct S4 { };
+  union U4 { };
+
+  extern class C4 c4;     // { dg-warning "\\\[-Wredundant-tags" }
+  extern struct S4 s4;    // { dg-warning "\\\[-Wredundant-tags" }
+  extern union U4 u4;     // { dg-warning "\\\[-Wredundant-tags" }
+}
+
+}   // namespace N
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.C
new file mode 100644
index 00000000000..9bb5cc4e1b5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.C
@@ -0,0 +1,49 @@ 
+// PR c++/93804 - exempt extern "C" headers from -Wredundant-tags
+// Verify that -Wredundant-tags is issued even for redundant class-key
+// in references in the main source file to extern "C" classes defined
+// in headers.
+// { dg-do compile }
+// { dg-options "-Wredundant-tags" }
+
+#include "Wredundant-tags-5.h"
+
+extern "C" {
+
+  void f0 (class C1)      // { dg-warning "\\\[-Wredundant-tags" }
+  {
+  }
+
+  void f1 (struct S1)     // { dg-warning "\\\[-Wredundant-tags" }
+  {
+  }
+
+  void f2 (union U1)      // { dg-warning "\\\[-Wredundant-tags" }
+  {
+  }
+
+}
+
+void f3 (class C2)        // { dg-warning "\\\[-Wredundant-tags" }
+{
+}
+
+void f4 (struct S2)       // { dg-warning "\\\[-Wredundant-tags" }
+{
+}
+
+void f5 (union U2)        // { dg-warning "\\\[-Wredundant-tags" }
+{
+}
+
+
+void f6 (class C3)        // { dg-warning "\\\[-Wredundant-tags" }
+{
+}
+
+void f7 (struct S3)       // { dg-warning "\\\[-Wredundant-tags" }
+{
+}
+
+void f8 (union U3)        // { dg-warning "\\\[-Wredundant-tags" }
+{
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.h b/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.h
new file mode 100644
index 00000000000..c9c2ec278c8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.h
@@ -0,0 +1,58 @@ 
+#ifndef WREDUNDANT_TAGS_H
+#define WREDUNDANT_TAGS_H
+
+extern "C" {
+
+class C1 { };
+struct S1 { };
+union U1 { };
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-tags"
+  void f0 (class C1);     // -Wredundant-tags
+#pragma GCC diagnostic pop
+
+  void f1 (struct S1);
+  void f2 (union U1);
+
+  void f0 (C1);
+  void f1 (S1);
+  void f2 (U1);
+}
+
+
+extern "C++" {
+
+class C2 { };
+struct S2 { };
+union U2 { };
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-tags"
+  void f3 (class C2);     // -Wredundant-tags
+  void f4 (struct S2);    // -Wredundant-tags
+  void f5 (union U2);     // -Wredundant-tags
+#pragma GCC diagnostic pop
+
+  void f3 (C2);
+  void f4 (S2);
+  void f5 (U2);
+}
+
+
+class C3 { };
+struct S3 { };
+union U3 { };
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-tags"
+  void f6 (class C3);     // -Wredundant-tags
+  void f7 (struct S3);    // -Wredundant-tags
+  void f8 (union U3);     // -Wredundant-tags
+#pragma GCC diagnostic pop
+
+  void f6 (C3);
+  void f7 (S3);
+  void f8 (U3);
+
+#endif   // WREDUNDANT_TAGS_H