https://github.com/keinflue updated 
https://github.com/llvm/llvm-project/pull/172209

>From 06f7ef593726a505d9d08dfd6139a341d49cd9c2 Mon Sep 17 00:00:00 2001
From: keinflue <[email protected]>
Date: Sun, 14 Dec 2025 13:15:03 +0100
Subject: [PATCH 1/2] [clang] Allow extra semicolons inside classes also in C++
 pedantic mode.

With DR 1693 and DR 3079 C++ also allows empty declaration, i.e. extra
semicolons, inside class member declaration lists in all contexts.

This removes warnings for such extra semicolons from -pedantic but keeps them as
a C++98 compatibility warning as well as -Wextra-semi, analogously to extra
semicolons at namespace scope.

fixes #155538
---
 clang/docs/ReleaseNotes.rst                   |  4 ++
 .../clang/Basic/DiagnosticParseKinds.td       | 14 ++++--
 clang/lib/Parse/Parser.cpp                    | 35 +++++++++-----
 clang/test/Parser/cxx-class.cpp               | 11 +++--
 clang/test/Parser/cxx-extra-semi.cpp          | 46 ++++++++++++++++++-
 clang/test/Parser/cxx0x-decl.cpp              |  9 ----
 6 files changed, 91 insertions(+), 28 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index feaf92ad4415f..1578713943665 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -211,6 +211,10 @@ C++17 Feature Support
 Resolutions to C++ Defect Reports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+- Implement DR1693 and DR3079 by allowing extra semicolons inside class member
+  declaration lists even in -pedantic mode. The warnings are still available
+  with -Wextra-semi. (#GH155538)
+
 C Language Changes
 ------------------
 
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 442a90ec2472d..9ce9748762b65 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -40,8 +40,12 @@ let CategoryName = "Parse Issue" in {
 def ext_empty_translation_unit : Extension<
   "ISO C requires a translation unit to contain at least one declaration">,
   InGroup<DiagGroup<"empty-translation-unit">>;
-def warn_cxx98_compat_top_level_semi : Warning<
-  "extra ';' outside of a function is incompatible with C++98">,
+def warn_cxx98_compat_extra_semi : Warning<
+  "%select{|||multiple }0extra ';' %select{"
+  "outside of a function|"
+  "inside a %1|"
+  "inside instance variable list|"
+  "after member function definition}0 is incompatible with C++98">,
   InGroup<CXX98CompatExtraSemi>, DefaultIgnore;
 def ext_extra_semi : Extension<
   "extra ';' %select{"
@@ -51,7 +55,11 @@ def ext_extra_semi : Extension<
   "after member function definition}0">,
   InGroup<ExtraSemi>;
 def ext_extra_semi_cxx11 : Extension<
-  "extra ';' outside of a function is a C++11 extension">,
+  "%select{|||multiple }0extra ';' %select{"
+  "outside of a function|"
+  "inside a %1|"
+  "inside instance variable list|"
+  "after member function definition}0 is a C++11 extension">,
   InGroup<CXX11ExtraSemi>;
 def warn_extra_semi_after_mem_fn_def : Warning<
   "extra ';' after member function definition">,
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 7b425dd3dda43..6325238d6ef75 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -205,27 +205,40 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, 
DeclSpec::TST TST) {
     ConsumeToken();
   }
 
+  if (Kind == ExtraSemiKind::AfterMemberFunctionDefinition &&
+      !HadMultipleSemis) {
+    // A single semicolon is valid after a member function definition.
+    Diag(StartLoc, diag::warn_extra_semi_after_mem_fn_def)
+        << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
+    return;
+  }
+
   // C++11 allows extra semicolons at namespace scope, but not in any of the
   // other contexts.
-  if (Kind == ExtraSemiKind::OutsideFunction && getLangOpts().CPlusPlus) {
+  // DR 1693 and DR 3079 extend this to class scope as well.
+  if ((Kind == ExtraSemiKind::OutsideFunction ||
+       Kind == ExtraSemiKind::InsideStruct ||
+       Kind == ExtraSemiKind::AfterMemberFunctionDefinition) &&
+      getLangOpts().CPlusPlus) {
     if (getLangOpts().CPlusPlus11)
-      Diag(StartLoc, diag::warn_cxx98_compat_top_level_semi)
+      Diag(StartLoc, diag::warn_cxx98_compat_extra_semi)
+          << Kind
+          << DeclSpec::getSpecifierName(
+                 TST, Actions.getASTContext().getPrintingPolicy())
           << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
     else
       Diag(StartLoc, diag::ext_extra_semi_cxx11)
+          << Kind
+          << DeclSpec::getSpecifierName(
+                 TST, Actions.getASTContext().getPrintingPolicy())
           << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
     return;
   }
 
-  if (Kind != ExtraSemiKind::AfterMemberFunctionDefinition || HadMultipleSemis)
-    Diag(StartLoc, diag::ext_extra_semi)
-        << Kind
-        << DeclSpec::getSpecifierName(
-               TST, Actions.getASTContext().getPrintingPolicy())
-        << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
-  else
-    // A single semicolon is valid after a member function definition.
-    Diag(StartLoc, diag::warn_extra_semi_after_mem_fn_def)
+  Diag(StartLoc, diag::ext_extra_semi)
+      << Kind
+      << DeclSpec::getSpecifierName(TST,
+                                    
Actions.getASTContext().getPrintingPolicy())
       << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
 }
 
diff --git a/clang/test/Parser/cxx-class.cpp b/clang/test/Parser/cxx-class.cpp
index a6757f39146a1..44665026c4fa0 100644
--- a/clang/test/Parser/cxx-class.cpp
+++ b/clang/test/Parser/cxx-class.cpp
@@ -20,11 +20,16 @@ class C {
   ; // ok, one extra ';' is permitted
   void m() {
     int l = 2;
-  };; // expected-warning{{extra ';' after member function definition}}
-
+  };;
+#if __cplusplus < 201103L
+  // expected-warning@-2{{extra ';' after member function definition is a 
C++11 extension}}
+#endif
   template<typename T> void mt(T) { }
   ;
