[clang-tools-extra] 0eb7d53 - [clang-tidy] add modernize-use-std-numbers (#66583)

Piotr Zegar via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 6 12:51:01 PST 2023


Author: Julian Schmidt
Date: 2023-12-06T20:49:14Z
New Revision: 0eb7d53cfc48f2e9287bb116415620618ca850b7

URL: https://github.com/llvm/llvm-project/commit/0eb7d53cfc48f2e9287bb116415620618ca850b7
DIFF: https://github.com/llvm/llvm-project/commit/0eb7d53cfc48f2e9287bb116415620618ca850b7.diff

LOG: [clang-tidy] add modernize-use-std-numbers (#66583)

Finds constants and function calls to math functions that can be
replaced with c++20's mathematical constants from the 'numbers' 
header and offers fix-it hints.
Does not match the use of variables with that value, and instead,
offers a replacement at the definition of those variables.

Added: 
    clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
    clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h
    clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst
    clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp

Modified: 
    clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
    clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/list.rst

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c40065358d2dc..28ca52f46943a 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
   UseNullptrCheck.cpp
   UseOverrideCheck.cpp
   UseStartsEndsWithCheck.cpp
+  UseStdNumbersCheck.cpp
   UseStdPrintCheck.cpp
   UseTrailingReturnTypeCheck.cpp
   UseTransparentFunctorsCheck.cpp

diff  --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index e994ffd2a75c8..654f4bd0c6ba4 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -40,6 +40,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseStartsEndsWithCheck.h"
+#include "UseStdNumbersCheck.h"
 #include "UseStdPrintCheck.h"
 #include "UseTrailingReturnTypeCheck.h"
 #include "UseTransparentFunctorsCheck.h"
@@ -69,6 +70,8 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
     CheckFactories.registerCheck<UseStartsEndsWithCheck>(
         "modernize-use-starts-ends-with");
+    CheckFactories.registerCheck<UseStdNumbersCheck>(
+        "modernize-use-std-numbers");
     CheckFactories.registerCheck<UseStdPrintCheck>("modernize-use-std-print");
     CheckFactories.registerCheck<RawStringLiteralCheck>(
         "modernize-raw-string-literal");

diff  --git a/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
new file mode 100644
index 0000000000000..1f2b034713ecf
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
@@ -0,0 +1,449 @@
+//===--- UseStdNumbersCheck.cpp - clang_tidy ------------------------------===//
+//
+// 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 "UseStdNumbersCheck.h"
+#include "../ClangTidyDiagnosticConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include <array>
+#include <cstdint>
+#include <cstdlib>
+#include <initializer_list>
+#include <string>
+#include <tuple>
+#include <utility>
+
+namespace {
+using namespace clang::ast_matchers;
+using clang::ast_matchers::internal::Matcher;
+using llvm::StringRef;
+
+AST_MATCHER_P2(clang::FloatingLiteral, near, double, Value, double,
+               DiffThreshold) {
+  return std::abs(Node.getValueAsApproximateDouble() - Value) < DiffThreshold;
+}
+
+AST_MATCHER_P(clang::QualType, hasCanonicalTypeUnqualified,
+              Matcher<clang::QualType>, InnerMatcher) {
+  return !Node.isNull() &&
+         InnerMatcher.matches(Node->getCanonicalTypeUnqualified(), Finder,
+                              Builder);
+}
+
+AST_MATCHER(clang::QualType, isArithmetic) {
+  return !Node.isNull() && Node->isArithmeticType();
+}
+AST_MATCHER(clang::QualType, isFloating) {
+  return !Node.isNull() && Node->isFloatingType();
+}
+
+AST_MATCHER_P(clang::Expr, anyOfExhaustive,
+              llvm::ArrayRef<Matcher<clang::Stmt>>, Exprs) {
+  bool FoundMatch = false;
+  for (const auto &InnerMatcher : Exprs) {
+    clang::ast_matchers::internal::BoundNodesTreeBuilder Result = *Builder;
+    if (InnerMatcher.matches(Node, Finder, &Result)) {
+      *Builder = std::move(Result);
+      FoundMatch = true;
+    }
+  }
+  return FoundMatch;
+}
+
+// Using this struct to store the 'DiffThreshold' config value to create the
+// matchers without the need to pass 'DiffThreshold' into every matcher.
+// 'DiffThreshold' is needed in the 'near' matcher, which is used for matching
+// the literal of every constant and for formulas' subexpressions that look at
+// literals.
+struct MatchBuilder {
+  auto
+  ignoreParenAndArithmeticCasting(const Matcher<clang::Expr> Matcher) const {
+    return expr(hasType(qualType(isArithmetic())), ignoringParenCasts(Matcher));
+  }
+
+  auto ignoreParenAndFloatingCasting(const Matcher<clang::Expr> Matcher) const {
+    return expr(hasType(qualType(isFloating())), ignoringParenCasts(Matcher));
+  }
+
+  auto matchMathCall(const StringRef FunctionName,
+                     const Matcher<clang::Expr> ArgumentMatcher) const {
+    return expr(ignoreParenAndFloatingCasting(
+        callExpr(callee(functionDecl(hasName(FunctionName),
+                                     hasParameter(0, hasType(isArithmetic())))),
+                 hasArgument(0, ArgumentMatcher))));
+  }
+
+  auto matchSqrt(const Matcher<clang::Expr> ArgumentMatcher) const {
+    return matchMathCall("sqrt", ArgumentMatcher);
+  }
+
+  // Used for top-level matchers (i.e. the match that replaces Val with its
+  // constant).
+  //
+  // E.g. The matcher of `std::numbers::pi` uses this matcher to look for
+  // floatLiterals that have the value of pi.
+  //
+  // If the match is for a top-level match, we only care about the literal.
+  auto matchFloatLiteralNear(const StringRef Constant, const double Val) const {
+    return expr(ignoreParenAndFloatingCasting(
+        floatLiteral(near(Val, DiffThreshold)).bind(Constant)));
+  }
+
+  // Used for non-top-level matchers (i.e. matchers that are used as inner
+  // matchers for top-level matchers).
+  //
+  // E.g.: The matcher of `std::numbers::log2e` uses this matcher to check if
+  // `e` of `log2(e)` is declared constant and initialized with the value for
+  // eulers number.
+  //
+  // Here, we do care about literals and about DeclRefExprs to variable
+  // declarations that are constant and initialized with `Val`. This allows
+  // top-level matchers to see through declared constants for their inner
+  // matches like the `std::numbers::log2e` matcher.
+  auto matchFloatValueNear(const double Val) const {
+    const auto Float = floatLiteral(near(Val, DiffThreshold));
+
+    const auto Dref = declRefExpr(
+        to(varDecl(hasType(qualType(isConstQualified(), isFloating())),
+                   hasInitializer(ignoreParenAndFloatingCasting(Float)))));
+    return expr(ignoreParenAndFloatingCasting(anyOf(Float, Dref)));
+  }
+
+  auto matchValue(const int64_t ValInt) const {
+    const auto Int =
+        expr(ignoreParenAndArithmeticCasting(integerLiteral(equals(ValInt))));
+    const auto Float = expr(ignoreParenAndFloatingCasting(
+        matchFloatValueNear(static_cast<double>(ValInt))));
+    const auto Dref = declRefExpr(to(varDecl(
+        hasType(qualType(isConstQualified(), isArithmetic())),
+        hasInitializer(expr(anyOf(ignoringImplicit(Int),
+                                  ignoreParenAndFloatingCasting(Float)))))));
+    return expr(anyOf(Int, Float, Dref));
+  }
+
+  auto match1Div(const Matcher<clang::Expr> Match) const {
+    return binaryOperator(hasOperatorName("/"), hasLHS(matchValue(1)),
+                          hasRHS(Match));
+  }
+
+  auto matchEuler() const {
+    return expr(anyOf(matchFloatValueNear(llvm::numbers::e),
+                      matchMathCall("exp", matchValue(1))));
+  }
+  auto matchEulerTopLevel() const {
+    return expr(anyOf(matchFloatLiteralNear("e_literal", llvm::numbers::e),
+                      matchMathCall("exp", matchValue(1)).bind("e_pattern")))
+        .bind("e");
+  }
+
+  auto matchLog2Euler() const {
+    return expr(
+               anyOf(
+                   matchFloatLiteralNear("log2e_literal", llvm::numbers::log2e),
+                   matchMathCall("log2", matchEuler()).bind("log2e_pattern")))
+        .bind("log2e");
+  }
+
+  auto matchLog10Euler() const {
+    return expr(
+               anyOf(
+                   matchFloatLiteralNear("log10e_literal",
+                                         llvm::numbers::log10e),
+                   matchMathCall("log10", matchEuler()).bind("log10e_pattern")))
+        .bind("log10e");
+  }
+
+  auto matchPi() const { return matchFloatValueNear(llvm::numbers::pi); }
+  auto matchPiTopLevel() const {
+    return matchFloatLiteralNear("pi_literal", llvm::numbers::pi).bind("pi");
+  }
+
+  auto matchEgamma() const {
+    return matchFloatLiteralNear("egamma_literal", llvm::numbers::egamma)
+        .bind("egamma");
+  }
+
+  auto matchInvPi() const {
+    return expr(anyOf(matchFloatLiteralNear("inv_pi_literal",
+                                            llvm::numbers::inv_pi),
+                      match1Div(matchPi()).bind("inv_pi_pattern")))
+        .bind("inv_pi");
+  }
+
+  auto matchInvSqrtPi() const {
+    return expr(anyOf(
+                    matchFloatLiteralNear("inv_sqrtpi_literal",
+                                          llvm::numbers::inv_sqrtpi),
+                    match1Div(matchSqrt(matchPi())).bind("inv_sqrtpi_pattern")))
+        .bind("inv_sqrtpi");
+  }
+
+  auto matchLn2() const {
+    return expr(anyOf(matchFloatLiteralNear("ln2_literal", llvm::numbers::ln2),
+                      matchMathCall("log", matchValue(2)).bind("ln2_pattern")))
+        .bind("ln2");
+  }
+
+  auto machterLn10() const {
+    return expr(
+               anyOf(matchFloatLiteralNear("ln10_literal", llvm::numbers::ln10),
+                     matchMathCall("log", matchValue(10)).bind("ln10_pattern")))
+        .bind("ln10");
+  }
+
+  auto matchSqrt2() const {
+    return expr(anyOf(matchFloatLiteralNear("sqrt2_literal",
+                                            llvm::numbers::sqrt2),
+                      matchSqrt(matchValue(2)).bind("sqrt2_pattern")))
+        .bind("sqrt2");
+  }
+
+  auto matchSqrt3() const {
+    return expr(anyOf(matchFloatLiteralNear("sqrt3_literal",
+                                            llvm::numbers::sqrt3),
+                      matchSqrt(matchValue(3)).bind("sqrt3_pattern")))
+        .bind("sqrt3");
+  }
+
+  auto matchInvSqrt3() const {
+    return expr(anyOf(matchFloatLiteralNear("inv_sqrt3_literal",
+                                            llvm::numbers::inv_sqrt3),
+                      match1Div(matchSqrt(matchValue(3)))
+                          .bind("inv_sqrt3_pattern")))
+        .bind("inv_sqrt3");
+  }
+
+  auto matchPhi() const {
+    const auto PhiFormula = binaryOperator(
+        hasOperatorName("/"),
+        hasLHS(binaryOperator(
+            hasOperatorName("+"), hasEitherOperand(matchValue(1)),
+            hasEitherOperand(matchMathCall("sqrt", matchValue(5))))),
+        hasRHS(matchValue(2)));
+    return expr(anyOf(PhiFormula.bind("phi_pattern"),
+                      matchFloatLiteralNear("phi_literal", llvm::numbers::phi)))
+        .bind("phi");
+  }
+
+  double DiffThreshold;
+};
+
+std::string getCode(const StringRef Constant, const bool IsFloat,
+                    const bool IsLongDouble) {
+  if (IsFloat) {
+    return ("std::numbers::" + Constant + "_v<float>").str();
+  }
+  if (IsLongDouble) {
+    return ("std::numbers::" + Constant + "_v<long double>").str();
+  }
+  return ("std::numbers::" + Constant).str();
+}
+
+bool isRangeOfCompleteMacro(const clang::SourceRange &Range,
+                            const clang::SourceManager &SM,
+                            const clang::LangOptions &LO) {
+  if (!Range.getBegin().isMacroID()) {
+    return false;
+  }
+  if (!clang::Lexer::isAtStartOfMacroExpansion(Range.getBegin(), SM, LO)) {
+    return false;
+  }
+
+  if (!Range.getEnd().isMacroID()) {
+    return false;
+  }
+
+  if (!clang::Lexer::isAtEndOfMacroExpansion(Range.getEnd(), SM, LO)) {
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace
+
+namespace clang::tidy::modernize {
+UseStdNumbersCheck::UseStdNumbersCheck(const StringRef Name,
+                                       ClangTidyContext *const Context)
+    : ClangTidyCheck(Name, Context),
+      IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+                                               utils::IncludeSorter::IS_LLVM),
+                      areDiagsSelfContained()),
+      DiffThresholdString{Options.get("DiffThreshold", "0.001")} {
+  if (DiffThresholdString.getAsDouble(DiffThreshold)) {
+    configurationDiag(
+        "Invalid DiffThreshold config value: '%0', expected a double")
+        << DiffThresholdString;
+    DiffThreshold = 0.001;
+  }
+}
+
+void UseStdNumbersCheck::registerMatchers(MatchFinder *const Finder) {
+  const auto Matches = MatchBuilder{DiffThreshold};
+  static const auto ConstantMatchers = {
+      Matches.matchLog2Euler(),     Matches.matchLog10Euler(),
+      Matches.matchEulerTopLevel(), Matches.matchEgamma(),
+      Matches.matchInvSqrtPi(),     Matches.matchInvPi(),
+      Matches.matchPiTopLevel(),    Matches.matchLn2(),
+      Matches.machterLn10(),        Matches.matchSqrt2(),
+      Matches.matchInvSqrt3(),      Matches.matchSqrt3(),
+      Matches.matchPhi(),
+  };
+
+  Finder->addMatcher(
+      expr(
+          anyOfExhaustive(ConstantMatchers),
+          unless(hasParent(explicitCastExpr(hasDestinationType(isFloating())))),
+          hasType(qualType(hasCanonicalTypeUnqualified(
+              anyOf(qualType(asString("float")).bind("float"),
+                    qualType(asString("double")),
+                    qualType(asString("long double")).bind("long double")))))),
+      this);
+}
+
+void UseStdNumbersCheck::check(const MatchFinder::MatchResult &Result) {
+  /*
+    List of all math constants in the `<numbers>` header
+    + e
+    + log2e
+    + log10e
+    + pi
+    + inv_pi
+    + inv_sqrtpi
+    + ln2
+    + ln10
+    + sqrt2
+    + sqrt3
+    + inv_sqrt3
+    + egamma
+    + phi
+  */
+
+  // The ordering determines what constants are looked at first.
+  // E.g. look at 'inv_sqrt3' before 'sqrt3' to be able to replace the larger
+  // expression
+  constexpr auto Constants = std::array<std::pair<StringRef, double>, 13>{
+      std::pair{StringRef{"log2e"}, llvm::numbers::log2e},
+      std::pair{StringRef{"log10e"}, llvm::numbers::log10e},
+      std::pair{StringRef{"e"}, llvm::numbers::e},
+      std::pair{StringRef{"egamma"}, llvm::numbers::egamma},
+      std::pair{StringRef{"inv_sqrtpi"}, llvm::numbers::inv_sqrtpi},
+      std::pair{StringRef{"inv_pi"}, llvm::numbers::inv_pi},
+      std::pair{StringRef{"pi"}, llvm::numbers::pi},
+      std::pair{StringRef{"ln2"}, llvm::numbers::ln2},
+      std::pair{StringRef{"ln10"}, llvm::numbers::ln10},
+      std::pair{StringRef{"sqrt2"}, llvm::numbers::sqrt2},
+      std::pair{StringRef{"inv_sqrt3"}, llvm::numbers::inv_sqrt3},
+      std::pair{StringRef{"sqrt3"}, llvm::numbers::sqrt3},
+      std::pair{StringRef{"phi"}, llvm::numbers::phi},
+  };
+
+  auto MatchedLiterals =
+      llvm::SmallVector<std::tuple<std::string, double, const Expr *>>{};
+
+  const auto &SM = *Result.SourceManager;
+  const auto &LO = Result.Context->getLangOpts();
+
+  const auto IsFloat = Result.Nodes.getNodeAs<QualType>("float") != nullptr;
+  const auto IsLongDouble =
+      Result.Nodes.getNodeAs<QualType>("long double") != nullptr;
+
+  for (const auto &[ConstantName, ConstantValue] : Constants) {
+    const auto *const Match = Result.Nodes.getNodeAs<Expr>(ConstantName);
+    if (Match == nullptr) {
+      continue;
+    }
+
+    const auto Range = Match->getSourceRange();
+
+    const auto IsMacro = Range.getBegin().isMacroID();
+
+    // We do not want to emit a diagnostic when we are matching a macro, but the
+    // match inside of the macro does not cover the whole macro.
+    if (IsMacro && !isRangeOfCompleteMacro(Range, SM, LO)) {
+      continue;
+    }
+
+    if (const auto PatternBindString = (ConstantName + "_pattern").str();
+        Result.Nodes.getNodeAs<Expr>(PatternBindString) != nullptr) {
+      const auto Code = getCode(ConstantName, IsFloat, IsLongDouble);
+      diag(Range.getBegin(), "prefer '%0' to this %select{formula|macro}1")
+          << Code << IsMacro << FixItHint::CreateReplacement(Range, Code);
+      return;
+    }
+
+    const auto LiteralBindString = (ConstantName + "_literal").str();
+    if (const auto *const Literal =
+            Result.Nodes.getNodeAs<FloatingLiteral>(LiteralBindString)) {
+      MatchedLiterals.emplace_back(
+          ConstantName,
+          std::abs(Literal->getValueAsApproximateDouble() - ConstantValue),
+          Match);
+    }
+  }
+
+  // We may have had no matches with literals, but a match with a pattern that
+  // was a part of a macro which was therefore skipped.
+  if (MatchedLiterals.empty()) {
+    return;
+  }
+
+  llvm::sort(MatchedLiterals, [](const auto &LHS, const auto &RHS) {
+    return std::get<1>(LHS) < std::get<1>(RHS);
+  });
+
+  const auto &[Constant, Diff, Node] = MatchedLiterals.front();
+
+  const auto Range = Node->getSourceRange();
+  const auto IsMacro = Range.getBegin().isMacroID();
+
+  // We do not want to emit a diagnostic when we are matching a macro, but the
+  // match inside of the macro does not cover the whole macro.
+  if (IsMacro && !isRangeOfCompleteMacro(Range, SM, LO)) {
+    return;
+  }
+
+  const auto Code = getCode(Constant, IsFloat, IsLongDouble);
+  diag(Range.getBegin(),
+       "prefer '%0' to this %select{literal|macro}1, 
diff ers by '%2'")
+      << Code << IsMacro << llvm::formatv("{0:e2}", Diff).str()
+      << FixItHint::CreateReplacement(Range, Code)
+      << IncludeInserter.createIncludeInsertion(
+             Result.SourceManager->getFileID(Range.getBegin()), "<numbers>");
+}
+
+void UseStdNumbersCheck::registerPPCallbacks(
+    const SourceManager &SM, Preprocessor *const PP,
+    Preprocessor *const ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdNumbersCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+  Options.store(Opts, "DiffThreshold", DiffThresholdString);
+}
+} // namespace clang::tidy::modernize

diff  --git a/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h
new file mode 100644
index 0000000000000..05fc5ada14b87
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h
@@ -0,0 +1,49 @@
+//===--- UseStdNumbersCheck.h - clang-tidy ----------------------*- C++ -*-===//
+//
+// 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_USESTDNUMBERSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDNUMBERSCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang::tidy::modernize {
+
+/// Finds constants and function calls to math functions that can be replaced
+/// with c++20's mathematical constants from the ``numbers`` header and
+/// offers fix-it hints.
+/// Does not match the use of variables with that value, and instead,
+/// offers a replacement at the definition of those variables.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-numbers.html
+class UseStdNumbersCheck : public ClangTidyCheck {
+public:
+  UseStdNumbersCheck(StringRef Name, ClangTidyContext *Context);
+
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus20;
+  }
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                           Preprocessor *ModuleExpanderPP) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+private:
+  utils::IncludeInserter IncludeInserter;
+  StringRef DiffThresholdString;
+  double DiffThreshold;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDNUMBERSCHECK_H

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 4ff4494cef562..9262f9bbfe62a 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -193,6 +193,13 @@ New checks
   replacing with ``starts_with`` when the method exists in the class. Notably,
   this will work with ``std::string`` and ``std::string_view``.
 
+- New :doc:`modernize-use-std-numbers
+  <clang-tidy/checks/modernize/use-std-numbers>` check.
+
+  Finds constants and function calls to math functions that can be replaced
+  with C++20's mathematical constants from the ``numbers`` header and
+  offers fix-it hints.
+
 - New :doc:`performance-enum-size
   <clang-tidy/checks/performance/enum-size>` check.
 

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index df2d5d15238d6..e6c02fe48fbf8 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -293,6 +293,7 @@ Clang-Tidy Checks
    :doc:`modernize-use-nullptr <modernize/use-nullptr>`, "Yes"
    :doc:`modernize-use-override <modernize/use-override>`, "Yes"
    :doc:`modernize-use-starts-ends-with <modernize/use-starts-ends-with>`, "Yes"
+   :doc:`modernize-use-std-numbers <modernize/use-std-numbers>`, "Yes"
    :doc:`modernize-use-std-print <modernize/use-std-print>`, "Yes"
    :doc:`modernize-use-trailing-return-type <modernize/use-trailing-return-type>`, "Yes"
    :doc:`modernize-use-transparent-functors <modernize/use-transparent-functors>`, "Yes"

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst
new file mode 100644
index 0000000000000..207e9c00e74ba
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst
@@ -0,0 +1,74 @@
+.. title:: clang-tidy - modernize-use-std-numbers
+
+modernize-use-std-numbers
+=========================
+
+Finds constants and function calls to math functions that can be replaced
+with C++20's mathematical constants from the ``numbers`` header and offers
+fix-it hints.
+Does not match the use of variables with that value, and instead,
+offers a replacement for the definition of those variables.
+Function calls that match the pattern of how the constant is calculated are
+matched and replaced with the ``std::numbers`` constant.
+The use of macros gets replaced with the corresponding ``std::numbers``
+constant, instead of changing the macro definition.
+
+The following list of constants from the ``numbers`` header are supported:
+
+* ``e``
+* ``log2e``
+* ``log10e``
+* ``pi``
+* ``inv_pi``
+* ``inv_sqrtpi``
+* ``ln2``
+* ``ln10``
+* ``sqrt2``
+* ``sqrt3``
+* ``inv_sqrt3``
+* ``egamma``
+* ``phi``
+
+The list currently includes all constants as of C++20.
+
+The replacements use the type of the matched constant and can remove explicit
+casts, i.e., switching between ``std::numbers::e``,
+``std::numbers::e_v<float>`` and ``std::numbers::e_v<long double>`` where
+appropriate.
+
+.. code-block:: c++
+
+    double sqrt(double);
+    double log2(double);
+    void sink(auto&&) {}
+    void floatSink(float);
+
+    #define MY_PI 3.1415926
+
+    void foo() {
+        const double Pi = 3.141592653589;           // const double Pi = std::numbers::pi
+        const auto Use = Pi / 2;                    // no match for Pi
+        static constexpr double Euler = 2.7182818;  // static constexpr double Euler = std::numbers::e;
+
+        log2(exp(1));                               // std::numbers::log2e;
+        log2(Euler);                                // std::numbers::log2e;
+        1 / sqrt(MY_PI);                            // std::numbers::inv_sqrtpi;
+        sink(MY_PI);                                // sink(std::numbers::pi);
+        floatSink(MY_PI);                           // floatSink(std::numbers::pi);
+        floatSink(static_cast<float>(MY_PI));       // floatSink(std::numbers::pi_v<float>);
+    }
+
+Options
+-------
+
+.. option:: DiffThreshold
+
+    A floating point value that sets the detection threshold for when literals
+    match a constant. A literal matches a constant if
+    ``abs(literal - constant) < DiffThreshold`` evaluates to ``true``. Default
+    is `0.001`.
+
+.. option:: IncludeStyle
+
+   A string specifying which include-style is used, `llvm` or `google`. Default
+   is `llvm`.

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp
new file mode 100644
index 0000000000000..6c5762da5e2e8
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp
@@ -0,0 +1,493 @@
+// RUN: %check_clang_tidy -check-suffix=ALL -std=c++20 %s modernize-use-std-numbers %t
+// RUN: %check_clang_tidy -check-suffix=ALL,IMPRECISE -std=c++20 %s modernize-use-std-numbers %t -- -config="{CheckOptions: { modernize-use-std-numbers.DiffThreshold: 0.01 }}"
+
+// CHECK-FIXES-ALL: #include <numbers>
+
+namespace bar {
+    double sqrt(double Arg);
+    float sqrt(float Arg);
+    template <typename T>
+    auto sqrt(T val) { return sqrt(static_cast<double>(val)); }
+
+    static constexpr double e = 2.718281828459045235360287471352662497757247093;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:33: warning: prefer 'std::numbers::e' to this literal, 
diff ers by '0.00e+00' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double e = std::numbers::e;
+}
+
+double exp(double Arg);
+double log(double Arg);
+
+double log2(double Arg);
+float log2(float Arg);
+template <typename T>
+auto log2(T val) { return log2(static_cast<double>(val)); }
+
+double log10(double Arg);
+
+template<typename T>
+void sink(T&&) { }
+
+void floatSink(float) {}
+
+#define MY_PI 3.1415926
+
+#define INV_SQRT3 1 / bar::sqrt(3)
+#define NOT_INV_SQRT3 1 / bar::sqrt(3) + 1
+
+using my_double = double;
+using my_float = float;
+
+void foo(){
+    static constexpr double Pi = 3.1415926;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:34: warning: prefer 'std::numbers::pi' to this literal, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double Pi = std::numbers::pi;
+
+    static constexpr double Euler = 2.7182818;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:37: warning: prefer 'std::numbers::e' to this literal, 
diff ers by '2.85e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double Euler = std::numbers::e;
+
+    static constexpr double Phi = 1.6180339;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:35: warning: prefer 'std::numbers::phi' to this literal, 
diff ers by '8.87e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double Phi = std::numbers::phi;
+
+    static constexpr double PiCopy = Pi;
+    static constexpr double PiDefineFromMacro = MY_PI;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:49: warning: prefer 'std::numbers::pi' to this macro, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double PiDefineFromMacro = std::numbers::pi;
+
+    static constexpr double Pi2 = 3.14;
+    // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:35: warning: prefer 'std::numbers::pi' to this literal, 
diff ers by '1.59e-03' [modernize-use-std-numbers]
+    // CHECK-FIXES-IMPRECISE: static constexpr double Pi2 = std::numbers::pi;
+    static constexpr double Euler2 = 2.71;
+    // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:38: warning: prefer 'std::numbers::e' to this literal, 
diff ers by '8.28e-03' [modernize-use-std-numbers]
+    // CHECK-FIXES-IMPRECISE: static constexpr double Euler2 = std::numbers::e;
+    static constexpr double Phi2 = 1.61;
+    // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:36: warning: prefer 'std::numbers::phi' to this literal, 
diff ers by '8.03e-03' [modernize-use-std-numbers]
+    // CHECK-FIXES-IMPRECISE: static constexpr double Phi2 = std::numbers::phi;
+
+    static constexpr double Pi3 = 3.1415926L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:35: warning: prefer 'std::numbers::pi_v<long double>' to this literal, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double Pi3 = std::numbers::pi_v<long double>;
+
+    static constexpr double Euler3 = 2.7182818L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:38: warning: prefer 'std::numbers::e_v<long double>' to this literal, 
diff ers by '2.85e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double Euler3 = std::numbers::e_v<long double>;
+
+    static constexpr double Phi3 = 1.6180339L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:36: warning: prefer 'std::numbers::phi_v<long double>' to this literal, 
diff ers by '8.87e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double Phi3 = std::numbers::phi_v<long double>;
+
+    static constexpr long double Pi4 = 3.1415926L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:40: warning: prefer 'std::numbers::pi_v<long double>' to this literal, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr long double Pi4 = std::numbers::pi_v<long double>;
+
+    static constexpr long double Euler4 = 2.7182818L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:43: warning: prefer 'std::numbers::e_v<long double>' to this literal, 
diff ers by '2.85e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr long double Euler4 = std::numbers::e_v<long double>;
+
+    static constexpr long double Phi4 = 1.6180339L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:41: warning: prefer 'std::numbers::phi_v<long double>' to this literal, 
diff ers by '8.87e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr long double Phi4 = std::numbers::phi_v<long double>;
+
+    static constexpr my_double Euler5 = 2.7182818;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:41: warning: prefer 'std::numbers::e' to this literal, 
diff ers by '2.85e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr my_double Euler5 = std::numbers::e;
+
+    static constexpr my_float Euler6 = 2.7182818;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:40: warning: prefer 'std::numbers::e' to this literal, 
diff ers by '2.85e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr my_float Euler6 = std::numbers::e;
+
+    static constexpr int NotEuler7 = 2.7182818;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:38: warning: prefer 'std::numbers::e' to this literal, 
diff ers by '2.85e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr int NotEuler7 = std::numbers::e;
+
+    static constexpr double InvPi = 1.0 / Pi;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:37: warning: prefer 'std::numbers::inv_pi'  to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr double InvPi = std::numbers::inv_pi;
+
+    static constexpr my_float Actually2MyFloat = 2;
+    bar::sqrt(Actually2MyFloat);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2_v<float>'  to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2_v<float>;
+
+    sink(MY_PI);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::pi' to this macro, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::pi);
+
+    auto X = 42.0;
+    auto Y = X * 3.14;
+    // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:18: warning: prefer 'std::numbers::pi' to this literal, 
diff ers by '1.59e-03' [modernize-use-std-numbers]
+    // CHECK-FIXES-IMPRECISE: auto Y = X * std::numbers::pi;
+
+    constexpr static auto One = 1;
+    constexpr static auto Two = 2;
+
+    bar::sqrt(2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+    bar::sqrt(Two);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+    bar::sqrt(2.0);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+    auto Not2 = 2;
+    Not2 = 42;
+    bar::sqrt(Not2);
+
+    const auto Actually2 = 2;
+    bar::sqrt(Actually2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+    exp(1);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::e;
+
+    exp(One);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::e;
+
+    exp(1.00000000000001);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::e;
+
+    log2(exp(1));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+    // CHECK-MESSAGES-ALL: :[[@LINE-2]]:10: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log2e;
+
+    log2(Euler);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log2e;
+
+    log2(bar::e);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log2e;
+
+    log2(Euler5);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log2e;
+
+    log2(Euler6);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log2e_v<float>;
+
+    log2(NotEuler7);
+
+    auto log2e = 1.4426950;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:18: warning: prefer 'std::numbers::log2e' to this literal, 
diff ers by '4.09e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: auto log2e = std::numbers::log2e;
+
+    floatSink(log2(Euler));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(std::numbers::log2e);
+
+    floatSink(static_cast<float>(log2(Euler)));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+    floatSink(1.4426950);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e' to this literal, 
diff ers by '4.09e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(std::numbers::log2e);
+
+    floatSink(static_cast<float>(1.4426950));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this literal, 
diff ers by '4.09e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+    floatSink(log2(static_cast<float>(Euler)));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+    floatSink(static_cast<float>(log2(static_cast<float>(Euler))));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+    floatSink(static_cast<float>(log2(static_cast<int>(Euler))));
+
+    floatSink(static_cast<int>(log2(static_cast<float>(Euler))));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:32: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(static_cast<int>(std::numbers::log2e_v<float>));
+
+    floatSink(1.4426950F);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this literal, 
diff ers by '1.93e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+    floatSink(static_cast<double>(1.4426950F));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e' to this literal, 
diff ers by '1.93e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(std::numbers::log2e);
+
+    floatSink(static_cast<int>(1.4426950F));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:32: warning: prefer 'std::numbers::log2e_v<float>' to this literal, 
diff ers by '1.93e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: floatSink(static_cast<int>(std::numbers::log2e_v<float>));
+
+    log10(exp(1));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+    // CHECK-MESSAGES-ALL: :[[@LINE-2]]:11: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log10e;
+
+    log10(Euler);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log10e;
+
+    log10(bar::e);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log10e;
+
+    auto log10e = .434294;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:19: warning: prefer 'std::numbers::log10e' to this literal, 
diff ers by '4.82e-07' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: auto log10e = std::numbers::log10e;
+
+    auto egamma = 0.5772156 * 42;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:19: warning: prefer 'std::numbers::egamma' to this literal, 
diff ers by '6.49e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: auto egamma = std::numbers::egamma * 42;
+
+    sink(InvPi);
+
+    sink(1 / Pi);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_pi' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::inv_pi);
+
+    sink(1 / bar::sqrt(Pi));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrtpi' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrtpi);
+
+    sink(1 / bar::sqrt(MY_PI));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrtpi' to this formula [modernize-use-std-numbers]
+    // CHECK-MESSAGES-ALL: :[[@LINE-2]]:24: warning: prefer 'std::numbers::pi' to this macro, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrtpi);
+
+    log(2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::ln2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::ln2;
+
+    log(10);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::ln10' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::ln10;
+
+    bar::sqrt(2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+    sink(1 / bar::sqrt(3));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrt3' to this formula [modernize-use-std-numbers]
+    // CHECK-MESSAGES-ALL: :[[@LINE-2]]:14: warning: prefer 'std::numbers::sqrt3' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrt3);
+
+    sink(INV_SQRT3);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrt3' to this macro [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrt3);
+
+    sink(NOT_INV_SQRT3);
+
+    const auto inv_sqrt3f = .577350269F;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:29: warning: prefer 'std::numbers::inv_sqrt3_v<float>' to this literal, 
diff ers by '1.04e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: const auto inv_sqrt3f = std::numbers::inv_sqrt3_v<float>;
+
+    bar::sqrt(3);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt3' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt3;
+
+    auto somePhi = 1.6180339;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:20: warning: prefer 'std::numbers::phi' to this literal, 
diff ers by '8.87e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: auto somePhi = std::numbers::phi;
+
+    sink(Phi);
+
+    sink((42 + bar::sqrt(5)) / 2);
+
+    sink((1 + bar::sqrt(5)) / 2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::phi' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::phi);
+
+    sink((bar::sqrt(5.0F) + 1) / 2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::phi_v<float>' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::phi_v<float>);
+}
+
+
+
+template <typename T>
+void baz(){
+    static constexpr T Pi = 3.1415926;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:29: warning: prefer 'std::numbers::pi' to this literal, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr T Pi = std::numbers::pi;
+
+    static constexpr T Euler = 2.7182818;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:32: warning: prefer 'std::numbers::e' to this literal, 
diff ers by '2.85e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr T Euler = std::numbers::e;
+
+    static constexpr T Phi = 1.6180339;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:30: warning: prefer 'std::numbers::phi' to this literal, 
diff ers by '8.87e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr T Phi = std::numbers::phi;
+
+    static constexpr T PiCopy = Pi;
+    static constexpr T PiDefineFromMacro = MY_PI;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:44: warning: prefer 'std::numbers::pi' to this macro, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr T PiDefineFromMacro = std::numbers::pi;
+
+    static constexpr T Pi2 = 3.14;
+    // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:30: warning: prefer 'std::numbers::pi' to this literal, 
diff ers by '1.59e-03' [modernize-use-std-numbers]
+    // CHECK-FIXES-IMPRECISE: static constexpr T Pi2 = std::numbers::pi;
+    static constexpr T Euler2 = 2.71;
+    // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:33: warning: prefer 'std::numbers::e' to this literal, 
diff ers by '8.28e-03' [modernize-use-std-numbers]
+    // CHECK-FIXES-IMPRECISE: static constexpr T Euler2 = std::numbers::e;
+    static constexpr T Phi2 = 1.61;
+    // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:31: warning: prefer 'std::numbers::phi' to this literal, 
diff ers by '8.03e-03' [modernize-use-std-numbers]
+    // CHECK-FIXES-IMPRECISE: static constexpr T Phi2 = std::numbers::phi;
+
+    static constexpr T Pi3 = 3.1415926L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:30: warning: prefer 'std::numbers::pi_v<long double>' to this literal, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr T Pi3 = std::numbers::pi_v<long double>;
+
+    static constexpr T Euler3 = 2.7182818L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:33: warning: prefer 'std::numbers::e_v<long double>' to this literal, 
diff ers by '2.85e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr T Euler3 = std::numbers::e_v<long double>;
+
+    static constexpr T Phi3 = 1.6180339L;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:31: warning: prefer 'std::numbers::phi_v<long double>' to this literal, 
diff ers by '8.87e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: static constexpr T Phi3 = std::numbers::phi_v<long double>;
+
+    static constexpr my_float Actually2MyFloat = 2;
+    bar::sqrt(Actually2MyFloat);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2_v<float>' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2_v<float>;
+
+    constexpr static T One = 1;
+    constexpr static T Two = 2;
+
+    bar::sqrt(2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+    bar::sqrt(Two);
+
+    bar::sqrt(2.0);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+    T Not2 = 2;
+    Not2 = 42;
+    bar::sqrt(Not2);
+
+    const T Actually2 = 2;
+    bar::sqrt(Actually2);
+
+    exp(1);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::e;
+
+    exp(One);
+
+    exp(1.00000000000001);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::e;
+
+    log2(exp(1));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+    // CHECK-MESSAGES-ALL: :[[@LINE-2]]:10: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log2e;
+
+    log2(Euler);
+
+    log2(bar::e);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log2e;
+
+    T log2e = 1.4426950;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e' to this literal, 
diff ers by '4.09e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: T log2e = std::numbers::log2e;
+
+    log10(exp(1));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+    // CHECK-MESSAGES-ALL: :[[@LINE-2]]:11: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log10e;
+
+    log10(Euler);
+
+    log10(bar::e);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::log10e;
+
+    T log10e = .434294;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:16: warning: prefer 'std::numbers::log10e' to this literal, 
diff ers by '4.82e-07' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: T log10e = std::numbers::log10e;
+
+    T egamma = 0.5772156 * 42;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:16: warning: prefer 'std::numbers::egamma' to this literal, 
diff ers by '6.49e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: T egamma = std::numbers::egamma * 42;
+
+    sink(1 / Pi);
+
+    sink(1 / bar::sqrt(Pi));
+
+    sink(1 / bar::sqrt(MY_PI));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrtpi' to this formula [modernize-use-std-numbers]
+    // CHECK-MESSAGES-ALL: :[[@LINE-2]]:24: warning: prefer 'std::numbers::pi' to this macro, 
diff ers by '5.36e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrtpi);
+
+
+    log(2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::ln2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::ln2;
+
+    log(10);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::ln10' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::ln10;
+
+    bar::sqrt(2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+    sink(1 / bar::sqrt(3));
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrt3' to this formula [modernize-use-std-numbers]
+    // CHECK-MESSAGES-ALL: :[[@LINE-2]]:14: warning: prefer 'std::numbers::sqrt3' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrt3);
+
+    bar::sqrt(3);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt3' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: std::numbers::sqrt3;
+
+    T phi = 1.6180339;
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: prefer 'std::numbers::phi' to this literal, 
diff ers by '8.87e-08' [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: T phi = std::numbers::phi;
+
+    sink((42 + bar::sqrt(5)) / 2);
+
+    sink((1 + bar::sqrt(5)) / 2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::phi' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::phi);
+
+    sink((bar::sqrt(5.0F) + 1) / 2);
+    // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::phi_v<float>' to this formula [modernize-use-std-numbers]
+    // CHECK-FIXES-ALL: sink(std::numbers::phi_v<float>);
+}
+
+template <typename T>
+void foobar(){
+    const T Two = 2;
+    bar::sqrt(Two);
+}
+void use_templates() {
+    foobar<float>();
+    foobar<double>();
+
+    baz<float>();
+    baz<double>();
+}
+
+#define BIG_MARCO                                                              \
+  struct InvSqrt3 {                                                            \
+    template <typename T> static T get() { return 1 / bar::sqrt(3); }          \
+  }
+
+BIG_MARCO;
+
+void use_BIG_MACRO() {
+InvSqrt3 f{};
+f.get<float>();
+f.get<double>();
+}


        


More information about the cfe-commits mailing list