From: John McCall Date: Tue, 9 Nov 2010 23:24:47 +0000 (+0000) Subject: Add a warning for implicit truncation of constant values due to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=beb22aaa22e255241d6a81e8b0a9239f5fa584f3;p=clang 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 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7b17d7093e..27d77e4618 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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>; +def warn_impcast_bitfield_precision_constant : Warning< + "implicit truncation from %2 to bitfield changes value from %0 to %1">, + InGroup>; def warn_cast_align : Warning< "cast from %0 to %1 increases required alignment from %2 to %3">, 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(E) && cast(E)->isComparisonOp()) - return AnalyzeComparison(S, cast(E)); + if (BinaryOperator *BO = dyn_cast(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/test/Sema/constant-conversion.c b/test/Sema/constant-conversion.c index cacd5968dc..2957183165 100644 --- a/test/Sema/constant-conversion.c +++ b/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}} +}