diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-07-23 05:45:25 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-07-23 05:45:25 +0000 |
commit | eab9d6f9065b042d39fbaf9842c9d8cc968dd6d0 (patch) | |
tree | ae1948b1996d0c59ea4f597701504ea5e8caa25c | |
parent | 3fe52ff7df93f7a928a15cc2cbf5134fdc0cec15 (diff) |
Add diagnostics for comma at end of enum and for extra semicolon at namespace
scope to -Wc++11-extensions. Move extra semicolon after member function
definition diagnostic out of -pedantic, since C++ allows a single semicolon
there. Keep it in -Wextra-semi, though, since it's still questionable.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160618 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticGroups.td | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 19 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 6 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 8 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 8 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 31 | ||||
-rw-r--r-- | test/Misc/warning-flags.c | 6 | ||||
-rw-r--r-- | test/Parser/cxx-class.cpp | 6 | ||||
-rw-r--r-- | test/Parser/cxx-decl.cpp | 6 | ||||
-rw-r--r-- | test/Parser/cxx-extra-semi.cpp | 26 | ||||
-rw-r--r-- | test/Parser/cxx0x-decl.cpp | 13 |
11 files changed, 88 insertions, 45 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 10affb07d3..8811e6aa36 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -62,6 +62,8 @@ def DocumentationPedantic : DiagGroup<"documentation-pedantic">; def Documentation : DiagGroup<"documentation", [DocumentationHTML]>; def EmptyBody : DiagGroup<"empty-body">; def ExtraTokens : DiagGroup<"extra-tokens">; +def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">; +def ExtraSemi : DiagGroup<"extra-semi", [CXX11ExtraSemi]>; def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; @@ -404,7 +406,7 @@ def NonGCC : DiagGroup<"non-gcc", // A warning group for warnings about using C++11 features as extensions in // earlier C++ versions. -def CXX11 : DiagGroup<"c++11-extensions">; +def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi]>; def : DiagGroup<"c++0x-extensions", [CXX11]>; def DelegatingCtorCycles : DiagGroup<"delegating-ctor-cycles">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index ae3f3a6a15..31b8077ef3 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -31,8 +31,14 @@ def ext_extra_semi : Extension< "outside of a function|" "inside a %1|" "inside instance variable list|" - "after function definition}0">, - InGroup<DiagGroup<"extra-semi">>; + "after member function definition}0">, + InGroup<ExtraSemi>; +def ext_extra_semi_cxx11 : Extension< + "extra ';' outside of a function is a C++11 extension">, + InGroup<CXX11ExtraSemi>; +def warn_extra_semi_after_mem_fn_def : Warning< + "extra ';' after member function definition">, + InGroup<ExtraSemi>, DefaultIgnore; def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">; def ext_plain_complex : ExtWarn< @@ -61,9 +67,12 @@ def ext_c99_compound_literal : Extension< "compound literals are a C99-specific feature">, InGroup<C99>; def ext_c99_flexible_array_member : Extension< "Flexible array members are a C99-specific feature">, InGroup<C99>; -def ext_enumerator_list_comma : Extension< - "commas at the end of enumerator lists are a %select{C99|C++11}0-specific " - "feature">; +def ext_enumerator_list_comma_c : Extension< + "commas at the end of enumerator lists are a C99-specific " + "feature">, InGroup<C99>; +def ext_enumerator_list_comma_cxx : Extension< + "commas at the end of enumerator lists are a C++11 extension">, + InGroup<CXX11>; def warn_cxx98_compat_enumerator_list_comma : Warning< "commas at the end of enumerator lists are incompatible with C++98">, InGroup<CXX98CompatPedantic>, DefaultIgnore; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 14ae6604b2..ca380463fb 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -596,16 +596,16 @@ private: /// to the semicolon, consumes that extra token. bool ExpectAndConsumeSemi(unsigned DiagID); - /// \brief The kind of extra semi diagnostic to emit. + /// \brief The kind of extra semi diagnostic to emit. enum ExtraSemiKind { OutsideFunction = 0, InsideStruct = 1, InstanceVariableList = 2, - AfterDefinition = 3 + AfterMemberFunctionDefinition = 3 }; /// \brief Consume any extra semi-colons until the end of the line. - void ConsumeExtraSemi(ExtraSemiKind Kind, const char* DiagMsg = ""); + void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified); //===--------------------------------------------------------------------===// // Scope manipulation diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 38aff5d4b9..9e58b312e3 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2876,8 +2876,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - ConsumeExtraSemi(InsideStruct, - DeclSpec::getSpecifierName((DeclSpec::TST)TagType)); + ConsumeExtraSemi(InsideStruct, TagType); continue; } @@ -3373,8 +3372,9 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { if (Tok.isNot(tok::identifier)) { if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x) - Diag(CommaLoc, diag::ext_enumerator_list_comma) - << getLangOpts().CPlusPlus + Diag(CommaLoc, getLangOpts().CPlusPlus ? + diag::ext_enumerator_list_comma_cxx : + diag::ext_enumerator_list_comma_c) << FixItHint::CreateRemoval(CommaLoc); else if (getLangOpts().CPlusPlus0x) Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma) diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 8e357f7e42..3dc96cf0d2 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1984,7 +1984,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Consume the ';' - it's optional unless we have a delete or default if (Tok.is(tok::semi)) - ConsumeExtraSemi(AfterDefinition); + ConsumeExtraSemi(AfterMemberFunctionDefinition); return; } @@ -2334,8 +2334,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - ConsumeExtraSemi(InsideStruct, - DeclSpec::getSpecifierName((DeclSpec::TST)TagType)); + ConsumeExtraSemi(InsideStruct, TagType); continue; } @@ -3060,8 +3059,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - ConsumeExtraSemi(InsideStruct, - DeclSpec::getSpecifierName((DeclSpec::TST)TagType)); + ConsumeExtraSemi(InsideStruct, TagType); continue; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 760c7bf717..7314228b9f 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -220,31 +220,40 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) { return ExpectAndConsume(tok::semi, DiagID); } -void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, const char* DiagMsg) { +void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) { if (!Tok.is(tok::semi)) return; - // AfterDefinition should only warn when placed on the same line as the - // definition. Otherwise, defer to another semi warning. - if (Kind == AfterDefinition && Tok.isAtStartOfLine()) return; - + bool HadMultipleSemis = false; SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc = Tok.getLocation(); ConsumeToken(); while ((Tok.is(tok::semi) && !Tok.isAtStartOfLine())) { + HadMultipleSemis = true; EndLoc = Tok.getLocation(); ConsumeToken(); } - if (Kind == OutsideFunction && getLangOpts().CPlusPlus0x) { - Diag(StartLoc, diag::warn_cxx98_compat_top_level_semi) - << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); + // C++11 allows extra semicolons at namespace scope, but not in any of the + // other contexts. + if (Kind == OutsideFunction && getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus0x) + Diag(StartLoc, diag::warn_cxx98_compat_top_level_semi) + << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); + else + Diag(StartLoc, diag::ext_extra_semi_cxx11) + << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); return; } - Diag(StartLoc, diag::ext_extra_semi) - << Kind << DiagMsg << FixItHint::CreateRemoval(SourceRange(StartLoc, - EndLoc)); + if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis) + Diag(StartLoc, diag::ext_extra_semi) + << Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST) + << 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) + << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); } //===----------------------------------------------------------------------===// diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c index b661c6dd20..f7c23df093 100644 --- a/test/Misc/warning-flags.c +++ b/test/Misc/warning-flags.c @@ -150,8 +150,6 @@ CHECK-NEXT: warn_use_out_of_scope_declaration CHECK-NEXT: warn_weak_identifier_undeclared CHECK-NEXT: warn_weak_import -The list of warnings in -Wpedenatic should NEVER grow. - -CHECK: Number in -Wpedantic (not covered by other -W flags): 71 - +The list of warnings in -Wpedantic should NEVER grow. +CHECK: Number in -Wpedantic (not covered by other -W flags): 70 diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp index 75e3fbacc4..feccba85cf 100644 --- a/test/Parser/cxx-class.cpp +++ b/test/Parser/cxx-class.cpp @@ -12,11 +12,15 @@ protected: int : 1, : 2; public: + void m0() {}; // ok, one extra ';' is permitted + void m1() {} + ; // ok, one extra ';' is permitted void m() { int l = 2; - }; // expected-warning{{extra ';' after function definition}} + };; // expected-warning{{extra ';' after member function definition}} template<typename T> void mt(T) { } + ; ; // expected-warning{{extra ';' inside a class}} virtual int vf() const volatile = 0; diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp index 57f33d826f..951cd3dfd1 100644 --- a/test/Parser/cxx-decl.cpp +++ b/test/Parser/cxx-decl.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux %s +// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -pedantic %s int x(*g); // expected-error {{use of undeclared identifier 'g'}} @@ -44,7 +44,7 @@ class asm_class_test { void foo() __asm__("baz"); }; -enum { fooenum = 1 }; +enum { fooenum = 1, }; // expected-warning {{commas at the end of enumerator lists are a C++11 extension}} struct a { int Type : fooenum; @@ -125,5 +125,3 @@ test6a { ;// expected-error {{C++ requires a type specifier for all declarations // expected-error {{expected ';' after top level declarator}} int test6b; - - diff --git a/test/Parser/cxx-extra-semi.cpp b/test/Parser/cxx-extra-semi.cpp index 35c886b63b..2aa18dfcc0 100644 --- a/test/Parser/cxx-extra-semi.cpp +++ b/test/Parser/cxx-extra-semi.cpp @@ -1,13 +1,26 @@ +// 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: cp %s %t // RUN: %clang_cc1 -x c++ -Wextra-semi -fixit %t // RUN: %clang_cc1 -x c++ -Wextra-semi -Werror %t class A { void A1(); - void A2() { }; // expected-warning{{extra ';' after function definition}} + 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{{extra ';' after member function definition}} ; // expected-warning{{extra ';' inside a class}} - void A3() { }; ;; // expected-warning{{extra ';' after function definition}} + void A2c() { } + ; +#ifndef PEDANTIC + // expected-warning@-2{{extra ';' after member function definition}} +#endif + void A3() { }; ;; // expected-warning{{extra ';' after member function definition}} ;;;;;;; // expected-warning{{extra ';' inside a class}} ; // expected-warning{{extra ';' inside a class}} ; ;; ; ;;; // expected-warning{{extra ';' inside a class}} @@ -20,6 +33,9 @@ union B { int a2;; // expected-warning{{extra ';' inside a union}} }; -; // expected-warning{{extra ';' outside of a function}} -; ;;// expected-warning{{extra ';' outside of a function}} - +; +; ;; +#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}} +#endif diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp index b9f5141a53..9a220caa5a 100644 --- a/test/Parser/cxx0x-decl.cpp +++ b/test/Parser/cxx0x-decl.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fsyntax-only -std=c++0x %s +// RUN: %clang_cc1 -verify -fsyntax-only -std=c++11 -pedantic %s // Make sure we know these are legitimate commas and not typos for ';'. namespace Commas { @@ -8,7 +8,7 @@ namespace Commas { } struct S {}; -enum E { e }; +enum E { e, }; auto f() -> struct S { return S(); @@ -16,3 +16,12 @@ auto f() -> struct S { auto g() -> enum E { return E(); } + +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-warning {{extra ';' after member function definition}} +}; |