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
