Hi,

I have a new check i'd like to get reviewed. It warns on dangerous long casts.

e.g
int a = 105000;
int b = 25000;
long l = a*b; // possible truncation before conversion from 'int' to 'long'

//Anders
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 221872)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -2472,6 +2472,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 221872)
+++ lib/Sema/SemaChecking.cpp	(working copy)
@@ -6408,6 +6408,14 @@
     return DiagnoseImpCast(S, E, T, CC, DiagID);
   }
 
+  if (SourceRange.Width < TargetRange.Width) {
+    if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(E))
+      if (Bop->getOpcode() == BO_Mul || Bop->getOpcode() == BO_Shl)
+        return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_trunc);
+    if (UnaryOperator *Uop = dyn_cast<UnaryOperator>(E))
+      if (Uop->getOpcode() == UO_Not)
+        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.
@@ -6436,6 +6444,39 @@
   return;
 }
 
+void CheckExplicitConversion(Sema &S, Expr *E, QualType T,
+                             SourceLocation CC, bool *ICContext = nullptr) {
+  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 (SourceRange.Width < TargetRange.Width) {
+    if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(E))
+      if (Bop->getOpcode() == BO_Mul || Bop->getOpcode() == BO_Shl)
+        return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_trunc);
+    if (UnaryOperator *Uop = dyn_cast<UnaryOperator>(E))
+      if (Uop->getOpcode() == UO_Not)
+        return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_trunc);
+  }
+}
+
 void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
                               SourceLocation CC, QualType T);
 
@@ -6518,6 +6559,11 @@
   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);
+  }
+
   // Skip past explicit casts.
   if (isa<ExplicitCastExpr>(E)) {
     E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts();
Index: test/Sema/conversion.c
===================================================================
--- test/Sema/conversion.c	(revision 221872)
+++ test/Sema/conversion.c	(working copy)
@@ -429,3 +429,13 @@
     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 test28(int a, int b) {
+  long l = a * b; // expected-warning {{possible truncation before conversion from 'int' to 'long'}}
+  l = (long)a * b;
+}
+
+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;
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to