ImplicitCastInLoopCheck.cpp
InefficientStringConcatenationCheck.cpp
PerformanceTidyModule.cpp
+ TypePromotionInMathFnCheck.cpp
UnnecessaryCopyInitialization.cpp
UnnecessaryValueParamCheck.cpp
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
-#include "InefficientStringConcatenationCheck.h"
-
#include "FasterStringFindCheck.h"
#include "ForRangeCopyCheck.h"
#include "ImplicitCastInLoopCheck.h"
+#include "InefficientStringConcatenationCheck.h"
+#include "TypePromotionInMathFnCheck.h"
#include "UnnecessaryCopyInitialization.h"
#include "UnnecessaryValueParamCheck.h"
"performance-implicit-cast-in-loop");
CheckFactories.registerCheck<InefficientStringConcatenationCheck>(
"performance-inefficient-string-concatenation");
+ CheckFactories.registerCheck<TypePromotionInMathFnCheck>(
+ "performance-type-promotion-in-math-fn");
CheckFactories.registerCheck<UnnecessaryCopyInitialization>(
"performance-unnecessary-copy-initialization");
CheckFactories.registerCheck<UnnecessaryValueParamCheck>(
--- /dev/null
+//===--- TypePromotionInMathFnCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypePromotionInMathFnCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringSet.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+namespace {
+AST_MATCHER_P(Type, isBuiltinType, BuiltinType::Kind, Kind) {
+ if (const auto *BT = dyn_cast<BuiltinType>(&Node)) {
+ return BT->getKind() == Kind;
+ }
+ return false;
+}
+} // anonymous namespace
+
+void TypePromotionInMathFnCheck::registerMatchers(MatchFinder *Finder) {
+ constexpr BuiltinType::Kind IntTy = BuiltinType::Int;
+ constexpr BuiltinType::Kind LongTy = BuiltinType::Long;
+ constexpr BuiltinType::Kind FloatTy = BuiltinType::Float;
+ constexpr BuiltinType::Kind DoubleTy = BuiltinType::Double;
+ constexpr BuiltinType::Kind LongDoubleTy = BuiltinType::LongDouble;
+
+ auto hasBuiltinTyParam = [](int Pos, BuiltinType::Kind Kind) {
+ return hasParameter(Pos, hasType(isBuiltinType(Kind)));
+ };
+ auto hasBuiltinTyArg = [](int Pos, BuiltinType::Kind Kind) {
+ return hasArgument(Pos, hasType(isBuiltinType(Kind)));
+ };
+
+ // Match calls to foo(double) with a float argument.
+ auto OneDoubleArgFns = hasAnyName(
+ "::acos", "::acosh", "::asin", "::asinh", "::atan", "::atanh", "::cbrt",
+ "::ceil", "::cos", "::cosh", "::erf", "::erfc", "::exp", "::exp2",
+ "::expm1", "::fabs", "::floor", "::ilogb", "::lgamma", "::llrint",
+ "::log", "::log10", "::log1p", "::log2", "::logb", "::lrint", "::modf",
+ "::nearbyint", "::rint", "::round", "::sin", "::sinh", "::sqrt", "::tan",
+ "::tanh", "::tgamma", "::trunc", "::llround", "::lround");
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(OneDoubleArgFns, parameterCountIs(1),
+ hasBuiltinTyParam(0, DoubleTy))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to foo(double, double) where both args are floats.
+ auto TwoDoubleArgFns = hasAnyName("::atan2", "::copysign", "::fdim", "::fmax",
+ "::fmin", "::fmod", "::hypot", "::ldexp",
+ "::nextafter", "::pow", "::remainder");
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(TwoDoubleArgFns, parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, DoubleTy))),
+ hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to fma(double, double, double) where all args are floats.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::fma"), parameterCountIs(3),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, DoubleTy),
+ hasBuiltinTyParam(2, DoubleTy))),
+ hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy),
+ hasBuiltinTyArg(2, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to frexp(double, int*) where the first arg is a float.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(
+ hasName("::frexp"), parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasParameter(1, parmVarDecl(hasType(pointerType(
+ pointee(isBuiltinType(IntTy)))))))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to nexttoward(double, long double) where the first arg is a
+ // float.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::nexttoward"), parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, LongDoubleTy))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to remquo(double, double, int*) where the first two args are
+ // floats.
+ Finder->addMatcher(
+ callExpr(
+ callee(functionDecl(
+ hasName("::remquo"), parameterCountIs(3),
+ hasBuiltinTyParam(0, DoubleTy), hasBuiltinTyParam(1, DoubleTy),
+ hasParameter(2, parmVarDecl(hasType(pointerType(
+ pointee(isBuiltinType(IntTy)))))))),
+ hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to scalbln(double, long) where the first arg is a float.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::scalbln"), parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, LongTy))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to scalbn(double, int) where the first arg is a float.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::scalbn"), parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, IntTy))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // modf(double, double*) is omitted because the second parameter forces the
+ // type -- there's no conversion from float* to double*.
+}
+
+void TypePromotionInMathFnCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ assert(Call != nullptr);
+
+ StringRef OldFnName = Call->getDirectCallee()->getName();
+
+ // In C++ mode, we prefer std::foo to ::foof. But some of these suggestions
+ // are only valid in C++11 and newer.
+ static llvm::StringSet<> Cpp11OnlyFns = {
+ "acosh", "asinh", "atanh", "cbrt", "copysign", "erf",
+ "erfc", "exp2", "expm1", "fdim", "fma", "fmax",
+ "fmin", "hypot", "ilogb", "lgamma", "llrint", "llround",
+ "log1p", "log2", "logb", "lrint", "lround", "nearbyint",
+ "nextafter", "nexttoward", "remainder", "remquo", "rint", "round",
+ "scalbln", "scalbn", "tgamma", "trunc"};
+ bool StdFnRequiresCpp11 = Cpp11OnlyFns.count(OldFnName);
+
+ std::string NewFnName;
+ if (getLangOpts().CPlusPlus &&
+ (!StdFnRequiresCpp11 || getLangOpts().CPlusPlus11))
+ NewFnName = ("std::" + OldFnName).str();
+ else
+ NewFnName = (OldFnName + "f").str();
+
+ diag(Call->getExprLoc(), "call to '%0' promotes float to double")
+ << OldFnName << FixItHint::CreateReplacement(
+ Call->getCallee()->getSourceRange(), NewFnName);
+
+ // FIXME: Perhaps we should suggest #include <cmath> if we suggest a cmath
+ // function and cmath is not already included.
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
--- /dev/null
+//===--- TypePromotionInMathFnCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// Finds calls to C math library functions with implicit float to double
+/// promotions.
+///
+/// For example, warns on ::sin(0.f), because this funciton's parameter is a
+/// double. You probably meant to call std::sin(0.f) (in C++), or sinf(0.f) (in
+/// C).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-type-promotion-in-math-fn.html
+class TypePromotionInMathFnCheck : public ClangTidyCheck {
+public:
+ TypePromotionInMathFnCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H
Warns about the performance overhead arising from concatenating strings using
the ``operator+``, instead of ``operator+=``.
+- New `performance-type-promotion-in-math-fn
+ <http://clang.llvm.org/extra/clang-tidy/checks/performance-type-promotion-in-math-fn.html>`_ check
+
+ Replaces uses of C-style standard math functions with double parameters and float
+ arguments with an equivalent function that takes a float parameter.
+
- `readability-container-size-empty
<http://clang.llvm.org/extra/clang-tidy/checks/readability-container-size-empty.html>`_ check
supports arbitrary containers with with suitable ``empty()`` and ``size()``
performance-for-range-copy
performance-implicit-cast-in-loop
performance-inefficient-string-concatenation
+ performance-type-promotion-in-math-fn
performance-unnecessary-copy-initialization
performance-unnecessary-value-param
readability-avoid-const-params-in-decls
--- /dev/null
+.. title:: clang-tidy - performance-type-promotion-in-math-fn
+
+performance-type-promotion-in-math-fn
+=====================================
+
+Finds calls to C math library functions (from ``math.h`` or, in C++, ``cmath``)
+with implicit ``float`` to ``double`` promotions.
+
+For example, warns on ``::sin(0.f)``, because this funciton's parameter is a
+double. You probably meant to call ``std::sin(0.f)`` (in C++), or ``sinf(0.f)``
+(in C).
--- /dev/null
+// RUN: %check_clang_tidy %s performance-type-promotion-in-math-fn %t
+
+double acos(double);
+double acosh(double);
+double asin(double);
+double asinh(double);
+double atan2(double, double);
+double atan(double);
+double atanh(double);
+double cbrt(double);
+double ceil(double);
+double copysign(double, double);
+double cos(double);
+double cosh(double);
+double erfc(double);
+double erf(double);
+double exp2(double);
+double exp(double);
+double expm1(double);
+double fabs(double);
+double fdim(double, double);
+double floor(double);
+double fma(double, double, double);
+double fmax(double, double);
+double fmin(double, double);
+double fmod(double, double);
+double frexp(double, int *);
+double hypot(double, double);
+double ilogb(double);
+double ldexp(double, double);
+double lgamma(double);
+long long llrint(double);
+double log10(double);
+double log1p(double);
+double log2(double);
+double logb(double);
+double log(double);
+long lrint(double);
+double modf(double);
+double nearbyint(double);
+double nextafter(double, double);
+double nexttoward(double, long double);
+double pow(double, double);
+double remainder(double, double);
+double remquo(double, double, int *);
+double rint(double);
+double round(double);
+double scalbln(double, long);
+double scalbn(double, int);
+double sin(double);
+double sinh(double);
+double sqrt(double);
+double tan(double);
+double tanh(double);
+double tgamma(double);
+double trunc(double);
+long long llround(double);
+long lround(double);
+
+void check_all_fns() {
+ float a, b, c;
+ int i;
+ long l;
+ int *int_ptr;
+
+ acos(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'acos' promotes float to double [performance-type-promotion-in-math-fn]
+ // CHECK-FIXES: {{^}} std::acos(a);{{$}}
+ acosh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'acosh'
+ // CHECK-FIXES: {{^}} std::acosh(a);{{$}}
+ asin(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'asin'
+ // CHECK-FIXES: {{^}} std::asin(a);{{$}}
+ asinh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'asinh'
+ // CHECK-FIXES: {{^}} std::asinh(a);{{$}}
+ atan2(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'atan2'
+ // CHECK-FIXES: {{^}} std::atan2(a, b);{{$}}
+ atan(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'atan'
+ // CHECK-FIXES: {{^}} std::atan(a);{{$}}
+ atanh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'atanh'
+ // CHECK-FIXES: {{^}} std::atanh(a);{{$}}
+ cbrt(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'cbrt'
+ // CHECK-FIXES: {{^}} std::cbrt(a);{{$}}
+ ceil(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'ceil'
+ // CHECK-FIXES: {{^}} std::ceil(a);{{$}}
+ copysign(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'copysign'
+ // CHECK-FIXES: {{^}} std::copysign(a, b);{{$}}
+ cos(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'cos'
+ // CHECK-FIXES: {{^}} std::cos(a);{{$}}
+ cosh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'cosh'
+ // CHECK-FIXES: {{^}} std::cosh(a);{{$}}
+ erf(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'erf'
+ // CHECK-FIXES: {{^}} std::erf(a);{{$}}
+ erfc(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'erfc'
+ // CHECK-FIXES: {{^}} std::erfc(a);{{$}}
+ exp2(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'exp2'
+ // CHECK-FIXES: {{^}} std::exp2(a);{{$}}
+ exp(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'exp'
+ // CHECK-FIXES: {{^}} std::exp(a);{{$}}
+ expm1(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'expm1'
+ // CHECK-FIXES: {{^}} std::expm1(a);{{$}}
+ fabs(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fabs'
+ // CHECK-FIXES: {{^}} std::fabs(a);{{$}}
+ fdim(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fdim'
+ // CHECK-FIXES: {{^}} std::fdim(a, b);{{$}}
+ floor(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'floor'
+ // CHECK-FIXES: {{^}} std::floor(a);{{$}}
+ fma(a, b, c);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fma'
+ // CHECK-FIXES: {{^}} std::fma(a, b, c);{{$}}
+ fmax(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fmax'
+ // CHECK-FIXES: {{^}} std::fmax(a, b);{{$}}
+ fmin(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fmin'
+ // CHECK-FIXES: {{^}} std::fmin(a, b);{{$}}
+ fmod(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fmod'
+ // CHECK-FIXES: {{^}} std::fmod(a, b);{{$}}
+ frexp(a, int_ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'frexp'
+ // CHECK-FIXES: {{^}} std::frexp(a, int_ptr);{{$}}
+ hypot(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'hypot'
+ // CHECK-FIXES: {{^}} std::hypot(a, b);{{$}}
+ ilogb(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'ilogb'
+ // CHECK-FIXES: {{^}} std::ilogb(a);{{$}}
+ ldexp(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'ldexp'
+ // CHECK-FIXES: {{^}} std::ldexp(a, b);{{$}}
+ lgamma(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'lgamma'
+ // CHECK-FIXES: {{^}} std::lgamma(a);{{$}}
+ llrint(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'llrint'
+ // CHECK-FIXES: {{^}} std::llrint(a);{{$}}
+ llround(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'llround'
+ // CHECK-FIXES: {{^}} std::llround(a);{{$}}
+ log10(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'log10'
+ // CHECK-FIXES: {{^}} std::log10(a);{{$}}
+ log1p(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'log1p'
+ // CHECK-FIXES: {{^}} std::log1p(a);{{$}}
+ log2(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'log2'
+ // CHECK-FIXES: {{^}} std::log2(a);{{$}}
+ log(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'log'
+ // CHECK-FIXES: {{^}} std::log(a);{{$}}
+ logb(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'logb'
+ // CHECK-FIXES: {{^}} std::logb(a);{{$}}
+ lrint(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'lrint'
+ // CHECK-FIXES: {{^}} std::lrint(a);{{$}}
+ lround(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'lround'
+ // CHECK-FIXES: {{^}} std::lround(a);{{$}}
+ nearbyint(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nearbyint'
+ // CHECK-FIXES: {{^}} std::nearbyint(a);{{$}}
+ nextafter(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nextafter'
+ // CHECK-FIXES: {{^}} std::nextafter(a, b);{{$}}
+ nexttoward(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(a, b);{{$}}
+ pow(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'pow'
+ // CHECK-FIXES: {{^}} std::pow(a, b);{{$}}
+ remainder(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'remainder'
+ // CHECK-FIXES: {{^}} std::remainder(a, b);{{$}}
+ remquo(a, b, int_ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'remquo'
+ // CHECK-FIXES: {{^}} std::remquo(a, b, int_ptr);{{$}}
+ rint(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'rint'
+ // CHECK-FIXES: {{^}} std::rint(a);{{$}}
+ round(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'round'
+ // CHECK-FIXES: {{^}} std::round(a);{{$}}
+ scalbln(a, l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbln'
+ // CHECK-FIXES: {{^}} std::scalbln(a, l);{{$}}
+ scalbn(a, i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbn'
+ // CHECK-FIXES: {{^}} std::scalbn(a, i);{{$}}
+ sin(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'sin'
+ // CHECK-FIXES: {{^}} std::sin(a);{{$}}
+ sinh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'sinh'
+ // CHECK-FIXES: {{^}} std::sinh(a);{{$}}
+ sqrt(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'sqrt'
+ // CHECK-FIXES: {{^}} std::sqrt(a);{{$}}
+ tan(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'tan'
+ // CHECK-FIXES: {{^}} std::tan(a);{{$}}
+ tanh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'tanh'
+ // CHECK-FIXES: {{^}} std::tanh(a);{{$}}
+ tgamma(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'tgamma'
+ // CHECK-FIXES: {{^}} std::tgamma(a);{{$}}
+ trunc(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'trunc'
+ // CHECK-FIXES: {{^}} std::trunc(a);{{$}}
+}
+
+// nexttoward/nexttowardf are weird -- the second param is always long double.
+// So we warn if the first arg is a float, regardless of what the second arg is.
+void check_nexttoward() {
+ nexttoward(0.f, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(0.f, 0);{{$}}
+ nexttoward(0.f, 0l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(0.f, 0l);{{$}}
+ nexttoward(0.f, 0.f);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(0.f, 0.f);{{$}}
+ nexttoward(0.f, 0.);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(0.f, 0.);{{$}}
+
+ // No warnings for these.
+ nexttoward(0., 0);
+ nexttoward(0., 0.f);
+ nexttoward(0., 0.);
+}
+
+// The second parameter to scalbn and scalbnf is an int, so we don't care what
+// type you pass as that argument; we warn iff the first argument is a float.
+void check_scalbn() {
+ scalbn(0.f, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbn'
+ // CHECK-FIXES: {{^}} std::scalbn(0.f, 0);{{$}}
+ scalbn(0.f, static_cast<char>(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbn'
+ // CHECK-FIXES: {{^}} std::scalbn(0.f, static_cast<char>(0));{{$}}
+
+ // No warnings for these.
+ scalbn(0., 0);
+ scalbn(0., static_cast<char>(0));
+}
+
+// scalbln/scalblnf are like scalbn/scalbnf except their second arg is a long.
+// Again, doesn't matter what we pass for the second arg; we warn iff the first
+// arg is a float.
+void check_scalbln() {
+ scalbln(0.f, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbln'
+ // CHECK-FIXES: {{^}} std::scalbln(0.f, 0);{{$}}
+ scalbln(0.f, 0l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbln'
+ // CHECK-FIXES: {{^}} std::scalbln(0.f, 0l);{{$}}
+
+ // No warnings for these.
+ scalbln(0., 0);
+ scalbln(0., 0l);
+}
+
+float cosf(float);
+double foo(double); // not a math.h function
+float cos(float); // not a math.h function (wrong signature)
+double cos(double, double); // not a math.h function (wrong signature)
+
+namespace std {
+void cos(float);
+} // namespace std
+
+void check_no_warnings() {
+ foo(0.); // no warning because not a math.h function.
+
+ sin(0); // no warning because arg is an int
+ cos(0.); // no warning because arg is a double
+ std::cos(0.f); // no warning because not ::cos.
+ cosf(0.f); // no warning; we expect this to take a float
+ cos(0.f); // does not match the expected signature of ::cos
+ cos(0.f, 0.f); // does not match the expected signature of ::cos
+
+ // No warnings because all args are not floats.
+ remainder(0., 0.f);
+ remainder(0.f, 0.);
+ remainder(0, 0.f);
+ remainder(0.f, 0);
+ fma(0.f, 0.f, 0);
+ fma(0.f, 0.f, 0.);
+ fma(0.f, 0., 0.f);
+ fma(0., 0.f, 0.f);
+}