On Thu, May 09, 2024 at 12:44:52PM -0400, Jason Merrill wrote:
> On 5/9/24 12:16, Marek Polacek wrote:
> > +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 (warn_extra_semi > 0)
> > +   warning_at (&richloc, OPT_Wextra_semi,
> > +               "extra %<;%> outside of a function");
> > +      /* 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.  */
> > +      else if (pedantic && cxx_dialect < cxx11)
> > +   pedwarn (&richloc, OPT_Wextra_semi,
> > +            "extra %<;%> outside of a function only allowed in C++11");
> 
> Shouldn't the pedwarn case come first?

Yes, I suppose we want both
-Wpedantic -std=c++98
-Wpedantic -std=c++98 -Wextra-semi
to give pedwarns.  Fixed.
 
> > +      break;
> > +
> > +    case extra_semi_kind::member:
> > +      if (warn_extra_semi > 0)
> > +   warning_at (&richloc, OPT_Wextra_semi, "extra %<;%> inside a struct");
> > +      /* 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".  */
> > +      else if (pedantic && cxx_dialect < cxx11)
> > +   pedwarn (&richloc, OPT_Wextra_semi,
> > +            "extra %<;%> inside a struct only allowed in C++11");
> 
> And here.

Fixed too.

> > +      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,27 @@ 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 %<;%>");
> > -       }
> > +     // ??? Should we check !in_system_header_at in maybe_warn_extra_semi?
> 
> The system header check seems to date back to PR 12479.  Apparently it has
> not ever proved necessary for the other cases.
> 
> Furthermore, all pedwarns are now ignored in system headers unless
> -Wsystem-headers is specified, in which case it would seem useful to report
> this.
> 
> So, my inclination is to drop the system header check entirely at this
> point.

Done.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
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.
---
 gcc/c-family/c.opt                            |  2 +-
 gcc/cp/parser.cc                              | 92 +++++++++++++++----
 gcc/doc/invoke.texi                           | 29 +++++-
 gcc/testsuite/g++.dg/diagnostic/semicolon1.C  | 18 ++++
 gcc/testsuite/g++.dg/diagnostic/semicolon10.C | 11 +++
 gcc/testsuite/g++.dg/diagnostic/semicolon11.C | 29 ++++++
 gcc/testsuite/g++.dg/diagnostic/semicolon12.C | 29 ++++++
 gcc/testsuite/g++.dg/diagnostic/semicolon13.C | 29 ++++++
 gcc/testsuite/g++.dg/diagnostic/semicolon14.C | 29 ++++++
 gcc/testsuite/g++.dg/diagnostic/semicolon15.C | 29 ++++++
 gcc/testsuite/g++.dg/diagnostic/semicolon16.C | 38 ++++++++
 gcc/testsuite/g++.dg/diagnostic/semicolon17.C | 29 ++++++
 gcc/testsuite/g++.dg/diagnostic/semicolon2.C  | 18 ++++
 gcc/testsuite/g++.dg/diagnostic/semicolon3.C  | 18 ++++
 gcc/testsuite/g++.dg/diagnostic/semicolon4.C  | 18 ++++
 gcc/testsuite/g++.dg/diagnostic/semicolon5.C  | 18 ++++
 gcc/testsuite/g++.dg/diagnostic/semicolon6.C  | 23 +++++
 gcc/testsuite/g++.dg/diagnostic/semicolon7.C  | 18 ++++
 gcc/testsuite/g++.dg/diagnostic/semicolon8.C  | 11 +++
 gcc/testsuite/g++.dg/diagnostic/semicolon9.C  | 11 +++
 20 files changed, 480 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon1.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon10.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon11.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon12.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon13.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon14.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon15.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon16.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon17.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon2.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon3.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon4.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon5.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon6.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon7.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon8.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon9.C

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 403abc1f26e..fb34c3b7031 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -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
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 7306ce9a8a8..476ddc0d63a 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;
                }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ddcd5213f06..cedc1a28c83 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
index 00000000000..8219d488f4d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon1.C
@@ -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
index 00000000000..4753f557453
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon10.C
@@ -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
index 00000000000..65df5e9abe6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon11.C
@@ -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
index 00000000000..f3e79f80bf0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon12.C
@@ -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
index 00000000000..c7a41202347
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon13.C
@@ -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
index 00000000000..ac2b985f3a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon14.C
@@ -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
index 00000000000..84b90e4ea35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon15.C
@@ -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
index 00000000000..26259cae552
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon16.C
@@ -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
index 00000000000..0b8d3f006e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon17.C
@@ -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
index 00000000000..1cfddf17e9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon2.C
@@ -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
index 00000000000..265b655a8fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon3.C
@@ -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
index 00000000000..22f7a539aed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon4.C
@@ -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
index 00000000000..41b7bfa2ed8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon5.C
@@ -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
index 00000000000..0c92a1e9523
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon6.C
@@ -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
index 00000000000..aca4f49785d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon7.C
@@ -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
index 00000000000..1b0de384dbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon8.C
@@ -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
index 00000000000..f90539d3bd7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/semicolon9.C
@@ -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 { };

base-commit: 54ba8d44bbd703bca6984700b4d6f978890097e2
-- 
2.45.0

Reply via email to