]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: DR 569, DR 1693: fun with semicolons [PR113760]
authorMarek Polacek <polacek@redhat.com>
Tue, 13 Feb 2024 00:36:16 +0000 (19:36 -0500)
committerMarek Polacek <polacek@redhat.com>
Wed, 15 May 2024 17:23:08 +0000 (13:23 -0400)
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.

20 files changed:
gcc/c-family/c.opt
gcc/cp/parser.cc
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/diagnostic/semicolon1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/semicolon9.C [new file with mode: 0644]

index 403abc1f26e18fb8c2ec39095fc8cc937f06a05d..fb34c3b7031966b91559781975ce2a309faf692f 100644 (file)
@@ -727,7 +727,7 @@ C ObjC C++ ObjC++ Warning
 ; in common.opt
 
 Wextra-semi
-C++ ObjC++ Var(warn_extra_semi) Warning
+C++ ObjC++ Var(warn_extra_semi) Init(-1) Warning
 Warn about semicolon after in-class function definition.
 
 Wflex-array-member-not-at-end
index 7306ce9a8a8b19f9cdd4a0a7452944e1cde43e34..476ddc0d63ad3f597123b86e3799d10db40be2e0 100644 (file)
@@ -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;
                }
index ddcd5213f06aedb6a1c2c5b0463fecad0c5df44e..cedc1a28c834a6abd2e5ce4c5cef9afe45c249a6 100644 (file)
@@ -4780,7 +4780,34 @@ undefined behavior at runtime.  This warning is enabled by default.
 @opindex Wextra-semi
 @opindex Wno-extra-semi
 @item -Wextra-semi @r{(C++, Objective-C++ only)}
