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
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