Implement -Wpedantic and --no-pedantic to complement -Weverything.

This patch introduces some magic in tablegen to create a "Pedantic" diagnostic
group which automagically includes all warnings that are extensions.  This
allows a user to suppress specific warnings traditionally under -pedantic used
an ordinary warning flag.  This also allows users to use #pragma to silence
specific -pedantic warnings, or promote them to errors, within blocks of text
(just like any other warning).

-Wpedantic is NOT an alias for -pedantic.  Instead, it provides another way
to (a) activate -pedantic warnings and (b) disable them.  Where they differ
is that -pedantic changes the behavior of the preprocessor slightly, whereas
-Wpedantic does not (it just turns on the warnings).

The magic in the tablegen diagnostic emitter has to do with computing the minimal
set of diagnostic groups and diagnostics that should go into -Wpedantic, as those
diagnostics that already members of groups that themselves are (transitively) members
of -Wpedantic do not need to be included in the Pedantic group directly.  I went
back and forth on whether or not to magically generate this group, and the invariant
was that we always wanted extension warnings to be included in -Wpedantic "some how",
but the bookkeeping would be very onerous to manage by hand.

-no-pedantic (and --no-pedantic) is included for completeness, and matches many of the
same kind of flags the compiler already supports.  It does what it says: cancels out
-pedantic.  One discrepancy is that if one specifies --no-pedantic and -Weverything or
-Wpedantic the pedantic warnings are still enabled (essentially the -W flags win).  We
can debate the correct behavior here.

Along the way, this patch nukes some code in TextDiagnosticPrinter.cpp and CXStoredDiagnostic.cpp
that determine whether to include the "-pedantic" flag in the warning output.  This is
no longer needed, as all extensions now have a -W flag.

This patch also significantly reduces the number of warnings not under flags from 229
to 158 (all extension warnings).  That's a 31% reduction.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159875 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 8753589..c1f85c1 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -380,6 +380,9 @@
 // DefaultIgnore in addition to putting it here.
 def : DiagGroup<"all", [Most, Parentheses, Switch]>;
 
+// Warnings enabled by -pedantic.  This is magically filled in by TableGen.
+def Pedantic : DiagGroup<"pedantic">;
+
 // Aliases.
 def : DiagGroup<"", [Extra]>;                   // -W = -Wextra
 def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wendif-tokens
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 48f9cd6..918718a 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -868,6 +868,7 @@
 def no_cpp_precomp : Flag<"-no-cpp-precomp">, Group<clang_ignored_f_Group>;
 def no_integrated_as : Flag<"-no-integrated-as">, Flags<[DriverOption]>;
 def no_integrated_cpp : Flag<"-no-integrated-cpp">, Flags<[DriverOption]>;
+def no_pedantic : Flag<"-no-pedantic">, Group<pedantic_Group>;
 def no__dead__strip__inits__and__terms : Flag<"-no_dead_strip_inits_and_terms">;
 def nobuiltininc : Flag<"-nobuiltininc">, Flags<[CC1Option]>,
   HelpText<"Disable builtin #include directories">;
@@ -1070,6 +1071,7 @@
 def _machine : Separate<"--machine">, Alias<m_Joined>;
 def _no_integrated_cpp : Flag<"--no-integrated-cpp">, Alias<no_integrated_cpp>;
 def _no_line_commands : Flag<"--no-line-commands">, Alias<P>;
+def _no_pedantic : Flag<"--no-pedantic">, Alias<no_pedantic>;
 def _no_standard_includes : Flag<"--no-standard-includes">, Alias<nostdinc>;
 def _no_standard_libraries : Flag<"--no-standard-libraries">, Alias<nostdlib>;
 def _no_undefined : Flag<"--no-undefined">, Flags<[LinkerInput]>;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index dd198a1..66d792f 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -2093,7 +2093,8 @@
   }
 
   Args.AddAllArgs(CmdArgs, options::OPT_W_Group);
-  Args.AddLastArg(CmdArgs, options::OPT_pedantic);
+  if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
+    CmdArgs.push_back("-pedantic");
   Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors);
   Args.AddLastArg(CmdArgs, options::OPT_w);
 
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index d07917f..30da72b 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -79,16 +79,6 @@
       Started = true;
     }
 
