From 88617a24adafed42e33d196972f97c72d9a5e0a0 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Tue, 28 Aug 2012 15:44:30 +0000 Subject: [PATCH] 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 --- include/clang/Basic/DiagnosticGroups.td | 2 + include/clang/Basic/DiagnosticSemaKinds.td | 3 + lib/Sema/SemaChecking.cpp | 64 +++++++++++++++++++ ...icit-conversion-floating-point-to-bool.cpp | 24 +++++++ 4 files changed, 93 insertions(+) create mode 100644 test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index c2f2a9fa51..4ce43e0d62 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -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">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 867f75c792..3779da7b1b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; +def warn_impcast_floating_point_to_bool : Warning< + "implicit conversion turns floating-point number into bool: %0 to %1">, + InGroup; def warn_impcast_function_to_bool : Warning< "address of function %q0 will always evaluate to 'true'">, InGroup; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index cb975ad1c0..8760c5e77f 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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(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(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(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(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(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(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. diff --git a/test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp b/test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp new file mode 100644 index 0000000000..1d8037aceb --- /dev/null +++ b/test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp @@ -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); + +} -- 2.40.0