<div dir="ltr">This seems to be causing a substantial amount of warning spew from MSVC:<div><a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/955">http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/955</a><br></div><div><br></div><div>I think our recommended "portable" method of using llvm_unreachable is outside the switch, instead of in the default case: <a href="http://llvm.org/docs/CodingStandards.html#don-t-use-default-labels-in-fully-covered-switches-over-enumerations">http://llvm.org/docs/CodingStandards.html#don-t-use-default-labels-in-fully-covered-switches-over-enumerations</a></div><div><br></div><div>-- Sean Silva</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Feb 29, 2016 at 4:18 PM, John McCall via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rjmccall<br>
Date: Mon Feb 29 18:18:05 2016<br>
New Revision: 262275<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=262275&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=262275&view=rev</a><br>
Log:<br>
Infrastructure improvements to Clang attribute TableGen.<br>
<br>
This should make it easier to add new Attr subclasses.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/AST/Attr.h<br>
    cfe/trunk/include/clang/Basic/AttrKinds.h<br>
    cfe/trunk/lib/AST/ASTDumper.cpp<br>
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/Attr.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=262275&r1=262274&r2=262275&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=262275&r1=262274&r2=262275&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/Attr.h (original)<br>
+++ cfe/trunk/include/clang/AST/Attr.h Mon Feb 29 18:18:05 2016<br>
@@ -129,7 +129,8 @@ public:<br>
<br>
   // Implement isa/cast/dyncast/etc.<br>
   static bool classof(const Attr *A) {<br>
-    return A->getKind() <= attr::LAST_INHERITABLE;<br>
+    return A->getKind() >= attr::FirstInheritableAttr &&<br>
+           A->getKind() <= attr::LastInheritableAttr;<br>
   }<br>
 };<br>
<br>
@@ -143,9 +144,8 @@ protected:<br>
 public:<br>
   // Implement isa/cast/dyncast/etc.<br>
   static bool classof(const Attr *A) {<br>
-    // Relies on relative order of enum emission with respect to MS inheritance<br>
-    // attrs.<br>
-    return A->getKind() <= attr::LAST_INHERITABLE_PARAM;<br>
+    return A->getKind() >= attr::FirstInheritableParamAttr &&<br>
+           A->getKind() <= attr::LastInheritableParamAttr;<br>
   }<br>
 };<br>
<br>
<br>
Modified: cfe/trunk/include/clang/Basic/AttrKinds.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrKinds.h?rev=262275&r1=262274&r2=262275&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrKinds.h?rev=262275&r1=262274&r2=262275&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/AttrKinds.h (original)<br>
+++ cfe/trunk/include/clang/Basic/AttrKinds.h Mon Feb 29 18:18:05 2016<br>
@@ -22,10 +22,10 @@ namespace attr {<br>
 // \brief A list of all the recognized kinds of attributes.<br>
 enum Kind {<br>
 #define ATTR(X) X,<br>
-#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X,<br>
-#define LAST_INHERITABLE_PARAM_ATTR(X) X, LAST_INHERITABLE_PARAM = X,<br>
+#define ATTR_RANGE(CLASS, FIRST_NAME, LAST_NAME) \<br>
+  First##CLASS = FIRST_NAME,                    \<br>
+  Last##CLASS = LAST_NAME,<br>
 #include "clang/Basic/AttrList.inc"<br>
-  NUM_ATTRS<br>
 };<br>
<br>
 } // end namespace attr<br>
<br>
Modified: cfe/trunk/lib/AST/ASTDumper.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=262275&r1=262274&r2=262275&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=262275&r1=262274&r2=262275&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ASTDumper.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTDumper.cpp Mon Feb 29 18:18:05 2016<br>
@@ -819,8 +819,6 @@ void ASTDumper::dumpAttr(const Attr *A)<br>
       switch (A->getKind()) {<br>
 #define ATTR(X) case attr::X: OS << #X; break;<br>
 #include "clang/Basic/AttrList.inc"<br>
-      default:<br>
-        llvm_unreachable("unexpected attribute kind");<br>
       }<br>
       OS << "Attr";<br>
     }<br>