-    // If the diagnostic is an extension diagnostic and not enabled by default
-    // then it must have been turned on with -pedantic.
-    bool EnabledByDefault;
-    if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(),
-                                              EnabledByDefault) &&
-        !EnabledByDefault) {
-      OS << (Started ? "," : " [") << "-pedantic";
-      Started = true;
-    }
-
     StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
     if (!Opt.empty()) {
       OS << (Started ? "," : " [") << "-W" << Opt;
diff --git a/test/Driver/warning-options.cpp b/test/Driver/warning-options.cpp
index ce434ab..7b1b097 100644
--- a/test/Driver/warning-options.cpp
+++ b/test/Driver/warning-options.cpp
@@ -8,3 +8,11 @@
 // CHECK: unknown warning option '-Wmonkey'
 // CHECK: unknown warning option '-Wno-monkey'
 // CHECK: unknown warning option '-Wno-unused-command-line-arguments'; did you mean '-Wno-unused-command-line-argument'?
+
+// RUN: %clang -### -pedantic -no-pedantic %s 2>&1 | FileCheck -check-prefix=NO_PEDANTIC %s
+// RUN: %clang -### -pedantic -Wno-pedantic %s 2>&1 | FileCheck -check-prefix=PEDANTIC %s
+// NO_PEDANTIC-NOT: -pedantic
+// RUN: %clang -### -pedantic -pedantic -no-pedantic -pedantic %s 2>&1 | FileCheck -check-prefix=PEDANTIC %s
+// RUN: %clang -### -pedantic -pedantic -no-pedantic -Wpedantic %s 2>&1 | FileCheck -check-prefix=PEDANTIC %s
+// PEDANTIC: -pedantic
+
diff --git a/test/Misc/show-diag-options.c b/test/Misc/show-diag-options.c
index f0404a8..ef0a5a6 100644
--- a/test/Misc/show-diag-options.c
+++ b/test/Misc/show-diag-options.c
@@ -23,5 +23,5 @@
   // OPTION_ERROR_CATEGORY: {{.*}}: error: {{[a-z ]+}} [-Werror,-Wparentheses,Semantic Issue]
 
   // Leverage the fact that all these '//'s get warned about in C89 pedantic.
-  // OPTION_PEDANTIC: {{.*}}: warning: {{[/a-z ]+}} [-pedantic,-Wcomment]
+  // OPTION_PEDANTIC: {{.*}}: warning: {{[/a-z ]+}} [-Wcomment]
 }
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 99ebf99..15b2d27 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -17,66 +17,7 @@
 
 The list of warnings below should NEVER grow.  It should gradually shrink to 0.
 
