llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: None (keinflue) <details> <summary>Changes</summary> With DR 1693 and DR 3079 C++ also allows empty declaration, i.e. extra semicolons, inside class member declaration lists in all contexts (as far as I can tell). 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 --- Full diff: https://github.com/llvm/llvm-project/pull/172209.diff 6 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+4) - (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+11-3) - (modified) clang/lib/Parse/Parser.cpp (+24-11) - (modified) clang/test/Parser/cxx-class.cpp (+8-3) - (modified) clang/test/Parser/cxx-extra-semi.cpp (+44-2) - (modified) clang/test/Parser/cxx0x-decl.cpp (-9) ``````````diff 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}} `````````` </details> https://github.com/llvm/llvm-project/pull/172209 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
