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