-  ; // expected-warning{{extra ';' inside a class}}
+  ;
+#if __cplusplus < 201103L
+  // expected-warning@-2{{extra ';' inside a class is a C++11 extension}}
+#endif
 
   virtual int vf() const volatile = 0;
 
diff --git a/clang/test/Parser/cxx-extra-semi.cpp 
b/clang/test/Parser/cxx-extra-semi.cpp
index de14bc0354d80..9bd69e18e9f02 100644
--- a/clang/test/Parser/cxx-extra-semi.cpp
+++ b/clang/test/Parser/cxx-extra-semi.cpp
@@ -5,6 +5,40 @@
 // RUN: %clang_cc1 -x c++ -Wextra-semi -fixit %t
 // RUN: %clang_cc1 -x c++ -Wextra-semi -Werror %t
 
+#if __cplusplus >= 201103L && defined(PEDANTIC)
+// In C++11 extra semicolons inside classes are allowed via defect reports.
+// expected-no-diagnostics
+class A {
+  void A1();
+  void A2() { };
+  void A2b() { };; 
+  ; 
+  void A2c() { }
+  ;
+  void A3() { };  ;; 
+  ;;;;;;; 
+  ; 
+  ; ;;          ;  ;;; 
+    ;  ;       ;       ;  ;; 
+  void A4();
+
+  union {
+    ;
+    int a;
+    ;
+  };
+};
+
+union B {
+  int a1;
+  int a2;; 
+};
+
+;
+; ;;
+
+#else
+
 class A {
   void A1();
   void A2() { };
@@ -13,19 +47,25 @@ class A {
   // -pedantic is specified, since one semicolon is technically permitted.
   // expected-warning@-4{{extra ';' after member function definition}}
 #endif
-  void A2b() { };; // expected-warning{{extra ';' after member function 
definition}}
+  void A2b() { };; // expected-warning{{multiple extra ';' after member 
function definition}}
   ; // expected-warning{{extra ';' inside a class}}
   void A2c() { }
   ;
 #ifndef PEDANTIC
   // expected-warning@-2{{extra ';' after member function definition}}
 #endif
-  void A3() { };  ;; // expected-warning{{extra ';' after member function 
definition}}
+  void A3() { };  ;; // expected-warning{{multiple extra ';' after member 
function definition}}
   ;;;;;;; // expected-warning{{extra ';' inside a class}}
   ; // expected-warning{{extra ';' inside a class}}
   ; ;;          ;  ;;; // expected-warning{{extra ';' inside a class}}
     ;  ;       ;       ;  ;; // expected-warning{{extra ';' inside a class}}
   void A4();