<br>
Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=262275&r1=262274&r2=262275&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=262275&r1=262274&r2=262275&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)<br>
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Mon Feb 29 18:18:05 2016<br>
@@ -1718,8 +1718,6 @@ void EmitClangAttrImpl(RecordKeeper &Rec<br>
       OS << "    return cast<" << R.getName() << "Attr>(this)->" << Method<br>
          << ";\n";<br>
     }<br>
-    OS << "  case attr::NUM_ATTRS:\n";<br>
-    OS << "    break;\n";<br>
     OS << "  }\n";<br>
     OS << "  llvm_unreachable(\"Unexpected attribute kind!\");\n";<br>
     OS << "}\n\n";<br>
@@ -1738,20 +1736,10 @@ void EmitClangAttrImpl(RecordKeeper &Rec<br>
<br>
 } // end namespace clang<br>
<br>
-static void EmitAttrList(raw_ostream &OS, StringRef Class,<br>
+static void emitAttrList(raw_ostream &OS, StringRef Class,<br>
                          const std::vector<Record*> &AttrList) {<br>
-  auto i = AttrList.cbegin(), e = AttrList.cend();<br>
-<br>
-  if (i != e) {<br>
-    // Move the end iterator back to emit the last attribute.<br>
-    for(--e; i != e; ++i) {<br>
-      if (!(*i)->getValueAsBit("ASTNode"))<br>
-        continue;<br>
-<br>
-      OS << Class << "(" << (*i)->getName() << ")\n";<br>
-    }<br>
-<br>
-    OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n";<br>
+  for (auto Cur : AttrList) {<br>
+    OS << Class << "(" << Cur->getName() << ")\n";<br>
   }<br>
 }<br>
<br>
@@ -1764,71 +1752,216 @@ static bool AttrHasPragmaSpelling(const<br>
          }) != Spellings.end();<br>
 }<br>
