aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.cc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2024-02-12 19:36:16 -0500
committerMarek Polacek <polacek@redhat.com>2024-05-15 13:23:08 -0400
commit0b3eac4b54a52bf206b88743d1e987badc97cff4 (patch)
tree24554e7cde20e07745d3810ceae5ded21d9009ce /gcc/cp/parser.cc
parent6ad7ca1bb905736c0f57688e93e9e77cbc71a325 (diff)
downloadgcc-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/parser.cc')
-rw-r--r--gcc/cp/parser.cc92
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;
}