llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-ssaf Author: Aviral Goel (aviralg) <details> <summary>Changes</summary> This change Introduces the analysis execution layer of the Scalable Static Analysis Framework. This layer bridges the LUSummary (entity summaries from the linker phase) to WPASuite (the collection of whole-program analysis results). It introduces the following classes: - `AnalysisResult` — base class for all per-analysis results. - `AnalysisBase` — minimal common base with a private kind tag used by the driver for dispatch - `SummaryAnalysis<ResultT, EntitySummaryT>` — processes per-entity EntitySummary objects from LUSummary. - `DerivedAnalysis<ResultT, DepResultTs...>` — consumes previously produced AnalysisResult objects. - `AnalysisRegistry` — unified `llvm::Registry` backed registry to register analyses. - `WPASuite` — Container bundling `EntityIdTable` and all `AnalysisResult` objects from a driver run. - `AnalysisDriver` — executes analyses topologically, feeding results of child analyses to parent analyses. --- Patch is 65.33 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/186813.diff 17 Files Affected: - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisBase.h (+55) - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisDriver.h (+96) - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.h (+49) - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisRegistry.h (+100) - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisResult.h (+30) - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisTraits.h (+33) - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/DerivedAnalysis.h (+145) - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/SummaryAnalysis.h (+134) - (added) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/WPASuite.h (+96) - (modified) clang/include/clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummary.h (+1) - (modified) clang/include/clang/ScalableStaticAnalysisFramework/Core/Support/FormatProviders.h (+8) - (added) clang/lib/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisDriver.cpp (+207) - (added) clang/lib/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.cpp (+16) - (added) clang/lib/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisRegistry.cpp (+44) - (modified) clang/lib/ScalableStaticAnalysisFramework/Core/CMakeLists.txt (+3) - (added) clang/unittests/ScalableStaticAnalysisFramework/Analysis/AnalysisDriverTest.cpp (+553) - (modified) clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt (+1) ``````````diff diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisBase.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisBase.h new file mode 100644 index 0000000000000..29c46f3c2e544 --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisBase.h @@ -0,0 +1,55 @@ +//===- AnalysisBase.h -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Minimal common base for SummaryAnalysisBase and DerivedAnalysisBase. +// Carries the identity (analysisName()) and dependency list +// (dependencyNames()) shared by every analysis regardless of kind. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISBASE_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISBASE_H + +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.h" +#include <vector> + +namespace clang::ssaf { + +class AnalysisDriver; +class SummaryAnalysisBase; +class DerivedAnalysisBase; + +/// Minimal common base for both analysis kinds. +/// +/// Not subclassed directly -- use SummaryAnalysis<...> or +/// DerivedAnalysis<...> instead. +class AnalysisBase { + friend class AnalysisDriver; + friend class SummaryAnalysisBase; + friend class DerivedAnalysisBase; + + enum class Kind { Summary, Derived }; + Kind TheKind; + +protected: + explicit AnalysisBase(Kind K) : TheKind(K) {} + +public: + virtual ~AnalysisBase() = default; + + /// Name of this analysis. Equal to ResultT::analysisName() in both typed + /// intermediates. + virtual AnalysisName analysisName() const = 0; + + /// AnalysisNames of all AnalysisResult dependencies. + virtual const std::vector<AnalysisName> &dependencyNames() const = 0; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISBASE_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisDriver.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisDriver.h new file mode 100644 index 0000000000000..c17cd584f2434 --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisDriver.h @@ -0,0 +1,96 @@ +//===- AnalysisDriver.h ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Central orchestrator for whole-program analysis. Takes ownership of an +// LUSummary, drives all registered analyses in topological dependency order, +// and returns a WPASuite. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISDRIVER_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISDRIVER_H + +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/WPASuite.h" +#include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummary.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Error.h" +#include <memory> +#include <vector> + +namespace clang::ssaf { + +class AnalysisBase; +class SummaryAnalysisBase; +class DerivedAnalysisBase; + +/// Orchestrates whole-program analysis over an LUSummary. +/// +/// Three run() patterns are supported: +/// - run() && -- all registered analyses in topological dependency +/// order. Returns an error if any registered analysis +/// has no matching entity data in the LUSummary. +/// Requires an rvalue driver because this exhausts the +/// LUSummary. +/// - run(names) -- named subset plus transitive dependencies; returns +/// Expected and fails if any listed name has no +/// registered analysis or missing entity data. +/// - run<ResultTs..> -- type-safe variant of run(names). +class AnalysisDriver final { +public: + explicit AnalysisDriver(std::unique_ptr<LUSummary> LU); + + /// Runs all registered analyses in topological dependency order. + /// Returns an error if any registered analysis has no matching entity data + /// in the LUSummary. + /// + /// Requires an rvalue driver (std::move(Driver).run()) because this + /// exhausts all remaining LUSummary data. + [[nodiscard]] llvm::Expected<WPASuite> run() &&; + + /// Runs only the named analyses (plus their transitive dependencies). + /// + /// Returns an error if any listed AnalysisName has no registered analysis + /// or if a required SummaryAnalysis has no matching entity data in the + /// LUSummary. The EntityIdTable is copied (not moved) so the driver remains + /// usable for subsequent calls. + [[nodiscard]] llvm::Expected<WPASuite> + run(llvm::ArrayRef<AnalysisName> Names); + + /// Type-safe variant of run(names). Derives names from + /// ResultTs::analysisName(). + template <typename... ResultTs> [[nodiscard]] llvm::Expected<WPASuite> run() { + return run({ResultTs::analysisName()...}); + } + +private: + std::unique_ptr<LUSummary> LU; + + /// Instantiates all analyses reachable from \p Roots (plus transitive + /// dependencies) and returns them in topological order via a single DFS. + /// Reports an error on unregistered names or cycles. + static llvm::Expected<std::vector<std::unique_ptr<AnalysisBase>>> + sort(llvm::ArrayRef<AnalysisName> Roots); + + /// Executes a topologically-sorted analysis list and returns a WPASuite. + /// \p IdTable is moved into the returned WPASuite. + llvm::Expected<WPASuite> + execute(EntityIdTable IdTable, + std::vector<std::unique_ptr<AnalysisBase>> Sorted); + + llvm::Error + executeSummaryAnalysis(std::unique_ptr<SummaryAnalysisBase> Summary, + WPASuite &Suite); + + llvm::Error + executeDerivedAnalysis(std::unique_ptr<DerivedAnalysisBase> Derived, + WPASuite &Suite); +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISDRIVER_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.h new file mode 100644 index 0000000000000..73ba96ccc594e --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.h @@ -0,0 +1,49 @@ +//===- AnalysisName.h -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Strong typedef identifying a whole-program analysis and its result type. +// Distinct from SummaryName, which identifies per-entity EntitySummary types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISNAME_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISNAME_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +namespace clang::ssaf { + +/// Uniquely identifies a whole-program analysis and the AnalysisResult it +/// produces. Used as the key in WPASuite and AnalysisRegistry. +/// +/// Distinct from SummaryName, which is used by EntitySummary types for routing +/// through the LUSummary. +class AnalysisName { +public: + explicit AnalysisName(std::string Name) : Name(std::move(Name)) {} + + bool operator==(const AnalysisName &Other) const { + return Name == Other.Name; + } + bool operator!=(const AnalysisName &Other) const { return !(*this == Other); } + bool operator<(const AnalysisName &Other) const { return Name < Other.Name; } + + /// Explicit conversion to the underlying string representation. + llvm::StringRef str() const { return Name; } + +private: + std::string Name; +}; + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const AnalysisName &AN); + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISNAME_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisRegistry.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisRegistry.h new file mode 100644 index 0000000000000..4ed5999bda477 --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisRegistry.h @@ -0,0 +1,100 @@ +//===- AnalysisRegistry.h -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Unified registry for both SummaryAnalysis and DerivedAnalysis subclasses. +// +// To register an analysis, add a static Add<AnalysisT> in its translation +// unit: +// +// static AnalysisRegistry::Add<MyAnalysis> +// Registered("One-line description of MyAnalysis"); +// +// The registry entry name is derived automatically from +// MyAnalysis::analysisName(), so name-mismatch bugs are impossible. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISREGISTRY_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISREGISTRY_H + +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.h" +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/DerivedAnalysis.h" +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/SummaryAnalysis.h" +#include "clang/ScalableStaticAnalysisFramework/Core/Support/ErrorBuilder.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Registry.h" +#include <memory> +#include <string> +#include <vector> + +namespace clang::ssaf { + +/// Unified registry for SummaryAnalysis and DerivedAnalysis implementations. +/// +/// Internally uses a single llvm::Registry<AnalysisBase>. The correct kind +/// is carried by the AnalysisBase::TheKind tag set in each subclass +/// constructor. +class AnalysisRegistry { + using RegistryT = llvm::Registry<AnalysisBase>; + + AnalysisRegistry() = delete; + +public: + /// Registers AnalysisT with the unified registry. + /// + /// The registry entry name is derived automatically from + /// AnalysisT::ResultType::analysisName(), so name-mismatch bugs are + /// impossible. + /// + /// Add objects must be declared static at namespace scope. + template <typename AnalysisT> struct Add { + static_assert(std::is_base_of_v<SummaryAnalysisBase, AnalysisT> || + std::is_base_of_v<DerivedAnalysisBase, AnalysisT>, + "AnalysisT must derive from SummaryAnalysis<...> or " + "DerivedAnalysis<...>"); + + explicit Add(llvm::StringRef Desc) + : Name(AnalysisT::ResultType::analysisName().str().str()), + Node(Name, Desc) { + if (contains(Name)) { + ErrorBuilder::fatal("duplicate analysis registration for '{0}'", Name); + } + getAnalysisNames().push_back(AnalysisT::ResultType::analysisName()); + } + + Add(const Add &) = delete; + Add &operator=(const Add &) = delete; + + private: + std::string Name; + RegistryT::Add<AnalysisT> Node; + }; + + /// Returns true if an analysis is registered under \p Name. + static bool contains(llvm::StringRef Name); + + /// Returns the names of all registered analyses. + static const std::vector<AnalysisName> &names(); + + /// Instantiates the analysis registered under \p Name, or returns an error + /// if no such analysis is registered. + static llvm::Expected<std::unique_ptr<AnalysisBase>> + instantiate(llvm::StringRef Name); + +private: + /// Returns the global list of registered analysis names. + /// + /// Uses a function-local static to avoid static initialization order + /// fiasco: Add<T> objects in other translation units may push names before + /// a plain static data member could be constructed. + static std::vector<AnalysisName> &getAnalysisNames(); +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISREGISTRY_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisResult.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisResult.h new file mode 100644 index 0000000000000..7ac2a9ad7db6a --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisResult.h @@ -0,0 +1,30 @@ +//===- AnalysisResult.h ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Base class for all whole-program analysis results produced by AnalysisDriver. +// Concrete subclasses carry a static analysisName(). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISRESULT_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISRESULT_H + +namespace clang::ssaf { + +/// Base class for whole-program analysis results. +/// +/// Concrete subclasses must provide: +/// static AnalysisName analysisName(); +class AnalysisResult { +public: + virtual ~AnalysisResult() = default; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISRESULT_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisTraits.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisTraits.h new file mode 100644 index 0000000000000..ef6a5a56d990a --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisTraits.h @@ -0,0 +1,33 @@ +//===- AnalysisTraits.h ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Type traits for AnalysisResult subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISTRAITS_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISTRAITS_H + +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.h" +#include <type_traits> + +namespace clang::ssaf { + +/// Type trait that checks whether \p T has a static \c analysisName() method +/// returning \c AnalysisName. Used to enforce the convention on AnalysisResult +/// subclasses and analysis classes at instantiation time. +template <typename T, typename = void> +struct HasAnalysisName : std::false_type {}; + +template <typename T> +struct HasAnalysisName<T, std::void_t<decltype(T::analysisName())>> + : std::is_same<decltype(T::analysisName()), AnalysisName> {}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_ANALYSISTRAITS_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/DerivedAnalysis.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/DerivedAnalysis.h new file mode 100644 index 0000000000000..7066f3451a3d0 --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analysis/DerivedAnalysis.h @@ -0,0 +1,145 @@ +//===- DerivedAnalysis.h --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines DerivedAnalysisBase (type-erased base known to AnalysisDriver) and +// the typed intermediate DerivedAnalysis<ResultT, DepResultTs...> that +// concrete analyses inherit from. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_DERIVEDANALYSIS_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSIS_DERIVEDANALYSIS_H + +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisBase.h" +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisName.h" +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisResult.h" +#include "clang/ScalableStaticAnalysisFramework/Core/Analysis/AnalysisTraits.h" +#include "clang/ScalableStaticAnalysisFramework/Core/Support/ErrorBuilder.h" +#include "llvm/Support/Error.h" +#include <map> +#include <memory> +#include <vector> + +namespace clang::ssaf { + +class AnalysisDriver; +class AnalysisRegistry; + +/// Type-erased base for derived analyses. Known to AnalysisDriver. +/// +/// Not subclassed directly -- use DerivedAnalysis<ResultT, DepResultTs...>. +/// A derived analysis consumes previously produced AnalysisResult objects +/// and computes a new one via an initialize/step/finalize lifecycle. +class DerivedAnalysisBase : public AnalysisBase { + friend class AnalysisDriver; + +protected: + DerivedAnalysisBase() : AnalysisBase(AnalysisBase::Kind::Derived) {} + +private: + /// Called once with the dependency results before the step() loop. + /// + /// \param DepResults Immutable results of all declared dependencies, keyed + /// by AnalysisName. Guaranteed to contain every name + /// returned by dependencyNames(). + virtual llvm::Error initialize( + const std::map<AnalysisName, const AnalysisResult *> &DepResults) = 0; + + /// Performs one pass. Returns true if another pass is needed; false when + /// converged. + virtual llvm::Expected<bool> step() = 0; + + /// Called after the step() loop converges. Default is a no-op. + virtual llvm::Error finalize() { return llvm::Error::success(); } + + /// Transfers ownership of the computed result. Called once after finalize(). + virtual std::unique_ptr<AnalysisResult> result() && = 0; +}; + +/// Typed intermediate that concrete derived analyses inherit from. +/// +/// Concrete analyses must implement: +/// llvm::Error initialize(const DepResultTs &...) override; +/// llvm::Expected<bool> step() override; +/// and may override finalize(). +/// +/// Dependencies are fixed for the lifetime of the analysis: initialize() +/// binds them once, step() is called until it returns false, and +/// finalize() post-processes after convergence. +template <typename ResultT, typename... DepResultTs> +class DerivedAnalysis : public DerivedAnalysisBase { + static_assert(std::is_base_of_v<AnalysisResult, ResultT>, + "ResultT must derive from AnalysisResult"); + static_assert(HasAnalysisName<ResultT>::value, + "ResultT must have a static analysisName() method"); + static_assert((std::is_base_of_v<AnalysisResult, DepResultTs> && ...), + "Every DepResultT must derive from AnalysisResult"); + static_assert((HasAnalysisName<DepResultTs>::value && ...), + "... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/186813 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
