In my codebase I usually assume that size_of::() >= 4 bytes (I sometimes add a const assert too). But sometimes, in tens of thousands of operations and assignments I may put by mistake a value larger than u32::MAX in an usize. This usually doesn't cause a problem because I am usually using a 64 bit system. But how can I spot such mistakes and only put values that fit in a 4 bytes inside my usize variables, so the code is portable to 32 bit systems too? A solution is to use u32 and cast only at the last moment to usize, but this introduces a ton of casts in my code that I want to avoid.
A possible solution could be to add two compilation features:
#![feature(debug_overflow_usize_past_u16_max)]
#![feature(debug_overflow_usize_past_u32_max)]
If you use one of them the compiler keeps using the same usize as before (this means size_of::() keeps being 8 for me) but it introduces overflow tests in debug builds to assure you don't put values larger than u32::MAX (or u16::MAX) inside your user-code usize values. I don't know if this a good solution, or if there's already another (better) solution.
If you try to create a usize from a different type, the compiler will force you to do a type conversion. If the conversion is always lossless, you'd be able to use From/Into, and if it can fail, you will have to use TryFrom/TryInto and handle the possible case of overflow.
Just be extra careful with as (avoid it at all or document the reasoning when you use it) and you won't be able to accidentally hit an overflow.
This can be solved by enabling integer_arithmetic clippy lint and using checked operations instead of operators. It's a good idea anyway if you care about correctness of your calculations.
Perhaps I'm missing something. Is that clippy lint able to do what I've asked, that is to give a run-time overflow error if in my code operations on 64 bit usize values generate a 64 bit usize value that doesn't fit inside 32 bits?
The clippy lint will give you a compile time warning/error if you use unchecked arithmetic operations (such as a + b for usize). To fix the warning, you will have to use checked arithmetic (e.g. a.checked_add(b)), and the compiler will force you to decide what to do in the case of overflow. There are also wrapping and saturating operations that may be convenient sometimes.
I am not sure, but I think you aren't understanding the problem. a + b for usize currently can't give an error because it fits in 64 bits. But that isn't the problem I am trying to solve. I am trying to solve a porting 64->32 bit problem, where I may have numbers larger than 32 bits inside 64 bit usize values on a 64 bit system. And I'd like to spot such problems on a 64 bit system. My first language isn't English, probably I am not expressing myself clearly enough in English...
a + b for usize can overflow (e.g. usize::MAX + 1 is not representable as usize), so this operation can panic or wrap, and it's better to use a checked conversion to handle the overflow case explicitly.
For usize, the available range of values depends on the platform. For example, if a = u32::MAX as usize and b = 1, then a.checked_add(b) will succeed on a 64-bit platform and fail on a 32-bit platform. By using a checked operation, you will catch the failure at run-time and will be able to handle it. If you want this operation to fail on a 64-bit platform as well, just use u32 instead of usize.
If this is not sufficient, can you give an example of the code that has the problem you'd like to detect?
I understand what you mean now, but I don't want to replace about 20_000 usize operations in my code with a checked_* just to avoid u64=>u32 possible porting bugs. That's too much unergonomic. Rust has transparent overflow checks on regular operations in debug builds (or builds with -C overflow-checks).
If we go back to my original post in this thread we can see a possible solution I've proposed, the usage of that #![feature(debug_overflow_usize_past_u32_max)] to introduce 32 bit overflow checks on the 64 bit usize values (perhaps I should move this question to the Internals forum?).