Author: Sam McCall Date: 2022-03-07T17:41:35+01:00 New Revision: 54d6b5b67fb3106eaf560261920df682eafa860f
URL: https://github.com/llvm/llvm-project/commit/54d6b5b67fb3106eaf560261920df682eafa860f DIFF: https://github.com/llvm/llvm-project/commit/54d6b5b67fb3106eaf560261920df682eafa860f.diff LOG: [pseudo] Rename {Preprocess,PPStructure} -> DirectiveMap. NFC More precisely describes what this file does. Per comments on https://reviews.llvm.org/D121092 Added: clang/include/clang/Tooling/Syntax/Pseudo/DirectiveMap.h clang/lib/Tooling/Syntax/Pseudo/DirectiveMap.cpp clang/unittests/Tooling/Syntax/Pseudo/DirectiveMapTest.cpp Modified: clang/lib/Tooling/Syntax/Pseudo/CMakeLists.txt clang/test/Syntax/lex.c clang/tools/clang-pseudo/ClangPseudo.cpp clang/unittests/Tooling/Syntax/Pseudo/CMakeLists.txt Removed: clang/include/clang/Tooling/Syntax/Pseudo/Preprocess.h clang/lib/Tooling/Syntax/Pseudo/Preprocess.cpp clang/unittests/Tooling/Syntax/Pseudo/PreprocessTest.cpp ################################################################################ diff --git a/clang/include/clang/Tooling/Syntax/Pseudo/Preprocess.h b/clang/include/clang/Tooling/Syntax/Pseudo/DirectiveMap.h similarity index 88% rename from clang/include/clang/Tooling/Syntax/Pseudo/Preprocess.h rename to clang/include/clang/Tooling/Syntax/Pseudo/DirectiveMap.h index 11a92042e7496..177302d9bae7a 100644 --- a/clang/include/clang/Tooling/Syntax/Pseudo/Preprocess.h +++ b/clang/include/clang/Tooling/Syntax/Pseudo/DirectiveMap.h @@ -1,4 +1,4 @@ -//===--- Preprocess.h - Preprocess token streams -----------------*- C++-*-===// +//===--- DirectiveMap.h - Find and strip preprocessor directives -*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -56,7 +56,7 @@ namespace pseudo { /// /// Unlike the clang preprocessor, we model the full tree explicitly. /// This class does not recognize macro usage, only directives. -struct PPStructure { +struct DirectiveMap { /// A range of code (and possibly comments) containing no directives. struct Code { Token::Range Tokens; @@ -76,7 +76,7 @@ struct PPStructure { /// /// The first branch will have an #if type directive. /// Subsequent branches will have #else type directives. - std::vector<std::pair<Directive, PPStructure>> Branches; + std::vector<std::pair<Directive, DirectiveMap>> Branches; /// The directive terminating the conditional, should be #endif. Directive End; }; @@ -86,22 +86,22 @@ struct PPStructure { std::vector<Chunk> Chunks; /// Extract preprocessor structure by examining the raw tokens. - static PPStructure parse(const TokenStream &); + static DirectiveMap parse(const TokenStream &); // FIXME: add heuristically selection of conditional branches. // FIXME: allow deriving a preprocessed stream }; -llvm::raw_ostream &operator<<(llvm::raw_ostream &, const PPStructure &); -llvm::raw_ostream &operator<<(llvm::raw_ostream &, const PPStructure::Chunk &); -llvm::raw_ostream &operator<<(llvm::raw_ostream &, const PPStructure::Code &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DirectiveMap &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DirectiveMap::Chunk &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DirectiveMap::Code &); llvm::raw_ostream &operator<<(llvm::raw_ostream &, - const PPStructure::Directive &); + const DirectiveMap::Directive &); llvm::raw_ostream &operator<<(llvm::raw_ostream &, - const PPStructure::Conditional &); + const DirectiveMap::Conditional &); // FIXME: This approximates std::variant<Code, Directive, Conditional>. // Switch once we can use C++17. -class PPStructure::Chunk { +class DirectiveMap::Chunk { public: enum Kind { K_Empty, K_Code, K_Directive, K_Conditional }; Kind kind() const { diff --git a/clang/lib/Tooling/Syntax/Pseudo/CMakeLists.txt b/clang/lib/Tooling/Syntax/Pseudo/CMakeLists.txt index be75138e60c60..1e00905731c83 100644 --- a/clang/lib/Tooling/Syntax/Pseudo/CMakeLists.txt +++ b/clang/lib/Tooling/Syntax/Pseudo/CMakeLists.txt @@ -1,13 +1,13 @@ set(LLVM_LINK_COMPONENTS Support) add_clang_library(clangToolingSyntaxPseudo + DirectiveMap.cpp Grammar.cpp GrammarBNF.cpp Lex.cpp LRGraph.cpp LRTable.cpp LRTableBuild.cpp - Preprocess.cpp Token.cpp LINK_LIBS diff --git a/clang/lib/Tooling/Syntax/Pseudo/Preprocess.cpp b/clang/lib/Tooling/Syntax/Pseudo/DirectiveMap.cpp similarity index 72% rename from clang/lib/Tooling/Syntax/Pseudo/Preprocess.cpp rename to clang/lib/Tooling/Syntax/Pseudo/DirectiveMap.cpp index 3a6403a147c91..06a3b4400cf39 100644 --- a/clang/lib/Tooling/Syntax/Pseudo/Preprocess.cpp +++ b/clang/lib/Tooling/Syntax/Pseudo/DirectiveMap.cpp @@ -1,4 +1,4 @@ -//===--- Preprocess.cpp - Preprocess token streams ------------------------===// +//===--- DirectiveMap.cpp - Find and strip preprocessor directives --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Tooling/Syntax/Pseudo/Preprocess.h" +#include "clang/Tooling/Syntax/Pseudo/DirectiveMap.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TokenKinds.h" #include "llvm/Support/FormatVariadic.h" @@ -16,10 +16,11 @@ namespace syntax { namespace pseudo { namespace { -class PPParser { +class DirectiveParser { public: - explicit PPParser(const TokenStream &Code) : Code(Code), Tok(&Code.front()) {} - void parse(PPStructure *Result) { parse(Result, /*TopLevel=*/true); } + explicit DirectiveParser(const TokenStream &Code) + : Code(Code), Tok(&Code.front()) {} + void parse(DirectiveMap *Result) { parse(Result, /*TopLevel=*/true); } private: // Roles that a directive might take within a conditional block. @@ -42,10 +43,11 @@ class PPParser { } } - // Parses tokens starting at Tok into PP. - // If we reach an End or Else directive that ends PP, returns it. + // Parses tokens starting at Tok into Map. + // If we reach an End or Else directive that ends Map, returns it. // If TopLevel is true, then we do not expect End and always return None. - llvm::Optional<PPStructure::Directive> parse(PPStructure *PP, bool TopLevel) { + llvm::Optional<DirectiveMap::Directive> parse(DirectiveMap *Map, + bool TopLevel) { auto StartsDirective = [&, AllowDirectiveAt((const Token *)nullptr)]() mutable { if (Tok->flag(LexFlags::StartsPPLine)) { @@ -65,29 +67,29 @@ class PPParser { do ++Tok; while (Tok->Kind != tok::eof && !StartsDirective()); - PP->Chunks.push_back(PPStructure::Code{ + Map->Chunks.push_back(DirectiveMap::Code{ Token::Range{Code.index(*Start), Code.index(*Tok)}}); continue; } // We have some kind of directive. - PPStructure::Directive Directive; + DirectiveMap::Directive Directive; parseDirective(&Directive); Cond Kind = classifyDirective(Directive.Kind); if (Kind == Cond::If) { // #if or similar, starting a nested conditional block. - PPStructure::Conditional Conditional; + DirectiveMap::Conditional Conditional; Conditional.Branches.emplace_back(); Conditional.Branches.back().first = std::move(Directive); parseConditional(&Conditional); - PP->Chunks.push_back(std::move(Conditional)); + Map->Chunks.push_back(std::move(Conditional)); } else if ((Kind == Cond::Else || Kind == Cond::End) && !TopLevel) { - // #endif or similar, ending this PPStructure scope. + // #endif or similar, ending this PStructure scope. // (#endif is unexpected at the top level, treat as simple directive). return std::move(Directive); } else { // #define or similar, a simple directive at the current scope. - PP->Chunks.push_back(std::move(Directive)); + Map->Chunks.push_back(std::move(Directive)); } } return None; @@ -95,7 +97,7 @@ class PPParser { // Parse the rest of a conditional section, after seeing the If directive. // Returns after consuming the End directive. - void parseConditional(PPStructure::Conditional *C) { + void parseConditional(DirectiveMap::Conditional *C) { assert(C->Branches.size() == 1 && C->Branches.front().second.Chunks.empty() && "Should be ready to parse first branch body"); @@ -118,7 +120,7 @@ class PPParser { } // Parse a directive. Tok is the hash. - void parseDirective(PPStructure::Directive *D) { + void parseDirective(DirectiveMap::Directive *D) { assert(Tok->Kind == tok::hash); // Directive spans from the hash until the end of line or file. @@ -142,25 +144,26 @@ class PPParser { } // namespace -PPStructure PPStructure::parse(const TokenStream &Code) { - PPStructure Result; - PPParser(Code).parse(&Result); +DirectiveMap DirectiveMap::parse(const TokenStream &Code) { + DirectiveMap Result; + DirectiveParser(Code).parse(&Result); return Result; } -static void dump(llvm::raw_ostream &OS, const PPStructure &, unsigned Indent); -static void dump(llvm::raw_ostream &OS, const PPStructure::Directive &Directive, +static void dump(llvm::raw_ostream &OS, const DirectiveMap &, unsigned Indent); +static void dump(llvm::raw_ostream &OS, const DirectiveMap::Directive &Directive, unsigned Indent) { OS.indent(Indent) << llvm::formatv("#{0} ({1} tokens)\n", tok::getPPKeywordSpelling(Directive.Kind), Directive.Tokens.size()); } -static void dump(llvm::raw_ostream &OS, const PPStructure::Code &Code, +static void dump(llvm::raw_ostream &OS, const DirectiveMap::Code &Code, unsigned Indent) { OS.indent(Indent) << llvm::formatv("code ({0} tokens)\n", Code.Tokens.size()); } static void dump(llvm::raw_ostream &OS, - const PPStructure::Conditional &Conditional, unsigned Indent) { + const DirectiveMap::Conditional &Conditional, + unsigned Indent) { for (const auto &Branch : Conditional.Branches) { dump(OS, Branch.first, Indent); dump(OS, Branch.second, Indent + 2); @@ -168,23 +171,23 @@ static void dump(llvm::raw_ostream &OS, dump(OS, Conditional.End, Indent); } -static void dump(llvm::raw_ostream &OS, const PPStructure::Chunk &Chunk, +static void dump(llvm::raw_ostream &OS, const DirectiveMap::Chunk &Chunk, unsigned Indent) { switch (Chunk.kind()) { - case PPStructure::Chunk::K_Empty: + case DirectiveMap::Chunk::K_Empty: llvm_unreachable("invalid chunk"); - case PPStructure::Chunk::K_Code: - return dump(OS, (const PPStructure::Code &)Chunk, Indent); - case PPStructure::Chunk::K_Directive: - return dump(OS, (const PPStructure::Directive &)Chunk, Indent); - case PPStructure::Chunk::K_Conditional: - return dump(OS, (const PPStructure::Conditional &)Chunk, Indent); + case DirectiveMap::Chunk::K_Code: + return dump(OS, (const DirectiveMap::Code &)Chunk, Indent); + case DirectiveMap::Chunk::K_Directive: + return dump(OS, (const DirectiveMap::Directive &)Chunk, Indent); + case DirectiveMap::Chunk::K_Conditional: + return dump(OS, (const DirectiveMap::Conditional &)Chunk, Indent); } } -static void dump(llvm::raw_ostream &OS, const PPStructure &PP, +static void dump(llvm::raw_ostream &OS, const DirectiveMap &Map, unsigned Indent) { - for (const auto &Chunk : PP.Chunks) + for (const auto &Chunk : Map.Chunks) dump(OS, Chunk, Indent); } @@ -194,11 +197,11 @@ static void dump(llvm::raw_ostream &OS, const PPStructure &PP, dump(OS, T, 0); \ return OS; \ } -OSTREAM_DUMP(PPStructure) -OSTREAM_DUMP(PPStructure::Chunk) -OSTREAM_DUMP(PPStructure::Directive) -OSTREAM_DUMP(PPStructure::Conditional) -OSTREAM_DUMP(PPStructure::Code) +OSTREAM_DUMP(DirectiveMap) +OSTREAM_DUMP(DirectiveMap::Chunk) +OSTREAM_DUMP(DirectiveMap::Directive) +OSTREAM_DUMP(DirectiveMap::Conditional) +OSTREAM_DUMP(DirectiveMap::Code) #undef OSTREAM_DUMP } // namespace pseudo diff --git a/clang/test/Syntax/lex.c b/clang/test/Syntax/lex.c index 7ec015417a177..39b114e8d9617 100644 --- a/clang/test/Syntax/lex.c +++ b/clang/test/Syntax/lex.c @@ -39,7 +39,7 @@ TOKEN-NEXT: hash 5:0 "#" flags=1 TOKEN-NEXT: raw_identifier 5:0 "endif" TOKEN-NEXT: r_brace 6:0 "}" flags=1 -RUN: clang-pseudo -source %s -print-pp-structure | FileCheck %s -check-prefix=PPS --strict-whitespace +RUN: clang-pseudo -source %s -print-directive-map | FileCheck %s -check-prefix=PPS --strict-whitespace PPS: code (5 tokens) PPS-NEXT: #ifndef (3 tokens) PPS-NEXT: code (4 tokens) diff --git a/clang/tools/clang-pseudo/ClangPseudo.cpp b/clang/tools/clang-pseudo/ClangPseudo.cpp index 59db927d8e081..c03cc0aaf8d91 100644 --- a/clang/tools/clang-pseudo/ClangPseudo.cpp +++ b/clang/tools/clang-pseudo/ClangPseudo.cpp @@ -7,10 +7,10 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/LangOptions.h" +#include "clang/Tooling/Syntax/Pseudo/DirectiveMap.h" #include "clang/Tooling/Syntax/Pseudo/Grammar.h" #include "clang/Tooling/Syntax/Pseudo/LRGraph.h" #include "clang/Tooling/Syntax/Pseudo/LRTable.h" -#include "clang/Tooling/Syntax/Pseudo/Preprocess.h" #include "clang/Tooling/Syntax/Pseudo/Token.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" @@ -33,8 +33,8 @@ static opt<std::string> Source("source", desc("Source file")); static opt<bool> PrintSource("print-source", desc("Print token stream")); static opt<bool> PrintTokens("print-tokens", desc("Print detailed token info")); static opt<bool> - PrintPPStructure("print-pp-structure", - desc("Print directive structure of source code")); + PrintDirectiveMap("print-directive-map", + desc("Print directive structure of source code")); static std::string readOrDie(llvm::StringRef Path) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = @@ -76,9 +76,9 @@ int main(int argc, char *argv[]) { std::string Text = readOrDie(Source); clang::LangOptions LangOpts; // FIXME: use real options. auto Stream = clang::syntax::pseudo::lex(Text, LangOpts); - auto Structure = clang::syntax::pseudo::PPStructure::parse(Stream); + auto Structure = clang::syntax::pseudo::DirectiveMap::parse(Stream); - if (PrintPPStructure) + if (PrintDirectiveMap) llvm::outs() << Structure; if (PrintSource) Stream.print(llvm::outs()); diff --git a/clang/unittests/Tooling/Syntax/Pseudo/CMakeLists.txt b/clang/unittests/Tooling/Syntax/Pseudo/CMakeLists.txt index 658ad9d926b96..0ece44ac19e62 100644 --- a/clang/unittests/Tooling/Syntax/Pseudo/CMakeLists.txt +++ b/clang/unittests/Tooling/Syntax/Pseudo/CMakeLists.txt @@ -3,9 +3,9 @@ set(LLVM_LINK_COMPONENTS ) add_clang_unittest(ClangPseudoTests + DirectiveMapTest.cpp GrammarTest.cpp LRTableTest.cpp - PreprocessTest.cpp TokenTest.cpp ) diff --git a/clang/unittests/Tooling/Syntax/Pseudo/PreprocessTest.cpp b/clang/unittests/Tooling/Syntax/Pseudo/DirectiveMapTest.cpp similarity index 75% rename from clang/unittests/Tooling/Syntax/Pseudo/PreprocessTest.cpp rename to clang/unittests/Tooling/Syntax/Pseudo/DirectiveMapTest.cpp index b6ff47d7fc8dc..1c3220b364738 100644 --- a/clang/unittests/Tooling/Syntax/Pseudo/PreprocessTest.cpp +++ b/clang/unittests/Tooling/Syntax/Pseudo/DirectiveMapTest.cpp @@ -1,4 +1,4 @@ -//===--- TokenTest.cpp ----------------------------------------------------===// +//===--- DirectiveMapTest.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Tooling/Syntax/Pseudo/Preprocess.h" +#include "clang/Tooling/Syntax/Pseudo/DirectiveMap.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TokenKinds.h" @@ -26,7 +26,7 @@ using testing::ElementsAre; using testing::Matcher; using testing::Pair; using testing::StrEq; -using Chunk = PPStructure::Chunk; +using Chunk = DirectiveMap::Chunk; MATCHER_P2(tokensAre, TS, Tokens, "tokens are " + std::string(Tokens)) { std::vector<llvm::StringRef> Texts; @@ -38,7 +38,7 @@ MATCHER_P2(tokensAre, TS, Tokens, "tokens are " + std::string(Tokens)) { MATCHER_P(chunkKind, K, "") { return arg.kind() == K; } -TEST(PPStructure, Parse) { +TEST(DirectiveMap, Parse) { LangOptions Opts; std::string Code = R"cpp( #include <foo.h> @@ -57,30 +57,30 @@ TEST(PPStructure, Parse) { )cpp"; TokenStream S = cook(lex(Code, Opts), Opts); - PPStructure PP = PPStructure::parse(S); + DirectiveMap PP = DirectiveMap::parse(S); ASSERT_THAT(PP.Chunks, ElementsAre(chunkKind(Chunk::K_Directive), chunkKind(Chunk::K_Code), chunkKind(Chunk::K_Conditional), chunkKind(Chunk::K_Code))); - EXPECT_THAT((const PPStructure::Directive &)PP.Chunks[0], + EXPECT_THAT((const DirectiveMap::Directive &)PP.Chunks[0], tokensAre(S, "# include < foo . h >")); - EXPECT_THAT((const PPStructure::Code &)PP.Chunks[1], + EXPECT_THAT((const DirectiveMap::Code &)PP.Chunks[1], tokensAre(S, "int main ( ) {")); - EXPECT_THAT((const PPStructure::Code &)PP.Chunks[3], tokensAre(S, "}")); + EXPECT_THAT((const DirectiveMap::Code &)PP.Chunks[3], tokensAre(S, "}")); - const PPStructure::Conditional &Ifdef(PP.Chunks[2]); + const DirectiveMap::Conditional &Ifdef(PP.Chunks[2]); EXPECT_THAT(Ifdef.Branches, ElementsAre(Pair(tokensAre(S, "# ifdef HAS_FOO"), _), Pair(tokensAre(S, "# elif NEEDS_FOO"), _))); EXPECT_THAT(Ifdef.End, tokensAre(S, "# endif")); - const PPStructure &HasFoo(Ifdef.Branches[0].second); - const PPStructure &NeedsFoo(Ifdef.Branches[1].second); + const DirectiveMap &HasFoo(Ifdef.Branches[0].second); + const DirectiveMap &NeedsFoo(Ifdef.Branches[1].second); EXPECT_THAT(HasFoo.Chunks, ElementsAre(chunkKind(Chunk::K_Conditional))); - const PPStructure::Conditional &If(HasFoo.Chunks[0]); + const DirectiveMap::Conditional &If(HasFoo.Chunks[0]); EXPECT_THAT(If.Branches, ElementsAre(Pair(tokensAre(S, "# if HAS_BAR"), _), Pair(tokensAre(S, "# else"), _))); EXPECT_THAT(If.Branches[0].second.Chunks, @@ -89,12 +89,12 @@ TEST(PPStructure, Parse) { ElementsAre(chunkKind(Chunk::K_Code))); EXPECT_THAT(NeedsFoo.Chunks, ElementsAre(chunkKind(Chunk::K_Directive))); - const PPStructure::Directive &Error(NeedsFoo.Chunks[0]); + const DirectiveMap::Directive &Error(NeedsFoo.Chunks[0]); EXPECT_THAT(Error, tokensAre(S, "# error missing_foo")); EXPECT_EQ(Error.Kind, tok::pp_error); } -TEST(PPStructure, ParseUgly) { +TEST(DirectiveMap, ParseUgly) { LangOptions Opts; std::string Code = R"cpp( /*A*/ # /*B*/ \ @@ -104,19 +104,19 @@ BAR /*D*/ /*E*/ )cpp"; TokenStream S = cook(lex(Code, Opts), Opts); - PPStructure PP = PPStructure::parse(S); + DirectiveMap PP = DirectiveMap::parse(S); ASSERT_THAT(PP.Chunks, ElementsAre(chunkKind(Chunk::K_Code), chunkKind(Chunk::K_Directive), chunkKind(Chunk::K_Code))); - EXPECT_THAT((const PPStructure::Code &)PP.Chunks[0], tokensAre(S, "/*A*/")); - const PPStructure::Directive &Define(PP.Chunks[1]); + EXPECT_THAT((const DirectiveMap::Code &)PP.Chunks[0], tokensAre(S, "/*A*/")); + const DirectiveMap::Directive &Define(PP.Chunks[1]); EXPECT_EQ(Define.Kind, tok::pp_define); EXPECT_THAT(Define, tokensAre(S, "# /*B*/ /*C*/ define BAR /*D*/")); - EXPECT_THAT((const PPStructure::Code &)PP.Chunks[2], tokensAre(S, "/*E*/")); + EXPECT_THAT((const DirectiveMap::Code &)PP.Chunks[2], tokensAre(S, "/*E*/")); } -TEST(PPStructure, ParseBroken) { +TEST(DirectiveMap, ParseBroken) { LangOptions Opts; std::string Code = R"cpp( a @@ -125,17 +125,17 @@ TEST(PPStructure, ParseBroken) { b )cpp"; TokenStream S = cook(lex(Code, Opts), Opts); - PPStructure PP = PPStructure::parse(S); + DirectiveMap PP = DirectiveMap::parse(S); ASSERT_THAT(PP.Chunks, ElementsAre(chunkKind(Chunk::K_Code), chunkKind(Chunk::K_Directive), chunkKind(Chunk::K_Conditional))); - EXPECT_THAT((const PPStructure::Code &)PP.Chunks[0], tokensAre(S, "a")); - const PPStructure::Directive &Endif(PP.Chunks[1]); + EXPECT_THAT((const DirectiveMap::Code &)PP.Chunks[0], tokensAre(S, "a")); + const DirectiveMap::Directive &Endif(PP.Chunks[1]); EXPECT_EQ(Endif.Kind, tok::pp_endif); EXPECT_THAT(Endif, tokensAre(S, "# endif // mismatched")); - const PPStructure::Conditional &X(PP.Chunks[2]); + const DirectiveMap::Conditional &X(PP.Chunks[2]); EXPECT_EQ(1u, X.Branches.size()); // The (only) branch of the broken conditional section runs until eof. EXPECT_EQ(tok::pp_if, X.Branches.front().first.Kind); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits