llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-ssaf Author: Aviral Goel (aviralg) <details> <summary>Changes</summary> This changes fixes the diagnostic infrastructure in `JSONFormat` implementation to pass model objects (`EntityId`, `EntityLinkage`, `BuildNamespace`, `NestedBuildNamespace`, `SummaryName`) directly to `ErrorBuilder` instead of manually extracting their components. This relies on existing `llvm::format_provider` specializations for these objects. To support consistent string conversion for `BuildNamespaceKind` and `EntityLinkageType`, across both serialization and `operator<<`, `toString`/`fromString` functions have been introduced in an internal header `ModelStringConversions.h`. `EntityLinkage::LinkageType` is promoted to a standalone enum class `EntityLinkageType` at namespace scope, following the same pattern as `BuildNamespaceKind`. Tests have been added for `operator<<` and `format_provider` for all affected types, and a new `ModelStringConversionsTest.cpp` directly unit-tests the `toString/fromString` functions including round-trip and unknown-input cases. --- Patch is 80.45 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/183390.diff 18 Files Affected: - (modified) clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h (+1-4) - (modified) clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h (+11-12) - (modified) clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h (-3) - (modified) clang/include/clang/Analysis/Scalable/Support/FormatProviders.h (+14) - (modified) clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp (+9-9) - (modified) clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp (+6-19) - (modified) clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp (+12-19) - (added) clang/lib/Analysis/Scalable/ModelStringConversions.h (+87) - (modified) clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp (+58-71) - (modified) clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp (+42-23) - (modified) clang/unittests/Analysis/Scalable/CMakeLists.txt (+5) - (modified) clang/unittests/Analysis/Scalable/EntityIdTest.cpp (+14) - (modified) clang/unittests/Analysis/Scalable/EntityLinkageTest.cpp (+41-3) - (modified) clang/unittests/Analysis/Scalable/EntityLinkerTest.cpp (+4-4) - (modified) clang/unittests/Analysis/Scalable/EntityNameTest.cpp (+14-2) - (added) clang/unittests/Analysis/Scalable/ModelStringConversionsTest.cpp (+100) - (modified) clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp (+140-134) - (modified) clang/unittests/Analysis/Scalable/SummaryNameTest.cpp (+7) ``````````diff diff --git a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h index 61c767e7953dc..39307d976e986 100644 --- a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h +++ b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h @@ -29,10 +29,6 @@ namespace clang::ssaf { enum class BuildNamespaceKind : unsigned short { CompilationUnit, LinkUnit }; -llvm::StringRef toString(BuildNamespaceKind BNK); - -std::optional<BuildNamespaceKind> parseBuildNamespaceKind(llvm::StringRef Str); - /// Represents a single namespace in the build process. /// /// A BuildNamespace groups program entities, such as those belonging to a @@ -123,6 +119,7 @@ class NestedBuildNamespace { const NestedBuildNamespace &NBN); }; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, BuildNamespaceKind BNK); llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const BuildNamespace &BN); llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const NestedBuildNamespace &NBN); diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h b/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h index 0d52a70ae7f92..3e9374d6ddab3 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h @@ -14,6 +14,12 @@ namespace clang::ssaf { +enum class EntityLinkageType { + None, ///< local variables, function parameters + Internal, ///< static functions/variables, anonymous namespace + External ///< globally visible across translation units +}; + /// Represents the linkage properties of an entity in the program model. /// /// EntityLinkage captures whether an entity has no linkage, internal linkage, @@ -24,26 +30,19 @@ class EntityLinkage { friend class TestFixture; public: - enum class LinkageType { - None, ///< local variables, function parameters - Internal, ///< static functions/variables, anonymous namespace - External ///< globally visible across translation units - }; + constexpr explicit EntityLinkage(EntityLinkageType L) : Linkage(L) {} - constexpr explicit EntityLinkage(LinkageType L) : Linkage(L) {} - - LinkageType getLinkage() const { return Linkage; } + EntityLinkageType getLinkage() const { return Linkage; } bool operator==(const EntityLinkage &Other) const; bool operator!=(const EntityLinkage &Other) const; private: - LinkageType Linkage; + EntityLinkageType Linkage; }; -/// Returns a string representation of the linkage type. -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - EntityLinkage::LinkageType Linkage); +/// Writes a string representation of the linkage type to the stream. +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EntityLinkageType Linkage); llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const EntityLinkage &Linkage); diff --git a/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h b/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h index 8d46bbf29863a..30dfa305238f6 100644 --- a/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h +++ b/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h @@ -69,9 +69,6 @@ class JSONFormat final : public SerializationFormat { EntityId entityIdFromJSON(const uint64_t EntityIdIndex) const; uint64_t entityIdToJSON(EntityId EI) const; - llvm::Expected<BuildNamespaceKind> - buildNamespaceKindFromJSON(llvm::StringRef BuildNamespaceKindStr) const; - llvm::Expected<BuildNamespace> buildNamespaceFromJSON(const Object &BuildNamespaceObject) const; Object buildNamespaceToJSON(const BuildNamespace &BN) const; diff --git a/clang/include/clang/Analysis/Scalable/Support/FormatProviders.h b/clang/include/clang/Analysis/Scalable/Support/FormatProviders.h index 3610a3b2d0074..80bbf79bbdb37 100644 --- a/clang/include/clang/Analysis/Scalable/Support/FormatProviders.h +++ b/clang/include/clang/Analysis/Scalable/Support/FormatProviders.h @@ -31,6 +31,13 @@ template <> struct format_provider<clang::ssaf::EntityId> { } }; +template <> struct format_provider<clang::ssaf::EntityLinkageType> { + static void format(clang::ssaf::EntityLinkageType Val, raw_ostream &OS, + StringRef Style) { + OS << Val; + } +}; + template <> struct format_provider<clang::ssaf::EntityLinkage> { static void format(clang::ssaf::EntityLinkage Val, raw_ostream &OS, StringRef Style) { @@ -38,6 +45,13 @@ template <> struct format_provider<clang::ssaf::EntityLinkage> { } }; +template <> struct format_provider<clang::ssaf::BuildNamespaceKind> { + static void format(clang::ssaf::BuildNamespaceKind Val, raw_ostream &OS, + StringRef Style) { + OS << Val; + } +}; + template <> struct format_provider<clang::ssaf::BuildNamespace> { static void format(const clang::ssaf::BuildNamespace &Val, raw_ostream &OS, StringRef Style) { diff --git a/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp b/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp index 1860a76db67aa..cd0c83a38a377 100644 --- a/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp +++ b/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp @@ -49,16 +49,16 @@ static constexpr const char *DuplicateTUNamespace = static NestedBuildNamespace resolveNamespace(const NestedBuildNamespace &LUNamespace, const NestedBuildNamespace &EntityNamespace, - EntityLinkage::LinkageType Linkage) { + EntityLinkageType Linkage) { switch (Linkage) { - case EntityLinkage::LinkageType::None: - case EntityLinkage::LinkageType::Internal: + case EntityLinkageType::None: + case EntityLinkageType::Internal: return EntityNamespace.makeQualified(LUNamespace); - case EntityLinkage::LinkageType::External: + case EntityLinkageType::External: return NestedBuildNamespace(LUNamespace); } - llvm_unreachable("Unhandled EntityLinkage::LinkageType variant"); + llvm_unreachable("Unhandled EntityLinkageType variant"); } EntityId EntityLinker::resolveEntity(const EntityName &OldName, @@ -79,8 +79,8 @@ EntityId EntityLinker::resolveEntity(const EntityName &OldName, // Insertion failure for `None` and `Internal` linkage is a fatal error // because these entities have unique namespaces and should never collide. // `External` linkage entities may collide. - if (Linkage.getLinkage() == EntityLinkage::LinkageType::None || - Linkage.getLinkage() == EntityLinkage::LinkageType::Internal) { + if (Linkage.getLinkage() == EntityLinkageType::None || + Linkage.getLinkage() == EntityLinkageType::Internal) { ErrorBuilder::fatal(ErrorMessages::EntityAlreadyExistsInLinkageTable, ErrorMessages::EntityLinkerFatalErrorPrefix, NewId, Linkage); @@ -144,8 +144,8 @@ EntityLinker::merge(TUSummaryEncoding &Summary, // Insertion should never fail for `None` and `Internal` linkage // entities because these entities will have different namespaces across // TUs even if their names match. - if (Linkage.getLinkage() == EntityLinkage::LinkageType::None || - Linkage.getLinkage() == EntityLinkage::LinkageType::Internal) { + if (Linkage.getLinkage() == EntityLinkageType::None || + Linkage.getLinkage() == EntityLinkageType::Internal) { ErrorBuilder::fatal( ErrorMessages::FailedToInsertEntityIntoOutputSummary, ErrorMessages::EntityLinkerFatalErrorPrefix, NewId, Linkage, SN); diff --git a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp index bdb2d03b3e7c1..b74ac7dcf80c8 100644 --- a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp +++ b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp @@ -7,30 +7,13 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Scalable/Model/BuildNamespace.h" +#include "../ModelStringConversions.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" #include <tuple> namespace clang::ssaf { -llvm::StringRef toString(BuildNamespaceKind BNK) { - switch (BNK) { - case BuildNamespaceKind::CompilationUnit: - return "compilation_unit"; - case BuildNamespaceKind::LinkUnit: - return "link_unit"; - } - llvm_unreachable("Unknown BuildNamespaceKind"); -} - -std::optional<BuildNamespaceKind> parseBuildNamespaceKind(llvm::StringRef Str) { - if (Str == "compilation_unit") - return BuildNamespaceKind::CompilationUnit; - if (Str == "link_unit") - return BuildNamespaceKind::LinkUnit; - return std::nullopt; -} - BuildNamespace BuildNamespace::makeCompilationUnit(llvm::StringRef CompilationId) { return BuildNamespace{BuildNamespaceKind::CompilationUnit, @@ -71,8 +54,12 @@ bool NestedBuildNamespace::operator<(const NestedBuildNamespace &Other) const { return Namespaces < Other.Namespaces; } +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, BuildNamespaceKind BNK) { + return OS << buildNamespaceKindToString(BNK); +} + llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const BuildNamespace &BN) { - return OS << "BuildNamespace(" << toString(BN.Kind) << ", " << BN.Name << ")"; + return OS << "BuildNamespace(" << BN.Kind << ", " << BN.Name << ")"; } llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, diff --git a/clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp b/clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp index 16cd78ee84943..d0c0654b5d5f6 100644 --- a/clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp +++ b/clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp @@ -7,27 +7,10 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Scalable/Model/EntityLinkage.h" -#include "llvm/Support/ErrorHandling.h" -namespace clang::ssaf { +#include "../ModelStringConversions.h" -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - EntityLinkage::LinkageType Linkage) { - switch (Linkage) { - case EntityLinkage::LinkageType::None: - return OS << "None"; - case EntityLinkage::LinkageType::Internal: - return OS << "Internal"; - case EntityLinkage::LinkageType::External: - return OS << "External"; - } - llvm_unreachable("Unhandled EntityLinkage::LinkageType variant"); -} - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const EntityLinkage &Linkage) { - return OS << "EntityLinkage(" << Linkage.getLinkage() << ")"; -} +namespace clang::ssaf { bool EntityLinkage::operator==(const EntityLinkage &Other) const { return Linkage == Other.Linkage; @@ -37,4 +20,14 @@ bool EntityLinkage::operator!=(const EntityLinkage &Other) const { return !(*this == Other); } +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + EntityLinkageType Linkage) { + return OS << entityLinkageTypeToString(Linkage); +} + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const EntityLinkage &Linkage) { + return OS << "EntityLinkage(" << Linkage.getLinkage() << ")"; +} + } // namespace clang::ssaf diff --git a/clang/lib/Analysis/Scalable/ModelStringConversions.h b/clang/lib/Analysis/Scalable/ModelStringConversions.h new file mode 100644 index 0000000000000..7042b08e7198e --- /dev/null +++ b/clang/lib/Analysis/Scalable/ModelStringConversions.h @@ -0,0 +1,87 @@ +//===- ModelStringConversions.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 +// +//===----------------------------------------------------------------------===// +// +// Internal string conversion utilities for SSAF model types. +// +// These functions are shared by the model .cpp files (for operator<<) and +// JSONFormat.cpp (for serialization). They are not part of the public API. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_LIB_ANALYSIS_SCALABLE_MODELSTRINGCONVERSIONS_H +#define CLANG_LIB_ANALYSIS_SCALABLE_MODELSTRINGCONVERSIONS_H + +#include "clang/Analysis/Scalable/Model/BuildNamespace.h" +#include "clang/Analysis/Scalable/Model/EntityLinkage.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" +#include <optional> + +namespace clang::ssaf { + +//===----------------------------------------------------------------------===// +// BuildNamespaceKind +//===----------------------------------------------------------------------===// + +/// Returns the canonical string representation of \p BNK used for +/// serialization and display (e.g. "CompilationUnit", "LinkUnit"). +inline llvm::StringRef buildNamespaceKindToString(BuildNamespaceKind BNK) { + switch (BNK) { + case BuildNamespaceKind::CompilationUnit: + return "CompilationUnit"; + case BuildNamespaceKind::LinkUnit: + return "LinkUnit"; + } + llvm_unreachable("Unhandled BuildNamespaceKind variant"); +} + +/// Parses a string produced by buildNamespaceKindToString(). Returns +/// std::nullopt if \p Str does not match any known BuildNamespaceKind value. +inline std::optional<BuildNamespaceKind> +buildNamespaceKindFromString(llvm::StringRef Str) { + if (Str == "CompilationUnit") + return BuildNamespaceKind::CompilationUnit; + if (Str == "LinkUnit") + return BuildNamespaceKind::LinkUnit; + return std::nullopt; +} + +//===----------------------------------------------------------------------===// +// EntityLinkageType +//===----------------------------------------------------------------------===// + +/// Returns the canonical string representation of \p LT used for +/// serialization and display (e.g. "None", "Internal", "External"). +inline llvm::StringRef entityLinkageTypeToString(EntityLinkageType LT) { + switch (LT) { + case EntityLinkageType::None: + return "None"; + case EntityLinkageType::Internal: + return "Internal"; + case EntityLinkageType::External: + return "External"; + } + llvm_unreachable("Unhandled EntityLinkageType variant"); +} + +/// Parses a string produced by entityLinkageTypeToString(). Returns +/// std::nullopt if \p Str does not match any known EntityLinkageType value. +inline std::optional<EntityLinkageType> +entityLinkageTypeFromString(llvm::StringRef Str) { + if (Str == "None") + return EntityLinkageType::None; + if (Str == "Internal") + return EntityLinkageType::Internal; + if (Str == "External") + return EntityLinkageType::External; + return std::nullopt; +} + +} // namespace clang::ssaf + +#endif // CLANG_LIB_ANALYSIS_SCALABLE_MODELSTRINGCONVERSIONS_H diff --git a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp index e2eda695a4eee..02c3b9b51da3e 100644 --- a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp +++ b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp @@ -1,6 +1,10 @@ #include "clang/Analysis/Scalable/Serialization/JSONFormat.h" + +#include "../ModelStringConversions.h" + #include "clang/Analysis/Scalable/Model/EntityLinkage.h" #include "clang/Analysis/Scalable/Support/ErrorBuilder.h" +#include "clang/Analysis/Scalable/Support/FormatProviders.h" #include "clang/Analysis/Scalable/TUSummary/TUSummary.h" #include "llvm/ADT/STLExtras.h" @@ -56,7 +60,7 @@ constexpr const char *ReadingFromFile = "reading {0} from file '{1}'"; constexpr const char *WritingToFile = "writing {0} to file '{1}'"; constexpr const char *FailedInsertionOnDuplication = - "failed to insert {0} at index '{1}': encountered duplicate {2} '{3}'"; + "failed to insert {0} at index '{1}': encountered duplicate '{2}'"; constexpr const char *FailedToReadObject = "failed to read {0}: expected JSON {1}"; @@ -66,24 +70,20 @@ constexpr const char *FailedToReadObjectAtIndex = "failed to read {0} from index '{1}': expected JSON {2}"; constexpr const char *FailedToDeserializeEntitySummaryNoFormatInfo = - "failed to deserialize EntitySummary: no FormatInfo registered for summary " - "'{0}'"; + "failed to deserialize EntitySummary: no FormatInfo registered for '{0}'"; constexpr const char *FailedToSerializeEntitySummaryNoFormatInfo = - "failed to serialize EntitySummary: no FormatInfo registered for summary " - "'{0}'"; + "failed to serialize EntitySummary: no FormatInfo registered for '{0}'"; constexpr const char *FailedToDeserializeEntitySummaryMissingData = - "failed to deserialize EntitySummary: null EntitySummary data for summary " - "'{0}'"; + "failed to deserialize EntitySummary: null EntitySummary data for '{0}'"; constexpr const char *FailedToSerializeEntitySummaryMissingData = - "JSONFormat - null EntitySummary data for summary '{0}'"; + "JSONFormat - null EntitySummary data for '{0}'"; constexpr const char *FailedToDeserializeEntitySummaryMismatchedSummaryName = - "failed to deserialize EntitySummary: EntitySummary data for summary '{0}' " - "reports mismatched summary '{1}'"; + "failed to deserialize EntitySummary: EntitySummary data for '{0}' reports " + "mismatched '{1}'"; constexpr const char *FailedToSerializeEntitySummaryMismatchedSummaryName = - "JSONFormat - EntitySummary data for summary '{0}' reports mismatched " - "summary '{1}'"; + "JSONFormat - EntitySummary data for '{0}' reports mismatched '{1}'"; constexpr const char *InvalidBuildNamespaceKind = "invalid 'kind' BuildNamespaceKind value '{0}'"; @@ -92,12 +92,10 @@ constexpr const char *InvalidEntityLinkageType = "invalid 'type' EntityLinkageType value '{0}'"; constexpr const char *FailedToDeserializeLinkageTableExtraId = - "failed to deserialize LinkageTable: extra EntityId '{0}' not present in " - "IdTable"; + "failed to deserialize LinkageTable: extra '{0}' not present in IdTable"; constexpr const char *FailedToDeserializeLinkageTableMissingId = - "failed to deserialize LinkageTable: missing EntityId '{0}' present in " - "IdTable"; + "failed to deserialize LinkageTable: missing '{0}' present in IdTable"; } // namespace ErrorMessages @@ -239,23 +237,24 @@ uint64_t JSONFormat::entityIdToJSON(EntityId EI) const { // BuildNamespaceKind //---------------------------------------------------------------------------- -llvm::Expected<BuildNamespaceKind> JSONFormat::buildNamespaceKindFromJSON( - llvm::StringRef BuildNamespaceKindStr) const { - auto OptBuildNamespaceKind = parseBuildNamespaceKind(BuildNamespaceKindStr); +namespace { + +llvm::Expected<BuildNamespaceKind> +buildNamespaceKindFromJSON(llvm::StringRef BuildNamespaceKindStr) { + auto OptBuildNamespaceKind = + buildNamespaceKindFromString(BuildNamespaceKindStr); if (!OptBuildNamespaceKind) { return ErrorBuilder::create(std::errc::invalid_argument, ErrorMessages::InvalidBuildNamespaceKind, BuildNamespaceKindStr) .build(); } - return *OptBuildNamespaceKind; } -namespace { - +// Provided for consistency with respect to rest of the codebase. llvm::StringRef buildNamespaceKindToJSON(BuildNamespaceKind BNK) { - return toString(BNK); + return buildNamespaceKindToString(BNK); } } // namespace @@ -275,10 +274,11 @@ JSONFormat::buildNamespaceFromJSON(const Object &BuildNamespaceObject) const { } auto ExpectedKind = buildNamespaceKindFromJSON(*OptBuildNamespaceKindStr); - if (!ExpectedKind) + if (!ExpectedKind) { return ErrorBuilder::wrap(ExpectedKind.takeError()) .context(ErrorMessages::ReadingFromField, "BuildNamespaceKind", "kind") .build(); + } auto OptNameStr = BuildNamespaceObject.getString("name"); if (!OptNameStr) { @@ -401,27 +401,21 @@ Object JSONFormat::entityNameToJSON(const EntityName &EN) const { namespace { -std::optional<EntityLinkage::LinkageType> -parseEntityLinkageType(llvm::StringRef S) { - if (S == "none") - return EntityLinkage::LinkageType::None; - if (S ... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/183390 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
