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}}
+};