-CHECK: Warnings without flags (229):
-CHECK-NEXT:   ext_anonymous_struct_union_qualified
-CHECK-NEXT:   ext_binary_literal
-CHECK-NEXT:   ext_cast_fn_obj
-CHECK-NEXT:   ext_delete_void_ptr_operand
-CHECK-NEXT:   ext_designated_init
-CHECK-NEXT:   ext_duplicate_declspec
-CHECK-NEXT:   ext_ellipsis_exception_spec
-CHECK-NEXT:   ext_enum_friend
-CHECK-NEXT:   ext_enum_value_not_int
-CHECK-NEXT:   ext_enumerator_list_comma
-CHECK-NEXT:   ext_expected_semi_decl_list
-CHECK-NEXT:   ext_explicit_instantiation_without_qualified_id
-CHECK-NEXT:   ext_explicit_specialization_storage_class
-CHECK-NEXT:   ext_forward_ref_enum
-CHECK-NEXT:   ext_freestanding_complex
-CHECK-NEXT:   ext_hexconstant_invalid
-CHECK-NEXT:   ext_ident_list_in_param
-CHECK-NEXT:   ext_imaginary_constant
-CHECK-NEXT:   ext_implicit_lib_function_decl
-CHECK-NEXT:   ext_in_class_initializer_non_constant
-CHECK-NEXT:   ext_integer_complement_complex
-CHECK-NEXT:   ext_integer_complex
-CHECK-NEXT:   ext_integer_increment_complex
-CHECK-NEXT:   ext_invalid_sign_spec
-CHECK-NEXT:   ext_missing_declspec
-CHECK-NEXT:   ext_missing_whitespace_after_macro_name
-CHECK-NEXT:   ext_new_paren_array_nonconst
-CHECK-NEXT:   ext_nonstandard_escape
-CHECK-NEXT:   ext_param_not_declared
-CHECK-NEXT:   ext_plain_complex
-CHECK-NEXT:   ext_pp_bad_vaargs_use
-CHECK-NEXT:   ext_pp_comma_expr
-CHECK-NEXT:   ext_pp_ident_directive
-CHECK-NEXT:   ext_pp_include_next_directive
-CHECK-NEXT:   ext_pp_line_too_big
-CHECK-NEXT:   ext_pp_macro_redef
-CHECK-NEXT:   ext_pp_warning_directive
-CHECK-NEXT:   ext_return_has_void_expr
-CHECK-NEXT:   ext_subscript_non_lvalue
-CHECK-NEXT:   ext_template_arg_extra_parens
-CHECK-NEXT:   ext_thread_before
-CHECK-NEXT:   ext_typecheck_addrof_void
-CHECK-NEXT:   ext_typecheck_cast_nonscalar
-CHECK-NEXT:   ext_typecheck_cast_to_union
-CHECK-NEXT:   ext_typecheck_comparison_of_distinct_pointers
-CHECK-NEXT:   ext_typecheck_comparison_of_distinct_pointers_nonstandard
-CHECK-NEXT:   ext_typecheck_comparison_of_fptr_to_void
-CHECK-NEXT:   ext_typecheck_comparison_of_pointer_integer
-CHECK-NEXT:   ext_typecheck_cond_incompatible_operands
-CHECK-NEXT:   ext_typecheck_cond_incompatible_operands_nonstandard
-CHECK-NEXT:   ext_typecheck_cond_one_void
-CHECK-NEXT:   ext_typecheck_convert_pointer_void_func
-CHECK-NEXT:   ext_typecheck_ordered_comparison_of_function_pointers
-CHECK-NEXT:   ext_typecheck_ordered_comparison_of_pointer_and_zero
-CHECK-NEXT:   ext_typecheck_ordered_comparison_of_pointer_integer
-CHECK-NEXT:   ext_typecheck_zero_array_size
-CHECK-NEXT:   ext_unknown_escape
-CHECK-NEXT:   ext_using_undefined_std
-CHECK-NEXT:   ext_vla_folded_to_constant
+CHECK: Warnings without flags (158):
 CHECK-NEXT:   pp_include_next_absolute_path
 CHECK-NEXT:   pp_include_next_in_primary
 CHECK-NEXT:   pp_invalid_string_literal
@@ -138,9 +79,6 @@
 CHECK-NEXT:   warn_enum_value_overflow
 CHECK-NEXT:   warn_enumerator_too_large
 CHECK-NEXT:   warn_exception_caught_by_earlier_handler
-CHECK-NEXT:   warn_excess_initializers
-CHECK-NEXT:   warn_excess_initializers_in_char_array_initializer
-CHECK-NEXT:   warn_expected_qualified_after_typename
 CHECK-NEXT:   warn_extraneous_char_constant
 CHECK-NEXT:   warn_fe_cc_log_diagnostics_failure
 CHECK-NEXT:   warn_fe_cc_print_header_failure
@@ -149,23 +87,17 @@
 CHECK-NEXT:   warn_function_attribute_wrong_type
 CHECK-NEXT:   warn_gc_attribute_weak_on_local
 CHECK-NEXT:   warn_gnu_inline_attribute_requires_inline
-CHECK-NEXT:   warn_hex_escape_too_large
 CHECK-NEXT:   warn_ignoring_ftabstop_value
-CHECK-NEXT:   warn_illegal_constant_array_size
 CHECK-NEXT:   warn_implements_nscopying
 CHECK-NEXT:   warn_incompatible_qualified_id
-CHECK-NEXT:   warn_initializer_string_for_char_array_too_long
 CHECK-NEXT:   warn_inline_namespace_reopened_noninline
 CHECK-NEXT:   warn_integer_too_large
 CHECK-NEXT:   warn_integer_too_large_for_signed
 CHECK-NEXT:   warn_invalid_asm_cast_lvalue
-CHECK-NEXT:   warn_many_braces_around_scalar_init
 CHECK-NEXT:   warn_maynot_respond
 CHECK-NEXT:   warn_member_extra_qualification
 CHECK-NEXT:   warn_method_param_redefinition
-CHECK-NEXT:   warn_mismatched_exception_spec
 CHECK-NEXT:   warn_missing_case_for_condition
-CHECK-NEXT:   warn_missing_dependent_template_keyword
 CHECK-NEXT:   warn_missing_exception_specification
 CHECK-NEXT:   warn_missing_whitespace_after_macro_name
 CHECK-NEXT:   warn_multiple_method_decl
