diff options
author | John McCall <rjmccall@apple.com> | 2010-11-09 23:24:47 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-11-09 23:24:47 +0000 |
commit | beb22aaa22e255241d6a81e8b0a9239f5fa584f3 (patch) | |
tree | 40d99917b6b32f9a949eea1e51e8109e608bf1d3 /lib/Sema/SemaChecking.cpp | |
parent | 15952c91671ce2d7a3da9e219d923a104cc432ec (diff) |
Add a warning for implicit truncation of constant values due to
bitfield assignment.
Implements rdar://problem/7809123
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118647 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 4cf466311b..caaa08c0bc 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/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 |