-Warn about redundant semicolons after in-class function definitions.
+Warn about redundant semicolons.  There are various contexts in which an extra
+semicolon can occur.  One is a semicolon after in-class function definitions,
+which is valid in all C++ dialects (and is never a pedwarn):
+
+@smallexample
+struct S @{
+  void foo () @{@};
+@};
+@end smallexample
+
+Another is an extra semicolon at namespace scope, which has been allowed
+since C++11 (therefore is a pedwarn in C++98):
+
+@smallexample
+struct S @{
+@};
+;
+@end smallexample
+
+And yet another is an extra semicolon in class definitions, which has been
+allowed since C++11 (therefore is a pedwarn in C++98):
+
+@smallexample
+struct S @{
+  int a;
+  ;
+@};
+@end smallexample
 
 @opindex Wno-global-module
 @opindex Wglobal-module
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon1.C b/gcc/testsuite/g++.dg/diagnostic/semicolon1.C
new file mode 100644 (file)
index 0000000..8219d48
--- /dev/null
@@ -0,0 +1,18 @@
+// DR 1693, Superfluous semicolons in class definitions
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "" }
+// { dg-prune-output "only available with" }
+
+struct X { ; };
+
+struct S {
+  void baz () = delete;
+  void qux () = delete;
+  ;
+  void corge () = delete;
+  ;
+  ;
+  int s;
+  ;
+};
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon10.C b/gcc/testsuite/g++.dg/diagnostic/semicolon10.C
new file mode 100644 (file)
index 0000000..4753f55
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-Wextra-semi" }
+
+struct S {
+  void f1 () {}
+  // A single semicolon is valid after a member function definition.
+  void f2 () {}; // { dg-warning "extra .;. after in-class function definition" }
+  void f3 () const;
+};
+void S::f3 () const { }; // { dg-warning "extra .;. outside of a function" }
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon11.C b/gcc/testsuite/g++.dg/diagnostic/semicolon11.C
new file mode 100644 (file)
index 0000000..65df5e9
--- /dev/null
@@ -0,0 +1,29 @@
+// DR 569, Spurious semicolons at namespace scope should be allowed
+// PR c++/113760
+// { dg-options "-pedantic-errors" }
+
+// C++11 allows extra semicolons at namespace scope.
+struct S {
+  void foo();
+};
+;                      // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
+
+void S::foo () {
+};                     // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
+
+namespace N {
+};                     // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
+
+void f();
+;                      // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
+
+void
+f ()
+{
+};                     // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
+
+int x;
+;                      // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon12.C b/gcc/testsuite/g++.dg/diagnostic/semicolon12.C
new file mode 100644 (file)
index 0000000..f3e79f8
--- /dev/null
@@ -0,0 +1,29 @@
+// DR 569, Spurious semicolons at namespace scope should be allowed
+// PR c++/113760
+// { dg-options "" }
+
+// C++11 allows extra semicolons at namespace scope.
+struct S {
+  void foo();
+};
+;
+
+void S::foo () {
+};
+;
+
+namespace N {
+};
+;
+
+void f();
+;
+
+void
+f ()
+{
+};
+;
+
+int x;
+;
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon13.C b/gcc/testsuite/g++.dg/diagnostic/semicolon13.C
new file mode 100644 (file)
index 0000000..c7a4120
--- /dev/null
@@ -0,0 +1,29 @@
+// DR 569, Spurious semicolons at namespace scope should be allowed
+// PR c++/113760
+// { dg-options "-Wpedantic" }
+
+// C++11 allows extra semicolons at namespace scope.
+struct S {
+  void foo();
+};
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+void S::foo () {
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+namespace N {
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+void f();
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+void
+f ()
+{
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+int x;
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon14.C b/gcc/testsuite/g++.dg/diagnostic/semicolon14.C
new file mode 100644 (file)
index 0000000..ac2b985
--- /dev/null
@@ -0,0 +1,29 @@
+// DR 569, Spurious semicolons at namespace scope should be allowed
+// PR c++/113760
+// { dg-options "-pedantic-errors -Wno-extra-semi" }
+
+// C++11 allows extra semicolons at namespace scope.
+struct S {
+  void foo();
+};
+;
+
+void S::foo () {
+};
+;
+
+namespace N {
+};
+;
+
+void f();
+;
+
+void
+f ()
+{
+};
+;
+
+int x;
+;
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon15.C b/gcc/testsuite/g++.dg/diagnostic/semicolon15.C
new file mode 100644 (file)
index 0000000..84b90e4
--- /dev/null
@@ -0,0 +1,29 @@
+// DR 569, Spurious semicolons at namespace scope should be allowed
+// PR c++/113760
+// { dg-options "-Wextra-semi" }
+
+// C++11 allows extra semicolons at namespace scope.
+struct S {
+  void foo();
+};
+;                      // { dg-warning "extra .;. outside of a function" }
+
+void S::foo () {
+};                     // { dg-warning "extra .;. outside of a function" }
+;                      // { dg-warning "extra .;. outside of a function" }
+
+namespace N {
+};                     // { dg-warning "extra .;. outside of a function" }
+;                      // { dg-warning "extra .;. outside of a function" }
+
+void f();
+;                      // { dg-warning "extra .;. outside of a function" }
+
+void
+f ()
+{
+};                     // { dg-warning "extra .;. outside of a function" }
+;                      // { dg-warning "extra .;. outside of a function" }
+
+int x;
+;                      // { dg-warning "extra .;. outside of a function" }
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon16.C b/gcc/testsuite/g++.dg/diagnostic/semicolon16.C
new file mode 100644 (file)
index 0000000..26259ca
--- /dev/null
@@ -0,0 +1,38 @@
+// DR 569, Spurious semicolons at namespace scope should be allowed
+// PR c++/113760
+// { dg-options "-Wextra-semi -pedantic-errors" }
+
+// C++11 allows extra semicolons at namespace scope.
+struct S {
+  void foo();
+};
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
+
+void S::foo () {
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
+
+namespace N {
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
+
+void f();
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
+
+void
+f ()
+{
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
+
+int x;
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++11 } }
+                       // { dg-error "extra .;. outside of a function" "" { target c++98_only } .-1 }
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon17.C b/gcc/testsuite/g++.dg/diagnostic/semicolon17.C
new file mode 100644 (file)
index 0000000..0b8d3f0
--- /dev/null
@@ -0,0 +1,29 @@
+// DR 569, Spurious semicolons at namespace scope should be allowed
+// PR c++/113760
+// { dg-options "-pedantic-errors -Wno-error=extra-semi" }
+
+// C++11 allows extra semicolons at namespace scope.
+struct S {
+  void foo();
+};
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+void S::foo () {
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+namespace N {
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+void f();
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+void
+f ()
+{
+};                     // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
+
+int x;
+;                      // { dg-warning "extra .;. outside of a function" "" { target c++98_only } }
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon2.C b/gcc/testsuite/g++.dg/diagnostic/semicolon2.C
new file mode 100644 (file)
index 0000000..1cfddf1
--- /dev/null
@@ -0,0 +1,18 @@
+// DR 1693, Superfluous semicolons in class definitions
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-Wpedantic" }
+// { dg-prune-output "only available with" }
+
+struct X { ; };                      // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+
+struct S {
+  void baz () = delete;
+  void qux () = delete;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+  void corge () = delete;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+  int s;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+};
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon3.C b/gcc/testsuite/g++.dg/diagnostic/semicolon3.C
new file mode 100644 (file)
index 0000000..265b655
--- /dev/null
@@ -0,0 +1,18 @@
+// DR 1693, Superfluous semicolons in class definitions
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-pedantic-errors" }
+// { dg-prune-output "only available with" }
+
+struct X { ; };                      // { dg-error "extra .;. inside a struct" "" { target c++98_only } }
+
+struct S {
+  void baz () = delete;
+  void qux () = delete;
+  ;                          // { dg-error "extra .;. inside a struct" "" { target c++98_only } }
+  void corge () = delete;
+  ;                          // { dg-error "extra .;. inside a struct" "" { target c++98_only } }
+  ;                          // { dg-error "extra .;. inside a struct" "" { target c++98_only } }
+  int s;
+  ;                          // { dg-error "extra .;. inside a struct" "" { target c++98_only } }
+};
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon4.C b/gcc/testsuite/g++.dg/diagnostic/semicolon4.C
new file mode 100644 (file)
index 0000000..22f7a53
--- /dev/null
@@ -0,0 +1,18 @@
+// DR 1693, Superfluous semicolons in class definitions
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-pedantic-errors -Wno-extra-semi" }
+// { dg-prune-output "only available with" }
+
+struct X { ; };
+
+struct S {
+  void baz () = delete;
+  void qux () = delete;
+  ;
+  void corge () = delete;
+  ;
+  ;
+  int s;
+  ;
+};
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon5.C b/gcc/testsuite/g++.dg/diagnostic/semicolon5.C
new file mode 100644 (file)
index 0000000..41b7bfa
--- /dev/null
@@ -0,0 +1,18 @@
+// DR 1693, Superfluous semicolons in class definitions
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-Wextra-semi" }
+// { dg-prune-output "only available with" }
+
+struct X { ; };                      // { dg-warning "extra .;. inside a struct" }
+
+struct S {
+  void baz () = delete;
+  void qux () = delete;
+  ;                          // { dg-warning "extra .;. inside a struct" }
+  void corge () = delete;
+  ;                          // { dg-warning "extra .;. inside a struct" }
+  ;                          // { dg-warning "extra .;. inside a struct" }
+  int s;
+  ;                          // { dg-warning "extra .;. inside a struct" }
+};
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon6.C b/gcc/testsuite/g++.dg/diagnostic/semicolon6.C
new file mode 100644 (file)
index 0000000..0c92a1e
--- /dev/null
@@ -0,0 +1,23 @@
+// DR 1693, Superfluous semicolons in class definitions
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-Wextra-semi -pedantic-errors" }
+// { dg-prune-output "only available with" }
+
+struct X { ; };                      // { dg-warning "extra .;. inside a struct" "" { target c++11 } }
+                             // { dg-error "extra .;. inside a struct" "" { target c++98_only } .-1 }
+
+struct S {
+  void baz () = delete;
+  void qux () = delete;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++11 } }
+                             // { dg-error "extra .;. inside a struct" "" { target c++98_only } .-1 }
+  void corge () = delete;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++11 } }
+                             // { dg-error "extra .;. inside a struct" "" { target c++98_only } .-1 }
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++11 } }
+                             // { dg-error "extra .;. inside a struct" "" { target c++98_only } .-1 }
+  int s;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++11 } }
+                             // { dg-error "extra .;. inside a struct" "" { target c++98_only } .-1 }
+};
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon7.C b/gcc/testsuite/g++.dg/diagnostic/semicolon7.C
new file mode 100644 (file)
index 0000000..aca4f49
--- /dev/null
@@ -0,0 +1,18 @@
+// DR 1693, Superfluous semicolons in class definitions
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-pedantic-errors -Wno-error=extra-semi" }
+// { dg-prune-output "only available with" }
+
+struct X { ; };                      // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+
+struct S {
+  void baz () = delete;
+  void qux () = delete;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+  void corge () = delete;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+  int s;
+  ;                          // { dg-warning "extra .;. inside a struct" "" { target c++98_only } }
+};
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon8.C b/gcc/testsuite/g++.dg/diagnostic/semicolon8.C
new file mode 100644 (file)
index 0000000..1b0de38
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-pedantic-errors" }
+
+struct S {
+  void f1 () {}
+  // A single semicolon is valid after a member function definition.
+  void f2 () {};
+  void f3 () const;
+};
+void S::f3 () const { }; // { dg-error "extra .;. outside of a function" "" { target c++98_only } }
diff --git a/gcc/testsuite/g++.dg/diagnostic/semicolon9.C b/gcc/testsuite/g++.dg/diagnostic/semicolon9.C
new file mode 100644 (file)
index 0000000..f90539d
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/113760
+// { dg-do compile }
+// { dg-options "-pedantic-errors -Wno-extra-semi" }
+
+struct S {
+  void f1 () {}
+  // A single semicolon is valid after a member function definition.
+  void f2 () {};
+  void f3 () const;
+};
+void S::f3 () const { };