[PATCH] Dangerous long casts
Aaron Ballman
aaron at aaronballman.com
Thu Dec 4 07:51:52 PST 2014
On Thu, Dec 4, 2014 at 8:45 AM, Anders Rönnholm
<Anders.Ronnholm at evidente.se> wrote:
> Thanks for the comments.
>
> I have added addition and ran it on clang and gimp without any false positives. Added some test cases and refactored the test.
Some minor nits below, but generally LGTM. I think Richard should take
a look as well -- my only concern is adding a warning that's
off-by-default (we usually try to avoid that unless there's
significant benefit). I think this patch has benefit, I've seen it
implemented by other vendors as well. However, Richard may have other
opinions.
> Index: include/clang/Basic/DiagnosticSemaKinds.td
> ===================================================================
> --- include/clang/Basic/DiagnosticSemaKinds.td (revision 223224)
> +++ include/clang/Basic/DiagnosticSemaKinds.td (working copy)
> @@ -2481,6 +2481,9 @@
> def warn_impcast_integer_precision : Warning<
> "implicit conversion loses integer precision: %0 to %1">,
> InGroup<Conversion>, DefaultIgnore;
> +def warn_impcast_trunc : Warning<
> + "possible truncation before conversion from %0 to %1">,
> + InGroup<Conversion>, DefaultIgnore;
> def warn_impcast_integer_64_32 : Warning<
> "implicit conversion loses integer precision: %0 to %1">,
> InGroup<Shorten64To32>, DefaultIgnore;
> Index: lib/Sema/SemaChecking.cpp
> ===================================================================
> --- lib/Sema/SemaChecking.cpp (revision 223224)
> +++ lib/Sema/SemaChecking.cpp (working copy)
> @@ -6248,6 +6248,19 @@
> S.getFixItZeroLiteralForType(T, Loc));
> }
>
> +static bool CheckPossibleTruncation(const Expr *E, const IntRange Source,
> + const IntRange Target) {
> + if (Source.Width < Target.Width) {
> + if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(E))
> + if (Bop->getOpcode() == BO_Mul || Bop->getOpcode() == BO_Shl ||
> + Bop->getOpcode() == BO_Add)
> + return true;
> + if (const UnaryOperator *Uop = dyn_cast<UnaryOperator>(E))
> + if (Uop->getOpcode() == UO_Not)
> + return true;
> + }
> + return false;
> +}
> void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
> SourceLocation CC, bool *ICContext = nullptr) {
> if (E->isTypeDependent() || E->isValueDependent()) return;
> @@ -6454,6 +6467,9 @@
> return DiagnoseImpCast(S, E, T, CC, DiagID);
> }
>
> + if (CheckPossibleTruncation(E, SourceRange, TargetRange))
> + return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_trunc);
> +
> // Diagnose conversions between different enumeration types.
> // In C, we pretend that the type of an EnumConstantDecl is its enumeration
> // type, to give us better diagnostics.
> @@ -6482,6 +6498,33 @@
> return;
> }
>
> +static void CheckExplicitConversion(Sema &S, Expr *E, QualType T,
> + SourceLocation CC) {
> + if (E->isTypeDependent() || E->isValueDependent())
> + return;
> +
> + if (CC.isInvalid())
> + return;
> +
> + const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
> + const Type *Target = S.Context.getCanonicalType(T).getTypePtr();
> +
> + if (Source == Target)
> + return;
> +
> + if (Target->isDependentType())
> + return;
> +
> + if (!Source->isIntegerType() || !Target->isIntegerType())
> + return;
> +
> + IntRange SourceRange = GetExprRange(S.Context, E);
> + IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
> +
> + if (CheckPossibleTruncation(E, SourceRange, TargetRange))
> + return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_trunc);
> +}
> +
> void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
> SourceLocation CC, QualType T);
>
> @@ -6571,7 +6614,13 @@
>
> if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
> return AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC);
> -
> +
> + // Check explicit conversions for CStyle castings.
> + if (CStyleCastExpr *CStyleExpr = dyn_cast<CStyleCastExpr>(E)) {
> + CheckExplicitConversion(S, CStyleExpr->getSubExpr()->IgnoreParenImpCasts(),
> + T, CC);
> + }
Can elide the braces.
> +
> // Skip past explicit casts.
> if (isa<ExplicitCastExpr>(E)) {
> E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts();
> Index: test/Sema/conversion.c
> ===================================================================
> --- test/Sema/conversion.c (revision 223224)
> +++ test/Sema/conversion.c (working copy)
> @@ -429,3 +429,27 @@
> ushort16 crCbScale = pairedConstants.s4; // expected-warning {{implicit conversion loses integer precision: 'uint32_t' (aka 'unsigned int') to 'ushort16'}}
> ushort16 brBias = pairedConstants.s6; // expected-warning {{implicit conversion loses integer precision: 'uint32_t' (aka 'unsigned int') to 'ushort16'}}
> }
> +
> +void f1(long l);
> +void test28(int a, int b) {
> + long l = a * b; // expected-warning {{possible truncation before conversion from 'int' to 'long'}}
> + l = (long)a * b;
> +
> + // implicit cast in function call
> + f1(a * 1000); // expected-warning {{possible truncation before conversion from 'int' to 'long'}}
> +
> + // implicit cast inside calculation
> + int result = (int)((a * 1000) / 2LL); // expected-warning {{possible truncation before conversion from 'int' to 'long long'}}
> +
> + long lAdd = a + b; // expected-warning {{possible truncation before conversion from 'int' to 'long'}}
> +}
> +
> +void test29(unsigned int n) {
> + long a = (long)(n << 8); // expected-warning {{possible truncation before conversion from 'unsigned int' to 'long'}}
> + a = (long)n << 8;
> +}
> +
> +long test30(int a) {
> + // implicit cast of return value to long
> + return a * 1000; // expected-warning {{possible truncation before conversion from 'int' to 'long'}}
> +}
Can still use some template tests, since the warning behavior changes
based on value/type dependence.
Thanks!
~Aaron
More information about the cfe-commits
mailing list