зеркало из https://github.com/microsoft/clang-1.git
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! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162763 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
9438016db2
Коммит
88617a24ad
|
@ -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">;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
Загрузка…
Ссылка в новой задаче