+  
+  union {
+    ; // expected-warning{{extra ';' inside a union}}
+    int a;
+    ; // expected-warning{{extra ';' inside a union}}
+  };
 };
 
 union B {
@@ -42,3 +82,5 @@ union B {
 // expected-warning@-6{{extra ';' outside of a function is incompatible with 
C++98}}
 // expected-warning@-6{{extra ';' outside of a function is incompatible with 
C++98}}
 #endif
+
+#endif
diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp
index 69a8d8a46557d..fd56c487ecdfa 100644
--- a/clang/test/Parser/cxx0x-decl.cpp
+++ b/clang/test/Parser/cxx0x-decl.cpp
@@ -62,15 +62,6 @@ namespace OpaqueEnumDecl {
 
 int decltype(f())::*ptr_mem_decltype;
 
-class ExtraSemiAfterMemFn {
-  // Due to a peculiarity in the C++11 grammar, a deleted or defaulted function
-  // is permitted to be followed by either one or two semicolons.
-  void f() = delete // expected-error {{expected ';' after delete}}
-  void g() = delete; // ok
-  void h() = delete;; // ok
-  void i() = delete;;; // expected-error {{extra ';' after member function 
definition}}
-};
-
 int *const const p = 0; // expected-error {{duplicate 'const' declaration 
specifier}}
 const const int *q = 0; // expected-error {{duplicate 'const' declaration 
specifier}}
 

>From 02bfa1d1ce3911517410f4527f9b92a077619f0f Mon Sep 17 00:00:00 2001
From: keinflue <[email protected]>
Date: Sun, 14 Dec 2025 17:47:23 +0100
Subject: [PATCH 2/2] Add DR test cases

---
 clang/test/CXX/drs/cwg16xx.cpp | 20 ++++++++++++++++++++
 clang/test/CXX/drs/cwg30xx.cpp |  7 ++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/clang/test/CXX/drs/cwg16xx.cpp b/clang/test/CXX/drs/cwg16xx.cpp
index bd2c484344ddf..788496dc66570 100644
--- a/clang/test/CXX/drs/cwg16xx.cpp
+++ b/clang/test/CXX/drs/cwg16xx.cpp
@@ -438,6 +438,26 @@ namespace cwg1692 { // cwg1692: 9
   }
 } // namespace cwg1692
 
+namespace cwg1693 { // cwg1693: 22
+  namespace issue_example {
+#if __cplusplus >= 201103L
+    struct A {
+      void f1() = delete;
+      void f2() = delete;;
+      void f3() = delete;;;
+    };
+#endif
+  }
+  struct A {
+    ; // cxx98-error{{extra ';' inside a struct is a C++11 extension}}
+    struct B {};; // cxx98-error{{extra ';' inside a struct is a C++11 
extension}}
+    int a;; // cxx98-error{{extra ';' inside a struct is a C++11 extension}}
+    void f();; // cxx98-error{{extra ';' inside a struct is a C++11 extension}}
+    void h(){
+    };; // cxx98-error{{multiple extra ';' after member function definition is 
a C++11 extension}}
+  };
+} // namespace cwg1693
+
 namespace cwg1696 { // cwg1696: 7
   namespace std_examples {
 #if __cplusplus >= 201402L
diff --git a/clang/test/CXX/drs/cwg30xx.cpp b/clang/test/CXX/drs/cwg30xx.cpp
index 648ba9e78cd66..91b24fe9bebd5 100644
--- a/clang/test/CXX/drs/cwg30xx.cpp
+++ b/clang/test/CXX/drs/cwg30xx.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++98 -pedantic-errors -verify=expected %s
+// RUN: %clang_cc1 -std=c++98 -pedantic-errors -verify=expected,cxx98 %s
 // RUN: %clang_cc1 -std=c++11 -pedantic-errors -verify=expected %s
 // RUN: %clang_cc1 -std=c++14 -pedantic-errors -verify=expected %s
 // RUN: %clang_cc1 -std=c++17 -pedantic-errors -verify=expected %s
@@ -20,4 +20,9 @@ void f(
     // expected-note@#cwg3005-first-param {{previous declaration is here}}
 }
 
+namespace cwg3079 { // cwg3079: 22 ready 2025-08-27
+  struct A { union {int x;;} u; }; // cxx98-error{{extra ';' inside a union is 
a C++11 extension}}
+  struct B { union {int x;;}; }; // cxx98-error{{extra ';' inside a union is a 
C++11 extension}}
+}
+
 } // namespace cwg3005

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to