summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-11-09 23:24:47 +0000
committerJohn McCall <rjmccall@apple.com>2010-11-09 23:24:47 +0000
commitd2a5312e14e3ff1797bb821e26e6da80dc8801cc (patch)
tree8e75bbc75b99ee45969799c82c6d3595552f1edc /clang
parent07569be70ccda18d0c35b67b0f0432894b82b17a (diff)
downloadbcm5719-llvm-d2a5312e14e3ff1797bb821e26e6da80dc8801cc.tar.gz
bcm5719-llvm-d2a5312e14e3ff1797bb821e26e6da80dc8801cc.zip
Add a warning for implicit truncation of constant values due to
bitfield assignment. Implements rdar://problem/7809123 llvm-svn: 118647
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--clang/lib/Sema/SemaChecking.cpp58
-rw-r--r--clang/test/Sema/constant-conversion.c6
3 files changed, 64 insertions, 3 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7b17d7093ed..27d77e46189 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 4cf466311b3..caaa08c0bc2 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -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
diff --git a/clang/test/Sema/constant-conversion.c b/clang/test/Sema/constant-conversion.c
index cacd5968dc0..29571831653 100644
--- a/clang/test/Sema/constant-conversion.c
+++ b/clang/test/Sema/constant-conversion.c
@@ -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}}
+}
OpenPOWER on IntegriCloud