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
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 10affb0..8811e6a 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -62,6 +62,8 @@
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 @@
// 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 ae3f3a6..31b8077 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -31,8 +31,14 @@
"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 @@
"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 14ae660..ca38046 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -596,16 +596,16 @@
/// 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 38aff5d..9e58b31 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2876,8 +2876,7 @@
// 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 @@
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 8e357f7..3dc96cf 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1984,7 +1984,7 @@
// 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 @@
// 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 @@
// 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 760c7bf..7314228 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -220,31 +220,40 @@
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 b661c6d..f7c23df 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -150,8 +150,6 @@
CHECK-NEXT: warn_weak_identifier_undeclared
CHECK-NEXT: warn_weak_import
-The list of warnings in -Wpedenatic should NEVER grow.
+The list of warnings in -Wpedantic should NEVER grow.
-CHECK: Number in -Wpedantic (not covered by other -W flags): 71
-
-
+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 75e3fba..feccba8 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -12,11 +12,15 @@
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 57f33d8..951cd3d 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 @@
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 @@
// 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 35c886b..2aa18df 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 @@
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 b9f5141..9a220ca 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 @@
}
struct S {};
-enum E { e };
+enum E { e, };
auto f() -> struct S {
return S();
@@ -16,3 +16,12 @@
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}}
+};