@@ -177,10 +109,8 @@
 CHECK-NEXT:   warn_objc_object_attribute_wrong_type
 CHECK-NEXT:   warn_objc_property_copy_missing_on_block
 CHECK-NEXT:   warn_objc_protocol_qualifier_missing_id
-CHECK-NEXT:   warn_octal_escape_too_large
 CHECK-NEXT:   warn_odr_tag_type_inconsistent
 CHECK-NEXT:   warn_on_superclass_use
-CHECK-NEXT:   warn_param_default_argument_redefinition
 CHECK-NEXT:   warn_partial_specs_not_deducible
 CHECK-NEXT:   warn_pointer_attribute_wrong_type
 CHECK-NEXT:   warn_pp_convert_lhs_to_positive
@@ -228,7 +158,6 @@
 CHECK-NEXT:   warn_second_parameter_to_va_arg_never_compatible
 CHECK-NEXT:   warn_standalone_specifier
 CHECK-NEXT:   warn_static_inline_explicit_inst_ignored
-CHECK-NEXT:   warn_static_non_static
 CHECK-NEXT:   warn_template_export_unsupported
 CHECK-NEXT:   warn_template_spec_extra_headers
 CHECK-NEXT:   warn_tentative_incomplete_array
@@ -247,3 +176,4 @@
 CHECK-NEXT:   warn_use_out_of_scope_declaration
 CHECK-NEXT:   warn_weak_identifier_undeclared
 CHECK-NEXT:   warn_weak_import
+
diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp
index 8284dc9..fa331de 100644
--- a/tools/libclang/CXStoredDiagnostic.cpp
+++ b/tools/libclang/CXStoredDiagnostic.cpp
@@ -66,13 +66,8 @@
       *Disable = createCXString("-ferror-limit=0");
     return createCXString("-ferror-limit=");
   }
-  
-  bool EnabledByDefault;
-  if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) &&
-      !EnabledByDefault)
-    return createCXString("-pedantic");
 
-  return createCXString("");  
+  return createCXString("");
 }
 
 unsigned CXStoredDiagnostic::getCategory() const {
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 2df7ca9..4c480ec 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -11,9 +11,11 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/TableGen/Record.h"
@@ -78,7 +80,7 @@
                                                    DiagGroupParents);
     if (!CatName.empty()) return CatName;
   }
-  
+
   // If the diagnostic itself has a category, get it.
   return R->getValueAsString("CategoryName");
 }
@@ -160,6 +162,179 @@
 }
 
 //===----------------------------------------------------------------------===//
