]> granicus.if.org Git - clang/commitdiff
Add a warning for implicit truncation of constant values due to
authorJohn McCall <rjmccall@apple.com>
Tue, 9 Nov 2010 23:24:47 +0000 (23:24 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 9 Nov 2010 23:24:47 +0000 (23:24 +0000)
bitfield assignment.

Implements rdar://problem/7809123

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118647 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaChecking.cpp
test/Sema/constant-conversion.c

index 7b17d7093edeed6a317a84a14f2e8deee9f419f1..27d77e461895727b2a13ad5ae3af70e0063a8533 100644 (file)
@@ -1044,6 +1044,9 @@ def warn_impcast_integer_64_32 : Warning<
 def warn_impcast_integer_precision_constant : Warning<
   "implicit conversion from %2 to %3 changes value from %0 to %1">,
   InGroup<DiagGroup<"constant-conversion">>;
+def warn_impcast_bitfield_precision_constant : Warning<
+  "implicit truncation from %2 to bitfield changes value from %0 to %1">,
+  InGroup<DiagGroup<"constant-conversion">>;
 
 def warn_cast_align : Warning<
   "cast from %0 to %1 increases required alignment from %2 to %3">,
index 4cf466311b3681ba437c7afe1d73d73699360431..caaa08c0bc25522e35526a3ede3b9fad90a5990f 100644 (file)
@@ -2587,6 +2587,52 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
     << lex->getSourceRange() << rex->getSourceRange();
 }
 
+/// Analyze the given simple or compound assignment for warning-worthy
+/// operations.
+void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
+  // Just recurse on the LHS.
+  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
+
+  // We want to recurse on the RHS as normal unless we're assigning to
+  // a bitfield.
+  if (FieldDecl *Bitfield = E->getLHS()->getBitField()) {
+    assert(Bitfield->isBitField());
+
+    Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
+
+    llvm::APSInt Width(32);
+    Expr::EvalResult RHSValue;
+    if (!Bitfield->isInvalidDecl() &&
+        Bitfield->getBitWidth()->isIntegerConstantExpr(Width, S.Context) &&
+        RHS->Evaluate(RHSValue, S.Context) && RHSValue.Val.isInt()) {
+      const llvm::APSInt &Value = RHSValue.Val.getInt();
+      unsigned OriginalWidth = Value.getBitWidth();
+      unsigned FieldWidth = Width.getZExtValue();
+
+      if (OriginalWidth > FieldWidth) {
+        llvm::APSInt TruncatedValue = Value;
+        TruncatedValue.trunc(FieldWidth);
+        TruncatedValue.extend(OriginalWidth);
+
+        if (Value != TruncatedValue) {
+          std::string PrettyValue = Value.toString(10);
+          std::string PrettyTrunc = TruncatedValue.toString(10);
+
+          S.Diag(E->getOperatorLoc(),
+                 diag::warn_impcast_bitfield_precision_constant)
+            << PrettyValue << PrettyTrunc << RHS->getType()
+            << E->getRHS()->getSourceRange();
+
+          // Recurse, ignoring any implicit conversions on the RHS.
+          return AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
+        }
+      }
+    }
+  }
+
+  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
+}
+
 /// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion.
 void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext,
                      unsigned diag) {
@@ -2810,9 +2856,15 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
     return AnalyzeImplicitConversions(S, E, CC);
   }
 
-  // Do a somewhat different check with comparison operators.
-  if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isComparisonOp())
-    return AnalyzeComparison(S, cast<BinaryOperator>(E));
+  if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+    // Do a somewhat different check with comparison operators.
+    if (BO->isComparisonOp())
+      return AnalyzeComparison(S, BO);
+
+    // And with assignments and compound assignments.
+    if (BO->isAssignmentOp())
+      return AnalyzeAssignment(S, BO);
+  }
 
   // These break the otherwise-useful invariant below.  Fortunately,
   // we don't really need to recurse into them, because any internal
index cacd5968dc0daa56fe32e6621cf42374ef20e38f..29571831653698996de0ca20101f8a0fcdaa67f8 100644 (file)
@@ -7,3 +7,9 @@
 void test_6792488(void) {
   int x = 0x3ff0000000000000U; // expected-warning {{implicit conversion from 'unsigned long' to 'int' changes value from 4607182418800017408 to 0}}
 }
+
+void test_7809123(void) {
+  struct { int i5 : 5; } a;
+
+  a.i5 = 36; // expected-warning {{implicit truncation for 'int' to bitfield changes value from 36 to 4}}
+}