diff options
author | Marek Polacek <polacek@redhat.com> | 2024-02-12 19:36:16 -0500 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2024-05-15 13:23:08 -0400 |
commit | 0b3eac4b54a52bf206b88743d1e987badc97cff4 (patch) | |
tree | 24554e7cde20e07745d3810ceae5ded21d9009ce /gcc/cp | |
parent | 6ad7ca1bb905736c0f57688e93e9e77cbc71a325 (diff) | |
download | gcc-0b3eac4b54a52bf206b88743d1e987badc97cff4.zip gcc-0b3eac4b54a52bf206b88743d1e987badc97cff4.tar.gz gcc-0b3eac4b54a52bf206b88743d1e987badc97cff4.tar.bz2 |
c++: DR 569, DR 1693: fun with semicolons [PR113760]
Prompted by c++/113760, I started looking into a bogus "extra ;"
warning in C++11. It quickly turned out that if I want to fix
this for good, the fix will not be so small.
This patch touches on DR 569, an extra ; at namespace scope should
be allowed since C++11:
struct S {
};
; // pedwarn in C++98
It also touches on DR 1693, which allows superfluous semicolons in
class definitions since C++11:
struct S {
int a;
; // pedwarn in C++98
};
Note that a single semicolon is valid after a member function definition:
struct S {
void foo () {}; // only warns with -Wextra-semi
};
There's a new function maybe_warn_extra_semi to handle all of the above
in a single place. So now they all get a fix-it hint.
-Wextra-semi turns on all "extra ;" diagnostics. Currently, options
like -Wc++11-compat or -Wc++11-extensions are not considered.
DR 1693
PR c++/113760
DR 569
gcc/c-family/ChangeLog:
* c.opt (Wextra-semi): Initialize to -1.
gcc/cp/ChangeLog:
* parser.cc (extra_semi_kind): New.
(maybe_warn_extra_semi): New.
(cp_parser_declaration): Call maybe_warn_extra_semi.
(cp_parser_member_declaration): Likewise.
gcc/ChangeLog:
* doc/invoke.texi: Update -Wextra-semi documentation.
gcc/testsuite/ChangeLog:
* g++.dg/diagnostic/semicolon1.C: New test.
* g++.dg/diagnostic/semicolon10.C: New test.
* g++.dg/diagnostic/semicolon11.C: New test.
* g++.dg/diagnostic/semicolon12.C: New test.
* g++.dg/diagnostic/semicolon13.C: New test.
* g++.dg/diagnostic/semicolon14.C: New test.
* g++.dg/diagnostic/semicolon15.C: New test.
* g++.dg/diagnostic/semicolon16.C: New test.
* g++.dg/diagnostic/semicolon17.C: New test.
* g++.dg/diagnostic/semicolon2.C: New test.
* g++.dg/diagnostic/semicolon3.C: New test.
* g++.dg/diagnostic/semicolon4.C: New test.
* g++.dg/diagnostic/semicolon5.C: New test.
* g++.dg/diagnostic/semicolon6.C: New test.
* g++.dg/diagnostic/semicolon7.C: New test.
* g++.dg/diagnostic/semicolon8.C: New test.
* g++.dg/diagnostic/semicolon9.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/parser.cc | 92 |
1 files changed, 75 insertions, 17 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 7306ce9..476ddc0 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -15331,6 +15331,61 @@ cp_parser_module_export (cp_parser *parser) module_kind = mk; } +/* Used for maybe_warn_extra_semi. */ + +enum class extra_semi_kind { decl, member, in_class_fn_def }; + +/* Warn about an extra semicolon. KIND says in which context the extra + semicolon occurs. */ + +static void +maybe_warn_extra_semi (location_t loc, extra_semi_kind kind) +{ + /* -Wno-extra-semi suppresses all. */ + if (warn_extra_semi == 0) + return; + + gcc_rich_location richloc (loc); + richloc.add_fixit_remove (); + + switch (kind) + { + case extra_semi_kind::decl: + /* If -Wextra-semi wasn't specified, warn only when -pedantic is in + effect in C++98. DR 569 says that spurious semicolons at namespace + scope should be allowed. */ + if (pedantic && cxx_dialect < cxx11) + pedwarn (&richloc, OPT_Wextra_semi, + "extra %<;%> outside of a function only allowed in C++11"); + else if (warn_extra_semi > 0) + warning_at (&richloc, OPT_Wextra_semi, + "extra %<;%> outside of a function"); + break; + + case extra_semi_kind::member: + /* If -Wextra-semi wasn't specified, warn only when -pedantic is in + effect in C++98. DR 1693 added "empty-declaration" to the syntax for + "member-declaration". */ + if (pedantic && cxx_dialect < cxx11) + pedwarn (&richloc, OPT_Wextra_semi, + "extra %<;%> inside a struct only allowed in C++11"); + else if (warn_extra_semi > 0) + warning_at (&richloc, OPT_Wextra_semi, "extra %<;%> inside a struct"); + break; + + case extra_semi_kind::in_class_fn_def: + /* A single semicolon is valid after a member function definition + so this is just a warning. */ + if (warn_extra_semi > 0) + warning_at (&richloc, OPT_Wextra_semi, + "extra %<;%> after in-class function definition"); + break; + + default: + gcc_unreachable (); + } +} + /* Declarations [gram.dcl.dcl] */ /* Parse an optional declaration-sequence. TOP_LEVEL is true, if this @@ -15430,11 +15485,11 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs) if (token1->type == CPP_SEMICOLON) { - cp_lexer_consume_token (parser->lexer); + location_t semicolon_loc + = cp_lexer_consume_token (parser->lexer)->location; /* A declaration consisting of a single semicolon is invalid - * before C++11. Allow it unless we're being pedantic. */ - if (cxx_dialect < cxx11) - pedwarn (input_location, OPT_Wpedantic, "extra %<;%>"); + before C++11. Allow it unless we're being pedantic. */ + maybe_warn_extra_semi (semicolon_loc, extra_semi_kind::decl); return; } else if (cp_lexer_nth_token_is (parser->lexer, @@ -28121,19 +28176,25 @@ cp_parser_member_declaration (cp_parser* parser) struct S { ; }; - [class.mem] + [class.mem] used to say Each member-declaration shall declare at least one member - name of the class. */ + name of the class. + + but since DR 1693: + + A member-declaration does not declare new members of the class + if it is + -- [...] + -- an empty-declaration. + For any other member-declaration, each declared entity that is not + an unnamed bit-field is a member of the class, and each such + member-declaration shall either declare at least one member name of + the class or declare at least one unnamed bit-field. */ if (!decl_specifiers.any_specifiers_p) { cp_token *token = cp_lexer_peek_token (parser->lexer); - if (cxx_dialect < cxx11 && !in_system_header_at (token->location)) - { - gcc_rich_location richloc (token->location); - richloc.add_fixit_remove (); - pedwarn (&richloc, OPT_Wpedantic, "extra %<;%>"); - } + maybe_warn_extra_semi (token->location, extra_semi_kind::member); } else { @@ -28564,11 +28625,8 @@ cp_parser_member_declaration (cp_parser* parser) { location_t semicolon_loc = cp_lexer_consume_token (parser->lexer)->location; - gcc_rich_location richloc (semicolon_loc); - richloc.add_fixit_remove (); - warning_at (&richloc, OPT_Wextra_semi, - "extra %<;%> after in-class " - "function definition"); + maybe_warn_extra_semi (semicolon_loc, + extra_semi_kind::in_class_fn_def); } goto out; } |