https://github.com/unterumarmung updated https://github.com/llvm/llvm-project/pull/189743
>From ed96c2be0eef30ed0ae2f47a181717e6490a9cbc Mon Sep 17 00:00:00 2001 From: Daniil Dudkin <[email protected]> Date: Mon, 14 Sep 2026 20:55:19 +0300 Subject: [PATCH] [clang-tidy] Add modernize-use-if-consteval check --- .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 3 + .../modernize/UseIfConstevalCheck.cpp | 147 ++++++++ .../modernize/UseIfConstevalCheck.h | 36 ++ clang-tools-extra/docs/ReleaseNotes.md | 6 + .../docs/clang-tidy/checks/list.md | 1 + .../checks/modernize/use-if-consteval.md | 26 ++ .../checkers/modernize/use-if-consteval.cpp | 313 ++++++++++++++++++ 8 files changed, 533 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-if-consteval.md create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index 23aeb393ad016..3972ea8436e91 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -39,6 +39,7 @@ add_clang_library(clangTidyModernizeModule STATIC UseEmplaceCheck.cpp UseEqualsDefaultCheck.cpp UseEqualsDeleteCheck.cpp + UseIfConstevalCheck.cpp UseIntegerSignComparisonCheck.cpp UseNodiscardCheck.cpp UseNoexceptCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index 62676469aefe7..7368e83b709f5 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -39,6 +39,7 @@ #include "UseEmplaceCheck.h" #include "UseEqualsDefaultCheck.h" #include "UseEqualsDeleteCheck.h" +#include "UseIfConstevalCheck.h" #include "UseIntegerSignComparisonCheck.h" #include "UseNodiscardCheck.h" #include "UseNoexceptCheck.h" @@ -91,6 +92,8 @@ class ModernizeModule : public ClangTidyModule { CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value"); CheckFactories.registerCheck<UseDesignatedInitializersCheck>( "modernize-use-designated-initializers"); + CheckFactories.registerCheck<UseIfConstevalCheck>( + "modernize-use-if-consteval"); CheckFactories.registerCheck<UseIntegerSignComparisonCheck>( "modernize-use-integer-sign-comparison"); CheckFactories.registerCheck<UseRangesCheck>("modernize-use-ranges"); diff --git a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp new file mode 100644 index 0000000000000..6b0d97d31fd66 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp @@ -0,0 +1,147 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "UseIfConstevalCheck.h" + +#include "../utils/BracesAroundStatement.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +struct BraceFix { + bool NeedsBraces = false; + utils::BraceInsertionHints Hints; +}; + +} // namespace + +static std::optional<SourceRange> getHeaderRange(const IfStmt *If, + const SourceManager &SM, + const LangOptions &LangOpts) { + if (If->getLParenLoc().isMacroID() || If->getRParenLoc().isMacroID()) + return std::nullopt; + + const SourceRange HeaderRange(If->getLParenLoc(), If->getRParenLoc()); + // Validate that the token range is safely rewriteable in file source before + // offering a fix-it. + if (Lexer::makeFileCharRange(CharSourceRange::getTokenRange(HeaderRange), SM, + LangOpts) + .isInvalid()) + return std::nullopt; + return HeaderRange; +} + +static std::optional<BraceFix> +getBraceFix(const Stmt *S, const LangOptions &LangOpts, const SourceManager &SM, + SourceLocation StartLoc, + SourceLocation EndLocHint = SourceLocation()) { + if (S) + S = S->stripLabelLikeStatements(); + if (!S || isa<CompoundStmt>(S)) + return BraceFix(); + + const auto Hints = + utils::getBraceInsertionsHints(S, LangOpts, SM, StartLoc, EndLocHint); + if (!Hints || !Hints.offersFixIts()) + return std::nullopt; + + return BraceFix{true, Hints}; +} + +static bool needsLeadingSpaceBeforeConsteval(SourceLocation LParenLoc, + const SourceManager &SM) { + bool Invalid = false; + const char *LParen = SM.getCharacterData(LParenLoc, &Invalid); + return Invalid || !isWhitespace(LParen[-1]); +} + +void UseIfConstevalCheck::registerMatchers(MatchFinder *Finder) { + const auto IsConstantEvaluatedCall = + callExpr(callee(functionDecl(hasName("is_constant_evaluated"), + isInStdNamespace()))) + .bind("call"); + const auto IsNegatedConstantEvaluatedExpr = + unaryOperator(hasOperatorName("!"), + hasUnaryOperand(ignoringParens(IsConstantEvaluatedCall))) + .bind("negation"); + const auto IsConstantEvaluatedExpr = ignoringParenImpCasts( + anyOf(IsConstantEvaluatedCall, IsNegatedConstantEvaluatedExpr)); + + Finder->addMatcher( + ifStmt(unless(isConstexpr()), + anyOf(hasCondition(IsConstantEvaluatedExpr), + hasConditionVariableStatement(declStmt(hasSingleDecl( + varDecl(hasInitializer(IsConstantEvaluatedExpr))))))) + .bind("if"), + this); +} + +void UseIfConstevalCheck::check(const MatchFinder::MatchResult &Result) { + const auto *If = Result.Nodes.getNodeAs<IfStmt>("if"); + const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call"); + assert(If && Call && "expected to match an if statement and its call"); + + const bool IsNegated = Result.Nodes.getNodeAs<UnaryOperator>("negation"); + const llvm::StringRef ConstevalClause = + IsNegated ? "!consteval" : "consteval"; + const SourceLocation DiagLoc = + Result.SourceManager->getExpansionLoc(Call->getExprLoc()); + + auto Diag = diag(DiagLoc, "use 'if %0' instead of checking " + "'std::is_constant_evaluated()'") + << ConstevalClause; + + if (If->hasInitStorage() || If->hasVarStorage()) + return; + + std::optional<SourceRange> HeaderRange = + getHeaderRange(If, *Result.SourceManager, getLangOpts()); + if (!HeaderRange) + return; + + std::optional<BraceFix> ThenBraceFix = + getBraceFix(If->getThen(), getLangOpts(), *Result.SourceManager, + If->getRParenLoc(), If->getElseLoc()); + if (!ThenBraceFix) + return; + + std::optional<BraceFix> ElseBraceFix = BraceFix(); + if (If->getElse()) { + ElseBraceFix = getBraceFix(If->getElse(), getLangOpts(), + *Result.SourceManager, If->getElseLoc()); + } + if (!ElseBraceFix) + return; + + const bool NeedsLeadingSpace = needsLeadingSpaceBeforeConsteval( + If->getLParenLoc(), *Result.SourceManager); + const std::string HeaderReplacement = [&] { + std::string Replacement = ConstevalClause.str(); + if (NeedsLeadingSpace) + Replacement.insert(0, 1, ' '); + if (ThenBraceFix->NeedsBraces) + Replacement += " {"; + return Replacement; + }(); + Diag << FixItHint::CreateReplacement(*HeaderRange, HeaderReplacement); + + if (ThenBraceFix->NeedsBraces) + Diag << ThenBraceFix->Hints.closingBraceFixIt(); + + if (ElseBraceFix && ElseBraceFix->NeedsBraces) + Diag << ElseBraceFix->Hints.openingBraceFixIt() + << ElseBraceFix->Hints.closingBraceFixIt(); +} + +} // namespace clang::tidy::modernize diff --git a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.h b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.h new file mode 100644 index 0000000000000..a87c9e6c5c8df --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEIFCONSTEVALCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEIFCONSTEVALCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::modernize { + +/// Use if consteval instead of std::is_constant_evaluated in if statements. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-if-consteval.html +class UseIfConstevalCheck : public ClangTidyCheck { +public: + UseIfConstevalCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus23; + } + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::modernize + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEIFCONSTEVALCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md index f523c7b4dc4a9..b258df9e91998 100644 --- a/clang-tools-extra/docs/ReleaseNotes.md +++ b/clang-tools-extra/docs/ReleaseNotes.md @@ -132,6 +132,12 @@ infrastructure are described first, followed by tool-specific sections. Finds casts from a scoped enumeration (`enum class`) to an integer type and replaces them with a call to `std::to_underlying` (introduced in C++23). +- New {doc}`modernize-use-if-consteval + <clang-tidy/checks/modernize/use-if-consteval>` check. + + Replaces direct `std::is_constant_evaluated()` checks in `if` statements + with C++23's `if consteval` syntax. + - New {doc}`performance-expensive-value-or <clang-tidy/checks/performance/expensive-value-or>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md index ea6f13365e206..f51fa3a4fe03e 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.md +++ b/clang-tools-extra/docs/clang-tidy/checks/list.md @@ -320,6 +320,7 @@ readability/* | {doc}`modernize-use-emplace <modernize/use-emplace>` | Yes | | {doc}`modernize-use-equals-default <modernize/use-equals-default>` | Yes | | {doc}`modernize-use-equals-delete <modernize/use-equals-delete>` | Yes | +| {doc}`modernize-use-if-consteval <modernize/use-if-consteval>` | Yes | | {doc}`modernize-use-integer-sign-comparison <modernize/use-integer-sign-comparison>` | Yes | | {doc}`modernize-use-nodiscard <modernize/use-nodiscard>` | Yes | | {doc}`modernize-use-noexcept <modernize/use-noexcept>` | Yes | diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-if-consteval.md b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-if-consteval.md new file mode 100644 index 0000000000000..d4b73d7fdb01d --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-if-consteval.md @@ -0,0 +1,26 @@ +```{title} clang-tidy - modernize-use-if-consteval +``` + +# modernize-use-if-consteval + +Replaces direct `std::is_constant_evaluated()` checks in `if` statements with +C++23's `if consteval` syntax. + +```cpp +if (std::is_constant_evaluated()) + return slow_but_constexpr_path(); +else + return fast_runtime_path(); +``` + +is rewritten as: + +```cpp +if consteval { + return slow_but_constexpr_path(); +} else { + return fast_runtime_path(); +} +``` + +The direct negated form is rewritten to `if !consteval`. diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp new file mode 100644 index 0000000000000..5a6000ebc03b7 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp @@ -0,0 +1,313 @@ +// RUN: %check_clang_tidy -std=c++23-or-later %s modernize-use-if-consteval %t + +namespace std { +constexpr bool is_constant_evaluated() noexcept { + return true; +} +} // namespace std + +namespace mine { +constexpr bool is_constant_evaluated() noexcept { + return __builtin_is_constant_evaluated(); +} +} // namespace mine + +namespace alias = std; + +#define ICE_CALL() std::is_constant_evaluated() +#define IF_ICE_HEADER if (std::is_constant_evaluated()) +#define IF_ONLY if +#define RETURN_ONE() return 1; +#define RETURN_THREE() return 3; + +bool runtime_predicate(); + +int direct() { + if (std::is_constant_evaluated()) + return 1; + else + return 2; + // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval] + // CHECK-FIXES: if consteval { + // CHECK-FIXES-NEXT: return 1; + // CHECK-FIXES-NEXT: } else { + // CHECK-FIXES-NEXT: return 2; + // CHECK-FIXES-NEXT: } +} + +int direct_global() { + if (::std::is_constant_evaluated()) { + return 1; + } + return 2; + // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { +} + +int compact_spacing() { + if(std::is_constant_evaluated()) { + return 1; + } + return 2; + // CHECK-MESSAGES: :[[@LINE-4]]:6: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { +} + +int using_decl() { + using std::is_constant_evaluated; + if (is_constant_evaluated()) { + return 1; + } + return 2; + // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { +} + +int using_namespace() { + using namespace std; + if (is_constant_evaluated()) { + return 1; + } + return 2; + // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { +} + +int namespace_alias() { + if (alias::is_constant_evaluated()) { + return 1; + } + return 2; + // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { +} + +int negated() { + if (!std::is_constant_evaluated()) + return 1; + return 2; + // CHECK-MESSAGES: :[[@LINE-3]]:8: warning: use 'if !consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if !consteval { + // CHECK-FIXES-NEXT: return 1; + // CHECK-FIXES-NEXT: } + // CHECK-FIXES-NEXT: return 2; +} + +int negated_alternative_token() { + if (not std::is_constant_evaluated()) + return 1; + return 2; + // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use 'if !consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if !consteval { + // CHECK-FIXES-NEXT: return 1; + // CHECK-FIXES-NEXT: } + // CHECK-FIXES-NEXT: return 2; +} + +int extra_parens() { + if ((((std::is_constant_evaluated())))) { + return 1; + } + return 2; + // CHECK-MESSAGES: :[[@LINE-4]]:10: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { +} + +template <typename T> +int templated() { + if (std::is_constant_evaluated()) { + return sizeof(T); + } + return 0; + // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { +} + +template int templated<int>(); +template int templated<long>(); + +auto Lambda = [] { + if (std::is_constant_evaluated()) + return 1; + return 2; + // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { + // CHECK-FIXES-NEXT: return 1; + // CHECK-FIXES-NEXT: } + // CHECK-FIXES-NEXT: return 2; +}; + +int attributed_then() { + if (std::is_constant_evaluated()) + [[likely]] return 1; + return 0; + // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { + // CHECK-FIXES-NEXT: {{[[][[]}}likely{{[]][]]}} return 1; + // CHECK-FIXES-NEXT: } + // CHECK-FIXES-NEXT: return 0; +} + +int labeled_then() { + if (std::is_constant_evaluated()) + labeled_then: + return 1; + return 0; + // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { + // CHECK-FIXES-NEXT: labeled_then: + // CHECK-FIXES-NEXT: return 1; + // CHECK-FIXES-NEXT: } + // CHECK-FIXES-NEXT: return 0; +} + +int else_if_chain(int Value) { + if (Value == 0) + return 0; + else if (std::is_constant_evaluated()) + return 1; + else + return 2; + // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: else if consteval { + // CHECK-FIXES-NEXT: return 1; + // CHECK-FIXES-NEXT: } else { + // CHECK-FIXES-NEXT: return 2; + // CHECK-FIXES-NEXT: } +} + +int outer_else_if() { + if (std::is_constant_evaluated()) + return 1; + else if (runtime_predicate()) + return 2; + return 0; + // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { + // CHECK-FIXES-NEXT: return 1; + // CHECK-FIXES-NEXT: } else { if (runtime_predicate()) + // CHECK-FIXES-NEXT: return 2; + // CHECK-FIXES-NEXT: } + // CHECK-FIXES-NEXT: return 0; +} + +int macro_header_safe() { + if (ICE_CALL()) { + return 1; + } else { + return 2; + } + // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if consteval { +} + +int with_init() { + if (int X = 0; std::is_constant_evaluated()) { + return X + 1; + } + return 0; + // CHECK-MESSAGES: :[[@LINE-4]]:18: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if (int X = 0; std::is_constant_evaluated()) { +} + +int with_condition_variable() { + if (bool B = std::is_constant_evaluated()) + return B ? 1 : 2; + else + return 3; + // CHECK-MESSAGES: :[[@LINE-4]]:16: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if (bool B = std::is_constant_evaluated()) + // CHECK-FIXES-NEXT: return B ? 1 : 2; + // CHECK-FIXES-NEXT: else + // CHECK-FIXES-NEXT: return 3; +} + +int macro_header_unsafe() { + IF_ICE_HEADER { + return 1; + } + return 0; + // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: IF_ICE_HEADER { +} + +int macro_if_token_unsafe() { + IF_ONLY (std::is_constant_evaluated()) { + return 1; + } + return 0; + // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: IF_ONLY consteval { +} + +int macro_body_unsafe() { + if (std::is_constant_evaluated()) + RETURN_ONE() + return 2; + // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if (std::is_constant_evaluated()) + // CHECK-FIXES-NEXT: RETURN_ONE() + // CHECK-FIXES-NEXT: return 2; +} + +int macro_else_unsafe() { + if (std::is_constant_evaluated()) + return 1; + else + RETURN_THREE() + return 4; + // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' + // CHECK-FIXES: if (std::is_constant_evaluated()) + // CHECK-FIXES-NEXT: return 1; + // CHECK-FIXES-NEXT: else + // CHECK-FIXES-NEXT: RETURN_THREE() + // CHECK-FIXES-NEXT: return 4; +} + +int not_std() { + if (mine::is_constant_evaluated()) { + return 1; + } + return 0; +} + +int composite_conditions() { + if (std::is_constant_evaluated() && runtime_predicate()) { + return 1; + } + if (!!std::is_constant_evaluated()) { + return 2; + } + return 0; +} + +int if_constexpr() { + if constexpr (std::is_constant_evaluated()) { + return 1; + } + return 2; +} + +int already_if_consteval() { + if consteval { + return 1; + } else { + return 2; + } +} + +int already_if_not_consteval() { + if !consteval { + return 1; + } else { + return 2; + } +} + +template <typename T> +concept HasICE = requires { + std::is_constant_evaluated(); +}; + +using ICEPtr = decltype(std::is_constant_evaluated()) *; +ICEPtr Ptr = nullptr; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