<br>
-namespace clang {<br>
-// Emits the enumeration list for attributes.<br>
-void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {<br>
-  emitSourceFileHeader("List of all attributes that Clang recognizes", OS);<br>
+namespace {<br>
+  struct AttrClassDescriptor {<br>
+    const char * const MacroName;<br>
+    const char * const TableGenName;<br>
+  };<br>
+}<br>
<br>
-  OS << "#ifndef LAST_ATTR\n";<br>
-  OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n";<br>
-  OS << "#endif\n\n";<br>
+static const AttrClassDescriptor AttrClassDescriptors[] = {<br>
+  { "ATTR", "Attr" },<br>
+  { "INHERITABLE_ATTR", "InheritableAttr" },<br>
+  { "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" }<br>
+};<br>
+<br>
+static void emitDefaultDefine(raw_ostream &OS, StringRef name,<br>
+                              const char *superName) {<br>
+  OS << "#ifndef " << name << "\n";<br>
+  OS << "#define " << name << "(NAME) ";<br>
+  if (superName) OS << superName << "(NAME)";<br>
+  OS << "\n#endif\n\n";<br>
+}<br>
+<br>
+namespace {<br>
+  /// A class of attributes.<br>
+  struct AttrClass {<br>
+    const AttrClassDescriptor &Descriptor;<br>
+    Record *TheRecord;<br>
+    AttrClass *SuperClass = nullptr;<br>
+    std::vector<AttrClass*> SubClasses;<br>
+    std::vector<Record*> Attrs;<br>
+<br>
+    AttrClass(const AttrClassDescriptor &Descriptor, Record *R)<br>
+      : Descriptor(Descriptor), TheRecord(R) {}<br>
+<br>
+    void emitDefaultDefines(raw_ostream &OS) const {<br>
+      // Default the macro unless this is a root class (i.e. Attr).<br>
+      if (SuperClass) {<br>
+        emitDefaultDefine(OS, Descriptor.MacroName,<br>
+                          SuperClass->Descriptor.MacroName);<br>
+      }<br>
+    }<br>
<br>
-  OS << "#ifndef INHERITABLE_ATTR\n";<br>
-  OS << "#define INHERITABLE_ATTR(NAME) ATTR(NAME)\n";<br>
-  OS << "#endif\n\n";<br>
+    void emitUndefs(raw_ostream &OS) const {<br>
+      OS << "#undef " << Descriptor.MacroName << "\n";<br>
+    }<br>
<br>
-  OS << "#ifndef LAST_INHERITABLE_ATTR\n";<br>
-  OS << "#define LAST_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n";<br>
-  OS << "#endif\n\n";<br>
+    void emitAttrList(raw_ostream &OS) const {<br>
+      for (auto SubClass : SubClasses) {<br>
+        SubClass->emitAttrList(OS);<br>
+      }<br>
<br>
-  OS << "#ifndef INHERITABLE_PARAM_ATTR\n";<br>
-  OS << "#define INHERITABLE_PARAM_ATTR(NAME) ATTR(NAME)\n";<br>
-  OS << "#endif\n\n";<br>
+      ::emitAttrList(OS, Descriptor.MacroName, Attrs);<br>
+    }<br>
<br>
-  OS << "#ifndef LAST_INHERITABLE_PARAM_ATTR\n";<br>
-  OS << "#define LAST_INHERITABLE_PARAM_ATTR(NAME)"<br>
-        " INHERITABLE_PARAM_ATTR(NAME)\n";<br>
-  OS << "#endif\n\n";<br>
+    void classifyAttrOnRoot(Record *Attr) {<br>
+      bool result = classifyAttr(Attr);<br>
+      assert(result && "failed to classify on root"); (void) result;<br>
+    }<br>
<br>
-  OS << "#ifndef PRAGMA_SPELLING_ATTR\n";<br>
-  OS << "#define PRAGMA_SPELLING_ATTR(NAME)\n";<br>
-  OS << "#endif\n\n";<br>
+    void emitAttrRange(raw_ostream &OS) const {<br>
+      OS << "ATTR_RANGE(" << Descriptor.TableGenName<br>
+         << ", " << getFirstAttr()->getName()<br>
+         << ", " << getLastAttr()->getName() << ")\n";<br>
+    }<br>
<br>
-  OS << "#ifndef LAST_PRAGMA_SPELLING_ATTR\n";<br>
-  OS << "#define LAST_PRAGMA_SPELLING_ATTR(NAME) PRAGMA_SPELLING_ATTR(NAME)\n";<br>
-  OS << "#endif\n\n";<br>
+  private:<br>
+    bool classifyAttr(Record *Attr) {<br>
+      // Check all the subclasses.<br>
+      for (auto SubClass : SubClasses) {<br>
+        if (SubClass->classifyAttr(Attr))<br>
+          return true;<br>
+      }<br>
<br>
-  Record *InhClass = Records.getClass("InheritableAttr");<br>
-  Record *InhParamClass = Records.getClass("InheritableParamAttr");<br>
-  std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"),<br>
-                        NonInhAttrs, InhAttrs, InhParamAttrs, PragmaAttrs;<br>
+      // It's not more specific than this class, but it might still belong here.<br>
+      if (Attr->isSubClassOf(TheRecord)) {<br>
+        Attrs.push_back(Attr);<br>
+        return true;<br>
+      }<br>
+<br>
+      return false;<br>
+    }<br>
+<br>
+    Record *getFirstAttr() const {<br>
+      if (!SubClasses.empty())<br>
+        return SubClasses.front()->getFirstAttr();<br>
+      return Attrs.front();<br>
+    }<br>
+<br>
+    Record *getLastAttr() const {<br>
+      if (!Attrs.empty())<br>
+        return Attrs.back();<br>
+      return SubClasses.back()->getLastAttr();<br>
+    }<br>
+  };<br>
+<br>
+  /// The entire hierarchy of attribute classes.<br>
+  class AttrClassHierarchy {<br>
+    std::vector<std::unique_ptr<AttrClass>> Classes;<br>
+  public:<br>
+    AttrClassHierarchy(RecordKeeper &Records) {<br>
+      // Find records for all the classes.<br>
+      for (auto &Descriptor : AttrClassDescriptors) {<br>
+        Record *ClassRecord = Records.getClass(Descriptor.TableGenName);<br>
+        AttrClass *Class = new AttrClass(Descriptor, ClassRecord);<br>
+        Classes.emplace_back(Class);<br>
+      }<br>
+<br>
+      // Link up the hierarchy.<br>
+      for (auto &Class : Classes) {<br>
+        if (AttrClass *SuperClass = findSuperClass(Class->TheRecord)) {<br>
+          Class->SuperClass = SuperClass;<br>
+          SuperClass->SubClasses.push_back(Class.get());<br>
+        }<br>
+      }<br>
+<br>
+#ifndef NDEBUG<br>
+      for (auto i = Classes.begin(), e = Classes.end(); i != e; ++i) {<br>
+        assert((i == Classes.begin()) == ((*i)->SuperClass == nullptr) &&<br>
+               "only the first class should be a root class!");<br>
+      }<br>
+#endif<br>
+    }<br>
+<br>
+    void emitDefaultDefines(raw_ostream &OS) const {<br>
+      for (auto &Class : Classes) {<br>
+        Class->emitDefaultDefines(OS);<br>
+      }<br>
+    }<br>
+<br>
+    void emitUndefs(raw_ostream &OS) const {<br>
+      for (auto &Class : Classes) {<br>
+        Class->emitUndefs(OS);<br>
+      }<br>
+    }<br>
+<br>
+    void emitAttrLists(raw_ostream &OS) const {<br>
+      // Just start from the root class.<br>
+      Classes[0]->emitAttrList(OS);<br>
+    }<br>
+<br>
+    void emitAttrRanges(raw_ostream &OS) const {<br>
+      for (auto &Class : Classes)<br>
+        Class->emitAttrRange(OS);<br>
+    }<br>
+<br>
+    void classifyAttr(Record *Attr) {<br>
+      // Add the attribute to the root class.<br>
+      Classes[0]->classifyAttrOnRoot(Attr);<br>
+    }<br>
+<br>
+  private:<br>
+    AttrClass *findClassByRecord(Record *R) const {<br>
+      for (auto &Class : Classes) {<br>
+        if (Class->TheRecord == R)<br>
+          return Class.get();<br>
+      }<br>
+      return nullptr;<br>
+    }<br>
+<br>
+    AttrClass *findSuperClass(Record *R) const {<br>
+      // TableGen flattens the superclass list, so we just need to walk it<br>
+      // in reverse.<br>
+      auto SuperClasses = R->getSuperClasses();<br>
+      for (signed i = 0, e = SuperClasses.size(); i != e; ++i) {<br>
+        auto SuperClass = findClassByRecord(SuperClasses[e - i - 1].first);<br>
+        if (SuperClass) return SuperClass;<br>
+      }<br>
+      return nullptr;<br>
+    }<br>
+  };<br>
+}<br>
+<br>
+namespace clang {<br>
+// Emits the enumeration list for attributes.<br>
+void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {<br>
+  emitSourceFileHeader("List of all attributes that Clang recognizes", OS);<br>
+<br>
+  AttrClassHierarchy Hierarchy(Records);<br>
+<br>
+  // Add defaulting macro definitions.<br>
+  Hierarchy.emitDefaultDefines(OS);<br>
+  emitDefaultDefine(OS, "PRAGMA_SPELLING_ATTR", nullptr);<br>
+<br>
+  std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");<br>
+  std::vector<Record *> PragmaAttrs;<br>
   for (auto *Attr : Attrs) {<br>
     if (!Attr->getValueAsBit("ASTNode"))<br>
       continue;<br>
<br>
+    // Add the attribute to the ad-hoc groups.<br>
     if (AttrHasPragmaSpelling(Attr))<br>
       PragmaAttrs.push_back(Attr);<br>
<br>
-    if (Attr->isSubClassOf(InhParamClass))<br>
-      InhParamAttrs.push_back(Attr);<br>
-    else if (Attr->isSubClassOf(InhClass))<br>
-      InhAttrs.push_back(Attr);<br>
-    else<br>
-      NonInhAttrs.push_back(Attr);<br>
+    // Place it in the hierarchy.<br>
+    Hierarchy.classifyAttr(Attr);<br>
   }<br>
<br>
-  EmitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs);<br>
-  EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);<br>
-  EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);<br>
-  EmitAttrList(OS, "ATTR", NonInhAttrs);<br>
-<br>
-  OS << "#undef LAST_ATTR\n";<br>
-  OS << "#undef INHERITABLE_ATTR\n";<br>
-  OS << "#undef LAST_INHERITABLE_ATTR\n";<br>
-  OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n";<br>
-  OS << "#undef LAST_PRAGMA_ATTR\n";<br>
+  // Emit the main attribute list.<br>
+  Hierarchy.emitAttrLists(OS);<br>
+<br>
+  // Emit the ad hoc groups.<br>
+  emitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs);<br>
+<br>
+  // Emit the attribute ranges.<br>
+  OS << "#ifdef ATTR_RANGE\n";<br>
+  Hierarchy.emitAttrRanges(OS);<br>
+  OS << "#undef ATTR_RANGE\n";<br>
+  OS << "#endif\n";<br>
+<br>
+  Hierarchy.emitUndefs(OS);<br>
   OS << "#undef PRAGMA_SPELLING_ATTR\n";<br>
