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/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;