Warn about suspicious implicit conversions from floating point to bool

This warns in two specific situations:

1) For potentially swapped function arguments, e.g.

     void foo(bool, float);
     foo(1.7, false);

2) Misplaced brackets around function call arguments, e.g.

     bool InRange = fabs(a - b < delta);

   Where the last argument in a function call is implicitly converted
   from bool to float, and the function returns a float which gets
   implicitly converted to bool.

Patch by Andreas Eckleder!

llvm-svn: 162763
This commit is contained in:
Hans Wennborg 2012-08-28 15:44:30 +00:00
parent 66a37f3aef
commit f4ad232921
4 changed files with 93 additions and 0 deletions

View File

@ -35,6 +35,8 @@ def BoolConversion : DiagGroup<"bool-conversion">;
def IntConversion : DiagGroup<"int-conversion">;
def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">;
def NullConversion : DiagGroup<"null-conversion">;
def ImplicitConversionFloatingPointToBool :
DiagGroup<"implicit-conversion-floating-point-to-bool">;
def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
def CXXCompat: DiagGroup<"c++-compat">;
def CastAlign : DiagGroup<"cast-align">;

View File

@ -1930,6 +1930,9 @@ def warn_non_literal_null_pointer : Warning<
def warn_impcast_null_pointer_to_integer : Warning<
"implicit conversion of NULL constant to %0">,
InGroup<NullConversion>;
def warn_impcast_floating_point_to_bool : Warning<
"implicit conversion turns floating-point number into bool: %0 to %1">,
InGroup<ImplicitConversionFloatingPointToBool>;
def warn_impcast_function_to_bool : Warning<
"address of function %q0 will always evaluate to 'true'">,
InGroup<BoolConversion>;

View File

@ -4356,6 +4356,46 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
return ValueInRange.toString(10);
}
static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) {
if (!isa<ImplicitCastExpr>(Ex))
return false;
Expr *InnerE = Ex->IgnoreParenImpCasts();
const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr();
const Type *Source =
S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
if (Target->isDependentType())
return false;
const BuiltinType *FloatCandidateBT =
dyn_cast<BuiltinType>(ToBool ? Source : Target);
const Type *BoolCandidateType = ToBool ? Target : Source;
return (BoolCandidateType->isSpecificBuiltinType(BuiltinType::Bool) &&
FloatCandidateBT && (FloatCandidateBT->isFloatingPoint()));
}
void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
SourceLocation CC) {
unsigned NumArgs = TheCall->getNumArgs();
for (unsigned i = 0; i < NumArgs; ++i) {
Expr *CurrA = TheCall->getArg(i);
if (!IsImplicitBoolFloatConversion(S, CurrA, true))
continue;
bool IsSwapped = ((i > 0) &&
IsImplicitBoolFloatConversion(S, TheCall->getArg(i - 1), false));
IsSwapped |= ((i < (NumArgs - 1)) &&
IsImplicitBoolFloatConversion(S, TheCall->getArg(i + 1), false));
if (IsSwapped) {
// Warn on this floating-point to bool conversion.
DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(),
CurrA->getType(), CC,
diag::warn_impcast_floating_point_to_bool);
}
}
}
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = 0) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@ -4491,6 +4531,26 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
}
// If the target is bool, warn if expr is a function or method call.
if (Target->isSpecificBuiltinType(BuiltinType::Bool) &&
isa<CallExpr>(E)) {
// Check last argument of function call to see if it is an
// implicit cast from a type matching the type the result
// is being cast to.
CallExpr *CEx = cast<CallExpr>(E);
unsigned NumArgs = CEx->getNumArgs();
if (NumArgs > 0) {
Expr *LastA = CEx->getArg(NumArgs - 1);
Expr *InnerE = LastA->IgnoreParenImpCasts();
const Type *InnerType =
S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
if (isa<ImplicitCastExpr>(LastA) && (InnerType == Target)) {
// Warn on this floating-point to bool conversion
DiagnoseImpCast(S, E, T, CC,
diag::warn_impcast_floating_point_to_bool);
}
}
}
return;
}
@ -4661,6 +4721,10 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
return;
}
// Check implicit argument conversions for function calls.
if (CallExpr *Call = dyn_cast<CallExpr>(E))
CheckImplicitArgumentConversions(S, Call, CC);
// Go ahead and check any implicit conversions we might have skipped.
// The non-canonical typecheck is just an optimization;
// CheckImplicitConversion will filter out dead implicit conversions.

View File

@ -0,0 +1,24 @@
// RUN: %clang_cc1 -verify -fsyntax-only %s
float foof(float x);
double food(double x);
void foo(bool b, float f);
void bar() {
float c = 1.7;
bool b = c;
double e = 1.7;
b = e;
b = foof(4.0);
b = foof(c < 1); // expected-warning {{implicit conversion turns floating-point number into bool: 'float' to 'bool'}}
b = food(e < 2); // expected-warning {{implicit conversion turns floating-point number into bool: 'double' to 'bool'}}
foo(c, b); // expected-warning {{implicit conversion turns floating-point number into bool: 'float' to 'bool'}}
foo(c, c);
}