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/3] [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/3] 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

>From d8804e51feaf48db7142c1f60474b3c8ed5dea5d Mon Sep 17 00:00:00 2001
From: keinflue <[email protected]>
Date: Wed, 24 Dec 2025 01:52:17 +0100
Subject: [PATCH 3/3] Rework tests and improve =delete/=default diagnostics

---
 clang/lib/Parse/ParseDeclCXX.cpp     |   2 +-
 clang/test/Parser/cxx-extra-semi.cpp | 112 +++++++++++++--------------
 2 files changed, 55 insertions(+), 59 deletions(-)

diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d8ed7e3ff96bd..3efde00184dd9 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3096,7 +3096,7 @@ Parser::DeclGroupPtrTy 
Parser::ParseCXXClassMemberDeclaration(
       LateParsedAttrs.clear();
 
       // Consume the ';' - it's optional unless we have a delete or default
-      if (Tok.is(tok::semi))
+      if (Tok.is(tok::semi) && DefinitionKind != 
FunctionDefinitionKind::Defaulted && DefinitionKind != 
FunctionDefinitionKind::Deleted)
         ConsumeExtraSemi(ExtraSemiKind::AfterMemberFunctionDefinition);
 
       return DeclGroupPtrTy::make(DeclGroupRef(FunDecl));
diff --git a/clang/test/Parser/cxx-extra-semi.cpp 
b/clang/test/Parser/cxx-extra-semi.cpp
index 9bd69e18e9f02..5c7255da89c87 100644
--- a/clang/test/Parser/cxx-extra-semi.cpp
+++ b/clang/test/Parser/cxx-extra-semi.cpp
@@ -1,86 +1,82 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -DPEDANTIC %s
-// RUN: %clang_cc1 -fsyntax-only -Wextra-semi -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wextra-semi -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify=compat98 -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify=cxx11_pedantic -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wextra-semi -verify=wextra,compat98 
-std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -Wextra-semi -verify=wextra,compat11 
-std=c++11 %s
 // RUN: cp %s %t
 // 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
+// cxx11_pedantic-no-diagnostics
+ 
 class A {
   void A1();
   void A2() { };
-  void A2b() { };; 
-  ; 
+  // This warning is only produced if we specify -Wextra-semi, and not if only
+  // -pedantic is specified, since one semicolon is technically permitted.
+  // wextra-warning@-3{{extra ';' after member function definition}}
+  void A2b() { };;
+  // compat98-warning@-1{{multiple extra ';' after member function definition 
is a C++11 extension}}
+  // compat11-warning@-2{{multiple extra ';' after member function definition 
is incompatible with C++98}}
+  ;
+  // compat98-warning@-1{{extra ';' inside a class is a C++11 extension}}
+  // compat11-warning@-2{{extra ';' inside a class is incompatible with C++98}}
   void A2c() { }
+  ; // wextra-warning{{extra ';' after member function definition}}
+  void A3() { };  ;;
+  // compat98-warning@-1{{multiple extra ';' after member function definition 
is a C++11 extension}}
+  // compat11-warning@-2{{multiple extra ';' after member function definition 
is incompatible with C++98}}
+  ;;;;;;;
+  // compat98-warning@-1{{extra ';' inside a class is a C++11 extension}}
+  // compat11-warning@-2{{extra ';' inside a class is incompatible with C++98}}
   ;
-  void A3() { };  ;; 
-  ;;;;;;; 
-  ; 
-  ; ;;          ;  ;;; 
-    ;  ;       ;       ;  ;; 
+  // compat98-warning@-1{{extra ';' inside a class is a C++11 extension}}
+  // compat11-warning@-2{{extra ';' inside a class is incompatible with C++98}}
+  ; ;;          ;  ;;;
+  // compat98-warning@-1{{extra ';' inside a class is a C++11 extension}}
+  // compat11-warning@-2{{extra ';' inside a class is incompatible with C++98}}
+    ;  ;       ;       ;  ;;
+  // compat98-warning@-1{{extra ';' inside a class is a C++11 extension}}
+  // compat11-warning@-2{{extra ';' inside a class is incompatible with C++98}}
   void A4();
-
+  
   union {
     ;
+    // compat98-warning@-1{{extra ';' inside a union is a C++11 extension}}
+    // compat11-warning@-2{{extra ';' inside a union is incompatible with 
C++98}}
     int a;
     ;
+    // compat98-warning@-1{{extra ';' inside a union is a C++11 extension}}
+    // compat11-warning@-2{{extra ';' inside a union is incompatible with 
C++98}}
   };
-};
 
-union B {
-  int a1;
-  int a2;; 
-};
-
-;
-; ;;
+  virtual void f() = 0;
+  virtual void g() = 0;;
+  // compat11-warning@-1{{extra ';' inside a class is incompatible with C++98}}
+  // compat98-warning@-2{{extra ';' inside a class is a C++11 extension}}
 
-#else
-
-class A {
-  void A1();
-  void A2() { };
-#ifndef PEDANTIC
-  // This warning is only produced if we specify -Wextra-semi, and not if only
-  // -pedantic is specified, since one semicolon is technically permitted.
-  // expected-warning@-4{{extra ';' after member function definition}}
-#endif
-  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{{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();
+#if __cplusplus >= 201103L
+  void h() = delete;
+  void i() = delete;; // wextra-warning{{extra ';' inside a class}}
+  void j() = delete;;; // wextra-warning{{extra ';' inside a class}}
   
-  union {
-    ; // expected-warning{{extra ';' inside a union}}
-    int a;
-    ; // expected-warning{{extra ';' inside a union}}
-  };
+  A(const A&) = default;
+  A(A&&) = default;;  // wextra-warning{{extra ';' inside a class}}
+  A(A&) = default;;;  // wextra-warning{{extra ';' inside a class}}
+#endif
 };
 
 union B {
   int a1;
-  int a2;; // expected-warning{{extra ';' inside a union}}
+  int a2;;
+  // compat11-warning@-1{{extra ';' inside a union is incompatible with C++98}}
+  // compat98-warning@-2{{extra ';' inside a union is a C++11 extension}}
 };
 
 ;
 ; ;;
-#if __cplusplus < 201103L
-// expected-warning@-3{{extra ';' outside of a function is a C++11 extension}}
-// expected-warning@-3{{extra ';' outside of a function is a C++11 extension}}
-#elif !defined(PEDANTIC)
-// 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
+// compat98-warning@-2{{extra ';' outside of a function is a C++11 extension}}
+// compat98-warning@-2{{extra ';' outside of a function is a C++11 extension}}
+// compat11-warning@-4{{extra ';' outside of a function is incompatible with 
C++98}}
+// compat11-warning@-4{{extra ';' outside of a function is incompatible with 
C++98}}
 
-#endif

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

Reply via email to