Index: clang-tools-extra/trunk/clang-tidy/performance/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/performance/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/performance/CMakeLists.txt @@ -6,6 +6,7 @@ ImplicitCastInLoopCheck.cpp InefficientStringConcatenationCheck.cpp PerformanceTidyModule.cpp + TypePromotionInMathFnCheck.cpp UnnecessaryCopyInitialization.cpp UnnecessaryValueParamCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/performance/PerformanceTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/performance/PerformanceTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/performance/PerformanceTidyModule.cpp @@ -10,11 +10,11 @@ #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" @@ -33,6 +33,8 @@ "performance-implicit-cast-in-loop"); CheckFactories.registerCheck( "performance-inefficient-string-concatenation"); + CheckFactories.registerCheck( + "performance-type-promotion-in-math-fn"); CheckFactories.registerCheck( "performance-unnecessary-copy-initialization"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/performance/TypePromotionInMathFnCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/performance/TypePromotionInMathFnCheck.h +++ clang-tools-extra/trunk/clang-tidy/performance/TypePromotionInMathFnCheck.h @@ -0,0 +1,40 @@ +//===--- 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 Index: clang-tools-extra/trunk/clang-tidy/performance/TypePromotionInMathFnCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/performance/TypePromotionInMathFnCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/performance/TypePromotionInMathFnCheck.cpp @@ -0,0 +1,172 @@ +//===--- 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(&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("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 if we suggest a cmath + // function and cmath is not already included. +} + +} // namespace performance +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/trunk/docs/ReleaseNotes.rst +++ clang-tools-extra/trunk/docs/ReleaseNotes.rst @@ -124,6 +124,12 @@ Warns about the performance overhead arising from concatenating strings using the ``operator+``, instead of ``operator+=``. +- New `performance-type-promotion-in-math-fn + `_ 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 `_ check supports arbitrary containers with with suitable ``empty()`` and ``size()`` Index: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst @@ -123,6 +123,7 @@ 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 Index: clang-tools-extra/trunk/docs/clang-tidy/checks/performance-type-promotion-in-math-fn.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/performance-type-promotion-in-math-fn.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/performance-type-promotion-in-math-fn.rst @@ -0,0 +1,11 @@ +.. 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). Index: clang-tools-extra/trunk/test/clang-tidy/performance-type-promotion-in-math-fn.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/performance-type-promotion-in-math-fn.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-type-promotion-in-math-fn.cpp @@ -0,0 +1,314 @@ +// 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(0)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbn' + // CHECK-FIXES: {{^}} std::scalbn(0.f, static_cast(0));{{$}} + + // No warnings for these. + scalbn(0., 0); + scalbn(0., static_cast(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); +}