<limits>: fix traps for integers#5816
Conversation
8fd1697 to
9833a4a
Compare
(cherry picked from commit c31c5e2)
Oh, however, this is arguably true for all non-promoted integer types. Due to usual arithmetic conversions, no arithmetic operation on |
Yes, @Alcaro mentioned that in Discord, and captured that in llvm/llvm-project#166053
You can try. |
|
Ah, I found that there's already LWG-554 which is closed as NAD. So perhaps we should make |
|
Thanks, I'll mention LWG-554 in the test.
I'm not sure. On one hand, the promotion happens. On the other, one can say that zero value does not change when it can be represented, whereas |
|
Let's make this mess even worse. Let's add two more interpretations of this property.
I feel the last one is slightly - slightly - more intuitive than the other four, but it's explicitly banhammered by LWG-554. I'm starting to suspect that the only winning move is not to play. |
I'd say the term "trap representation" is questionable. WG14-N2861 corrected it to "non-value representation", which should have clarified that such representations are not about values. CWG-2899 also clarified similar conditions in C++. Oh, |
# Conflicts: # tests/std/test.lst
# Conflicts: # tests/libcxx/expected_results.txt
|
Thanks for figuring all this stuff out and my apologies for how long it took to get to this! 😸 |
|
I'm mirroring this to the MSVC-internal repo. Please notify me if any further changes are pushed, otherwise no action is required. |
|
Thanks, Admiral Ackbar! 🐠 🧑🚀 💥 |
ARM64 coverage being added in #5815 drawn my attention to that
numeric_limithastraps, and it is apparently defined incorrectly for some architectures.🪤 What are traps?
See https://en.cppreference.com/w/cpp/types/numeric_limits/traps.html
trapsshould betrueif there's an operation on a value of that type that traps.For integers, it is zero division, it usually traps, but still does not trap for certain compiler/platform combinations. Sometimes it also happens with signed overflow on division. See below.
Hypothetically, I imagine that other signed overflows, like incrementing
intcontainingINT_MAX, may trap, but I'm not aware if any hardware behaves like this, at least, not our target platforms.We all know that
bools are integers, but they are surprisingly exempt from zero division trap: when you divide byfalse, you actually divide by integer zero, so it is notboolvalue that traps 😕. Oh, andboolhas non-value representations, but they do not trap for us either.For the same reason, other promoted integers don't trap.
Floats normally don't trap. You need to both compile with
/fp:exceptand enable these exceptions to make them trap. The trait reflects the state after program starts, so enabling by setting control word does not count.Overall that part of the traits doesn't seem to be terribly useful feature. For platform-agnostic code, the information "it is trap" is not useful, it does not tell where is the trap and what is the trap. And for platform-specific code, you can know the behavior of exact platforms specifically without querying the trait.
➗ Integer division traps
On x64 and x86,, integer zero division triggers some interrupt, ultimately resulting in
STATUS_INTEGER_DIVIDE_BY_ZERO(0xC0000094) structured exception.On Arm64 zero integer division results in having zero at destination, and no trap.
However, MSVC inserts check for zero and
brkinstruction to get into the same trap 🐶.clang-cldoes not implement this behavior, and does not trap on Arm64.INT_MIN / -1division would also trap on x64 and x86. The exception code isSTATUS_INTEGER_OVERFLOW(0xC0000095).This integer division overflow does not trap on Arm64: MSVC does not insert any checks for that.
⚙️ Product code fix
We change the value of
trapsfor all integers exceptbools and other promoted ones on all supported architectures.Except for Clang on Arm64, where we keep it
false.✔️ Coverage
The runtime test approach was rejected, as it needs UB to perform the actual behavior test.
So the test checks for the assumed behavior on current hardware and compiler.
It errors out on an unknown hardware.
This libc++ test still needs some fixes.
I have not checked ARM64 EC, but according to the 👮♂️ two policemen theorem 👮♀️, if it traps on x64, and traps on Arm64, then on Arm64 EC that is between both of them it also traps. And I expect from Clang to behave naturally and don't trap there.
🎃 Horror
This might be a mess when we link Clang and MSVC objects together, we define the same variable differently. On the other hand, we also mix behaviors in this case. The variable is
constexprand hence very inline, so the definition should not matter, it is expected to inline to query site even in/Od.