diff options
| author | John McCall <rjmccall@apple.com> | 2011-07-14 22:39:48 +0000 |
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2011-07-14 22:39:48 +0000 |
| commit | 5143181ff961706cd845c7e85f30f1fde2e5a03c (patch) | |
| tree | 8eb56e366e417a60bb6ee4c9f447bd1ae2cf64aa /clang | |
| parent | 1f9913fdb20f922e9ae48cb590a3b7b52e8c8a30 (diff) | |
| download | bcm5719-llvm-5143181ff961706cd845c7e85f30f1fde2e5a03c.tar.gz bcm5719-llvm-5143181ff961706cd845c7e85f30f1fde2e5a03c.zip | |
Teach -Wconversion, -Wsign-compare etc. about division and remainder.
llvm-svn: 135208
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 48 | ||||
| -rw-r--r-- | clang/test/Sema/conversion.c | 8 |
2 files changed, 52 insertions, 4 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 267cda8f401..3b48201eddf 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2659,14 +2659,54 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { case BO_Sub: if (BO->getLHS()->getType()->isPointerType()) return IntRange::forValueOfType(C, E->getType()); - // fallthrough + break; - default: + // The width of a division result is mostly determined by the size + // of the LHS. + case BO_Div: { + // Don't 'pre-truncate' the operands. + unsigned opWidth = C.getIntWidth(E->getType()); + IntRange L = GetExprRange(C, BO->getLHS(), opWidth); + + // If the divisor is constant, use that. + llvm::APSInt divisor; + if (BO->getRHS()->isIntegerConstantExpr(divisor, C)) { + unsigned log2 = divisor.logBase2(); // floor(log_2(divisor)) + if (log2 >= L.Width) + L.Width = (L.NonNegative ? 0 : 1); + else + L.Width = std::min(L.Width - log2, MaxWidth); + return L; + } + + // Otherwise, just use the LHS's width. + IntRange R = GetExprRange(C, BO->getRHS(), opWidth); + return IntRange(L.Width, L.NonNegative && R.NonNegative); + } + + // The result of a remainder can't be larger than the result of + // either side. + case BO_Rem: { + // Don't 'pre-truncate' the operands. + unsigned opWidth = C.getIntWidth(E->getType()); + IntRange L = GetExprRange(C, BO->getLHS(), opWidth); + IntRange R = GetExprRange(C, BO->getRHS(), opWidth); + + IntRange meet = IntRange::meet(L, R); + meet.Width = std::min(meet.Width, MaxWidth); + return meet; + } + + // The default behavior is okay for these. + case BO_Mul: + case BO_Add: + case BO_Xor: + case BO_Or: break; } - // Treat every other operator as if it were closed on the - // narrowest type that encompasses both operands. + // The default case is to treat the operation as if it were closed + // on the narrowest type that encompasses both operands. IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth); return IntRange::join(L, R); diff --git a/clang/test/Sema/conversion.c b/clang/test/Sema/conversion.c index 1eaf7082d67..03204c63e96 100644 --- a/clang/test/Sema/conversion.c +++ b/clang/test/Sema/conversion.c @@ -335,3 +335,11 @@ void test_8559831(enum E8559831b value_a, E8559831c value_c) { enum E8559831a a3 = value_d; a3 = value_d; } + +void test26(int si, long sl) { + si = sl % sl; // expected-warning {{implicit conversion loses integer precision: 'long' to 'int'}} + si = sl % si; + si = si % sl; + si = si / sl; + si = sl / si; // expected-warning {{implicit conversion loses integer precision: 'long' to 'int'}} +} |

