I have modifyed GetExprRange() to capture the promotion
of boolean values to ints when applying unary not to ensure
-Wsign-compare identifies unsigned/signed comparisons as
identified in:
Details
- Reviewers
rsmith aaron.ballman erichkeane
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
clang/lib/Sema/SemaChecking.cpp | ||
---|---|---|
12328 | UO_Plus also. |
Thank you for the patch! This is certainly an improvement but I think there are still some cases where we compute the wrong range for ~ with this patch applied.
clang/lib/Sema/SemaChecking.cpp | ||
---|---|---|
12328 | Taking those in turn:
In any case, I don't think we should have a default here that returns the width of the operand. Instead, I think the default should return the range for the type of E. | |
12334 | I don't think falling through and picking up the expression range of the operand is ever correct for ~. For example: bool f(char c) { return ~c > 0x10000; } ... produces a bogus tautological comparison warning. (This is not tautological: the ~ operator will map negative chars to ints in the range [2^31 - 2^7, 2^31) and non-negative chars to ints in the range [-2^31, -2^31+2^7), so this is equivalent to c < 0.) Also, using MaxWidth here is conservatively correct but isn't precise; for example, we should still warn on: bool f(bool b) { return ~b > 0x1'0000'0000LL; } ... because ~b always fits in an int, but I think MaxWidth here will be 64 so we won't warn. (It'd be nice to warn even on ~b > 0 but I don't think we can do that without some major changes to how IntRange is represented.) The true result range of ~n will be something like [-2^N, -2^N + 2^M) u [2^N - 2^M, 2^N) if the input is signed. IntRange can't represent a range with a hole in the middle like that, but it can represent [-2^N, 2^N), which seems like the least wrong answer that we can give -- that is notably also the entire range of the type of the ~ expression. We get a contiguous range [-2^N, -2^N + 2^M) if the input is known non-negative, but IntRange still can't represent that, and so that doesn't help us make our result any more precise than using the entire range of the type of E, unfortunately. So I think UO_Not should never look at its subexpression -- the best result we can give is IntRange::forValueOfType(C, GetExprType(E)), and that's what we should use. |
I've not been able to get the time for a while, I hope to be able to spend some more time on it, but I'd probably do that through a GitHub PR now. If someone else wants to take it on, I'd be fine with that.
Richard mentions UO_PreInc, UO_PreDec, UO_Minus, and UO_Not. What about the other 3?