+// Infer members of -Wpedantic.
+//===----------------------------------------------------------------------===//
+
+typedef std::vector<const Record *> RecordVec;
+typedef llvm::DenseSet<const Record *> RecordSet;
+typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
+
+namespace {
+class InferPedantic {
+  typedef llvm::DenseMap<const Record*,
+                         std::pair<unsigned, llvm::Optional<unsigned> > > GMap;
+
+  DiagGroupParentMap &DiagGroupParents;
+  const std::vector<Record*> &Diags;
+  const std::vector<Record*> DiagGroups;
+  std::map<std::string, GroupInfo> &DiagsInGroup;
+  llvm::DenseSet<const Record*> DiagsSet;
+  GMap GroupCount;
+public:
+  InferPedantic(DiagGroupParentMap &DiagGroupParents,
+                const std::vector<Record*> &Diags,
+                const std::vector<Record*> &DiagGroups,
+                std::map<std::string, GroupInfo> &DiagsInGroup)
+  : DiagGroupParents(DiagGroupParents),
+  Diags(Diags),
+  DiagGroups(DiagGroups),
+  DiagsInGroup(DiagsInGroup) {}
+
+  /// Compute the set of diagnostics and groups that are immediately
+  /// in -Wpedantic.
+  void compute(VecOrSet DiagsInPedantic,
+               VecOrSet GroupsInPedantic);
+
+private:
+  /// Determine whether a group is a subgroup of another group.
+  bool isSubGroupOfGroup(const Record *Group,
+                         llvm::StringRef RootGroupName);
+
+  /// Determine if the diagnostic is an extension.
+  bool isExtension(const Record *Diag);
+
+  /// Increment the count for a group, and transitively marked
+  /// parent groups when appropriate.
+  void markGroup(const Record *Group);
+
+  /// Return true if the diagnostic is in a pedantic group.
+  bool groupInPedantic(const Record *Group, bool increment = false);
+};
+} // end anonymous namespace
+
+bool InferPedantic::isSubGroupOfGroup(const Record *Group,
+                                      llvm::StringRef GName) {
+
+  const std::string &GroupName = Group->getValueAsString("GroupName");
+  if (GName == GroupName)
+    return true;
+
+  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
+  for (unsigned i = 0, e = Parents.size(); i != e; ++i)
+    if (isSubGroupOfGroup(Parents[i], GName))
+      return true;
+
+  return false;
+}
+
+/// Determine if the diagnostic is an extension.
+bool InferPedantic::isExtension(const Record *Diag) {
+  const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
+  return ClsName == "CLASS_EXTENSION";
+}
+
+bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
+  GMap::mapped_type &V = GroupCount[Group];
+  // Lazily compute the threshold value for the group count.
+  if (!V.second.hasValue()) {
+    const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
+    V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
+  }
+
+  if (increment)
+    ++V.first;
+
+  // Consider a group in -Wpendatic IFF if has at least one diagnostic
+  // or subgroup AND all of those diagnostics and subgroups are covered
+  // by -Wpedantic via our computation.
+  return V.first != 0 && V.first == V.second.getValue();
+}
+
+void InferPedantic::markGroup(const Record *Group) {
+  // If all the diagnostics and subgroups have been marked as being
+  // covered by -Wpedantic, increment the count of parent groups.  Once the
+  // group's count is equal to the number of subgroups and diagnostics in
+  // that group, we can safely add this group to -Wpedantic.
+  if (groupInPedantic(Group, /* increment */ true)) {
+    const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
+    for (unsigned i = 0, e = Parents.size(); i != e; ++i)
+      markGroup(Parents[i]);
+  }
+}
+
+void InferPedantic::compute(VecOrSet DiagsInPedantic,
+                            VecOrSet GroupsInPedantic) {
+  // All extensions are implicitly in the "pedantic" group.  For those that
+  // aren't explicitly included in -Wpedantic, mark them for consideration
+  // to be included in -Wpedantic directly.
+  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+    Record *R = Diags[i];
+    if (isExtension(R))
+      DiagsSet.insert(R);
+    if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
+      const Record *GroupRec = Group->getDef();
+      if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
+        markGroup(GroupRec);
+      }
+    }
+  }
+
+  // Compute the set of diagnostics that are directly in -Wpedantic.  We
+  // march through Diags a second time to ensure the results are emitted
+  // in deterministic order.
+  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+    Record *R = Diags[i];
+    if (!DiagsSet.count(R))
+      continue;
+    // Check if the group is implicitly in -Wpedantic.  If so,
+    // the diagnostic should not be directly included in the -Wpedantic
+    // diagnostic group.
+    if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group")))
+      if (groupInPedantic(Group->getDef()))
+        continue;
+
+    // The diagnostic is not included in a group that is (transitively) in
+    // -Wpedantic.  Include it in -Wpedantic directly.
+    if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
+      V->push_back(R);
+    else {
+      DiagsInPedantic.get<RecordSet*>()->insert(R);
+    }
+  }
+
+  if (!GroupsInPedantic)
+    return;
+
+  // Compute the set of groups that are directly in -Wpedantic.  We
+  // march through the groups to ensure the results are emitted
+  /// in a deterministc order.
+  for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
+    Record *Group = DiagGroups[i];
+    if (!groupInPedantic(Group))
+      continue;
+
+    unsigned ParentsInPedantic = 0;
+    const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
+    for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
+      if (groupInPedantic(Parents[j]))
+        ++ParentsInPedantic;
+    }
+    // If all the parents are in -Wpedantic, this means that this diagnostic
+    // group will be indirectly included by -Wpedantic already.  In that
+    // case, do not add it directly to -Wpedantic.  If the group has no
+    // parents, obviously it should go into -Wpedantic.
+    if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
+      continue;
+
+    if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
+      V->push_back(Group);
+    else {
+      GroupsInPedantic.get<RecordSet*>()->insert(Group);
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
 // Warning Tables (.inc file) generation.
 //===----------------------------------------------------------------------===//
 
@@ -190,6 +365,11 @@
   DiagCategoryIDMap CategoryIDs(Records);
   DiagGroupParentMap DGParentMap(Records);
 
+  // Compute the set of diagnostics that are in -Wpedantic.
+  RecordSet DiagsInPedantic;
+  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
+  inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0);
+
   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
     const Record &R = *Diags[i];
     // Filter by component.
