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">;
// 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">;
"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<
"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;
/// 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
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
- ConsumeExtraSemi(InsideStruct,
- DeclSpec::getSpecifierName((DeclSpec::TST)TagType));
+ ConsumeExtraSemi(InsideStruct, TagType);
continue;
}
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)
// Consume the ';' - it's optional unless we have a delete or default
if (Tok.is(tok::semi))
- ConsumeExtraSemi(AfterDefinition);
+ ConsumeExtraSemi(AfterMemberFunctionDefinition);
return;
}
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
- ConsumeExtraSemi(InsideStruct,
- DeclSpec::getSpecifierName((DeclSpec::TST)TagType));
+ ConsumeExtraSemi(InsideStruct, TagType);
continue;
}
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
- ConsumeExtraSemi(InsideStruct,
- DeclSpec::getSpecifierName((DeclSpec::TST)TagType));
+ ConsumeExtraSemi(InsideStruct, TagType);
continue;
}
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));
}
//===----------------------------------------------------------------------===//
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
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;
-// 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'}}
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;
// expected-error {{expected ';' after top level declarator}}
int test6b;
-
-
+// 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}}
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
-// 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 {
}
struct S {};
-enum E { e };
+enum E { e, };
auto f() -> struct S {
return 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}}
+};