-  OS << "#undef ATTR\n";<br>
 }<br>
<br>
 // Emits the code to read an attribute from a precompiled header.<br>
@@ -1841,8 +1974,6 @@ void EmitClangAttrPCHRead(RecordKeeper &<br>
   std::vector<std::unique_ptr<Argument>> Args;<br>
<br>
   OS << "  switch (Kind) {\n";<br>
-  OS << "  default:\n";<br>
-  OS << "    llvm_unreachable(\"Unknown attribute!\");\n";<br>
   for (const auto *Attr : Attrs) {<br>
     const Record &R = *Attr;<br>
     if (!R.getValueAsBit("ASTNode"))<br>
@@ -1882,9 +2013,6 @@ void EmitClangAttrPCHWrite(RecordKeeper<br>
   std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;<br>
<br>
   OS << "  switch (A->getKind()) {\n";<br>
-  OS << "  default:\n";<br>
-  OS << "    llvm_unreachable(\"Unknown attribute kind!\");\n";<br>
-  OS << "    break;\n";<br>
   for (const auto *Attr : Attrs) {<br>
     const Record &R = *Attr;<br>
     if (!R.getValueAsBit("ASTNode"))<br>
@@ -2075,11 +2203,7 @@ void EmitClangAttrSpellingListIndex(Reco<br>
   emitSourceFileHeader("Code to translate different attribute spellings "<br>
                        "into internal identifiers", OS);<br>
<br>
-  OS <<<br>
-    "  switch (AttrKind) {\n"<br>
-    "  default:\n"<br>
-    "    llvm_unreachable(\"Unknown attribute kind!\");\n"<br>
-    "    break;\n";<br>
+  OS << "  switch (AttrKind) {\n";<br>
<br>
   ParsedAttrMap Attrs = getParsedAttrList(Records);<br>
   for (const auto &I : Attrs) {<br>
@@ -2159,9 +2283,7 @@ void EmitClangAttrASTVisitor(RecordKeepe<br>
      << "  if (!A)\n"<br>
      << "    return true;\n"<br>
      << "\n"<br>
-     << "  switch (A->getKind()) {\n"<br>
-     << "    default:\n"<br>
-     << "      return true;\n";<br>
+     << "  switch (A->getKind()) {\n";<br>
<br>
   for (const auto *Attr : Attrs) {<br>
     const Record &R = *Attr;<br>
@@ -2188,9 +2310,7 @@ void EmitClangAttrTemplateInstantiate(Re<br>
      << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "<br>
      << "Sema &S,\n"<br>
      << "        const MultiLevelTemplateArgumentList &TemplateArgs) {\n"<br>
-     << "  switch (At->getKind()) {\n"<br>
-     << "    default:\n"<br>
-     << "      break;\n";<br>
+     << "  switch (At->getKind()) {\n";<br>
<br>
   for (const auto *Attr : Attrs) {<br>
     const Record &R = *Attr;<br>
@@ -2788,11 +2908,7 @@ void EmitClangAttrParsedAttrKinds(Record<br>
 void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) {<br>
   emitSourceFileHeader("Attribute dumper", OS);<br>
<br>
-  OS <<<br>
-    "  switch (A->getKind()) {\n"<br>
-    "  default:\n"<br>
-    "    llvm_unreachable(\"Unknown attribute kind!\");\n"<br>
-    "    break;\n";<br>
+  OS << "  switch (A->getKind()) {\n";<br>
   std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;<br>
   for (const auto *Attr : Attrs) {<br>
     const Record &R = *Attr;<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>