@@ -211,6 +391,11 @@
           DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
       assert(I != DiagsInGroup.end());
       OS << ", " << I->second.IDNo;
+    } else if (DiagsInPedantic.count(&R)) {
+      std::map<std::string, GroupInfo>::iterator I =
+        DiagsInGroup.find("pedantic");
+      assert(I != DiagsInGroup.end() && "pedantic group not defined");
+      OS << ", " << I->second.IDNo;
     } else {
       OS << ", 0";
     }
@@ -262,12 +447,12 @@
     enumName += isalnum(*I) ? *I : '_';
   return enumName.str();
 }
-
+  
 namespace clang {
 void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
   // Compute a mapping from a DiagGroup to all of its parents.
   DiagGroupParentMap DGParentMap(Records);
-  
+
   std::vector<Record*> Diags =
     Records.getAllDerivedDefinitions("Diagnostic");
   
@@ -276,7 +461,15 @@
 
   std::map<std::string, GroupInfo> DiagsInGroup;
   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
-  
+
+  // All extensions are implicitly in the "pedantic" group.  Record the
+  // implicit set of groups in the "pedantic" group, and use this information
+  // later when emitting the group information for Pedantic.
+  RecordVec DiagsInPedantic;
+  RecordVec GroupsInPedantic;
+  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
+  inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
+
   // Walk through the groups emitting an array for each diagnostic of the diags
   // that are mapped to.
   OS << "\n#ifdef GET_DIAG_ARRAYS\n";
@@ -284,17 +477,23 @@
   for (std::map<std::string, GroupInfo>::iterator
        I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
     MaxLen = std::max(MaxLen, (unsigned)I->first.size());
-    
+    const bool IsPedantic = I->first == "pedantic";
+
     std::vector<const Record*> &V = I->second.DiagsInGroup;
-    if (!V.empty()) {
+    if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
       OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
       for (unsigned i = 0, e = V.size(); i != e; ++i)
         OS << "diag::" << V[i]->getName() << ", ";
+      // Emit the diagnostics implicitly in "pedantic".
+      if (IsPedantic) {
+        for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i)
+          OS << "diag::" << DiagsInPedantic[i]->getName() << ", ";
+      }
       OS << "-1 };\n";
     }
     
     const std::vector<std::string> &SubGroups = I->second.SubGroups;
-    if (!SubGroups.empty()) {
+    if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
       OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
       for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
         std::map<std::string, GroupInfo>::iterator RI =
@@ -302,6 +501,18 @@
         assert(RI != DiagsInGroup.end() && "Referenced without existing?");
         OS << RI->second.IDNo << ", ";
       }
+      // Emit the groups implicitly in "pedantic".
+      if (IsPedantic) {
+        for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) {
+          const std::string &GroupName =
+            GroupsInPedantic[i]->getValueAsString("GroupName");
+          std::map<std::string, GroupInfo>::iterator RI =
+            DiagsInGroup.find(GroupName);
+          assert(RI != DiagsInGroup.end() && "Referenced without existing?");
+          OS << RI->second.IDNo << ", ";
+        }
+      }
+
       OS << "-1 };\n";
     }
   }
@@ -321,15 +532,22 @@
       throw "Invalid character in diagnostic group '" + I->first + "'";
     OS.write_escaped(I->first) << "\","
                                << std::string(MaxLen-I->first.size()+1, ' ');
-    
+
+    // Special handling for 'pedantic'.
+    const bool IsPedantic = I->first == "pedantic";
+
     // Diagnostics in the group.
-    if (I->second.DiagsInGroup.empty())
+    const bool hasDiags = !I->second.DiagsInGroup.empty() ||
+                          (IsPedantic && !DiagsInPedantic.empty());
+    if (!hasDiags)
       OS << "0, ";
     else
       OS << "DiagArray" << I->second.IDNo << ", ";
     
     // Subgroups.
-    if (I->second.SubGroups.empty())
+    const bool hasSubGroups = !I->second.SubGroups.empty() ||
+                              (IsPedantic && !GroupsInPedantic.empty());
+    if (!hasSubGroups)
       OS << 0;
     else
       OS << "DiagSubGroup" << I->second.IDNo;