Re-apply r159875 with fixes.

- Split pedantic driver flag test into separate test file, and XFAIL on cygwin,mingw32
- Fix bug in tablegen logic where a missing '{' caused errors to be included in -Wpedantic.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159892 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 2df7ca9..0e3527f 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,180 @@
 }
 
 //===----------------------------------------------------------------------===//
+// 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 +366,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 +392,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 +448,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 +462,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 +478,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 +502,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 +533,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;