Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -4646,19 +4646,33 @@ if (AbsKind == 0 && !IsStdAbs) return; - QualType ArgType = Call->getArg(0)->IgnoreParenImpCasts()->getType(); + const Expr *ArgExpr = Call->getArg(0)->IgnoreParenImpCasts(); + QualType ArgType = ArgExpr->getType(); QualType ParamType = Call->getArg(0)->getType(); - // Unsigned types cannot be negative. Suggest removing the absolute value + // Unsigned types cannot be negative, but a difference of two unsigned + // values can be negative if the subtrahend is greater. If the + // expression is not a difference, suggest removing the absolute value // function call. if (ArgType->isUnsignedIntegerType()) { - const char *FunctionName = - IsStdAbs ? "std::abs" : Context.BuiltinInfo.GetName(AbsKind); - Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType; - Diag(Call->getExprLoc(), diag::note_remove_abs) - << FunctionName - << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange()); - return; + if (!isa(ArgExpr) || + cast(ArgExpr)->getOpcode() != BO_Sub) { + const char *FunctionName = + IsStdAbs ? "std::abs" : Context.BuiltinInfo.GetName(AbsKind); + Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType; + Diag(Call->getExprLoc(), diag::note_remove_abs) + << FunctionName + << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange()); + return; + } + // Assume the argument type is the corresponding signed type for the + // rest of this analysis. + if (ArgType->isSpecificBuiltinType(BuiltinType::ULong)) + ArgType = Context.LongTy; + else if (ArgType->isSpecificBuiltinType(BuiltinType::ULongLong)) + ArgType = Context.LongLongTy; + else + ArgType = Context.IntTy; } // std::abs has overloads which prevent most of the absolute value problems Index: test/Sema/warn-absolute-value.c =================================================================== --- test/Sema/warn-absolute-value.c +++ test/Sema/warn-absolute-value.c @@ -780,3 +780,128 @@ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"" } +void test_unsigned_int_difference(unsigned int x, unsigned int y) { + (void)abs(x-y); + (void)labs(x-y); + (void)llabs(x-y); + + (void)fabsf(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"abs" + (void)fabs(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of integer type}} + // expected-note@-2 {{use function 'abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"abs" + (void)fabsl(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"abs" + + (void)cabsf(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"abs" + (void)cabs(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of integer type}} + // expected-note@-2 {{use function 'abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"abs" + (void)cabsl(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"abs" + + (void)__builtin_abs(x-y); + (void)__builtin_labs(x-y); + (void)__builtin_llabs(x-y); + + (void)__builtin_fabsf(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_abs" + (void)__builtin_fabs(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_abs" + (void)__builtin_fabsl(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_abs" + + (void)__builtin_cabsf(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_abs" + (void)__builtin_cabs(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_abs" + (void)__builtin_cabsl(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_abs" +} + +void test_unsigned_long_difference(unsigned long x, unsigned long y) { + (void)abs(x-y); // no warning - int and long are same length for this target + (void)labs(x-y); + (void)llabs(x-y); + + (void)fabsf(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"labs" + (void)fabs(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of integer type}} + // expected-note@-2 {{use function 'labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"labs" + (void)fabsl(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"labs" + + (void)cabsf(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"labs" + (void)cabs(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of integer type}} + // expected-note@-2 {{use function 'labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"labs" + (void)cabsl(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"labs" + + (void)__builtin_abs(x-y); // no warning - int and long are same length for + // this target + (void)__builtin_labs(x-y); + (void)__builtin_llabs(x-y); + + (void)__builtin_fabsf(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_labs" + (void)__builtin_fabs(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_labs" + (void)__builtin_fabsl(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_labs" + + (void)__builtin_cabsf(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_labs" + (void)__builtin_cabs(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_labs" + (void)__builtin_cabsl(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of integer type}} + // expected-note@-2 {{use function '__builtin_labs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_labs" +} + Index: test/SemaCXX/warn-absolute-value.cpp =================================================================== --- test/SemaCXX/warn-absolute-value.cpp +++ test/SemaCXX/warn-absolute-value.cpp @@ -821,3 +821,132 @@ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"" } +void test_unsigned_int_difference(unsigned int x, unsigned int y) { + (void)std::abs(x-y); + + (void)abs(x-y); + (void)labs(x-y); + (void)llabs(x-y); + + (void)fabsf(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs" + (void)fabs(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs" + (void)fabsl(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs" + + (void)cabsf(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs" + (void)cabs(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs" + (void)cabsl(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs" + + (void)__builtin_abs(x-y); + (void)__builtin_labs(x-y); + (void)__builtin_llabs(x-y); + + (void)__builtin_fabsf(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs" + (void)__builtin_fabs(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs" + (void)__builtin_fabsl(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs" + + (void)__builtin_cabsf(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs" + (void)__builtin_cabs(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs" + (void)__builtin_cabsl(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs" +} + +void test_unsigned_long_difference(unsigned long x, unsigned long y) { + (void)std::abs(x-y); + + (void)abs(x-y); // no warning - int and long are same length for this target + (void)labs(x-y); + (void)llabs(x-y); + + (void)fabsf(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs" + (void)fabs(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs" + (void)fabsl(x-y); + // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs" + + (void)cabsf(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs" + (void)cabs(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs" + (void)cabsl(x-y); + // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs" + + (void)__builtin_abs(x-y); // no warning - int and long are same length for + // this target + (void)__builtin_labs(x-y); + (void)__builtin_llabs(x-y); + + (void)__builtin_fabsf(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs" + (void)__builtin_fabs(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs" + (void)__builtin_fabsl(x-y); + // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs" + + (void)__builtin_cabsf(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs" + (void)__builtin_cabs(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs" + (void)__builtin_cabsl(x-y); + // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of integer type}} + // expected-note@-2 {{use function 'std::abs' instead}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs" +} +