-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
floating point to floating point casts have undefined behaviour #15536
Comments
Nominating |
I think this is not a 1.0 issue. There is no reasonable backwards incompatible language change we can make here to fix it. The only thing to do is to change the LLVM semantics here to not be UB, but rather be an undefined value. |
@pcwalton the LLVM semantics here are that the result is an undefined value, not that the instruction exhibits undefined behavior. Otherwise you wouldn't be able to hoist an |
OK, then I believe this is not a bug, just something to remember to note in the spec. |
@zwarich: Rust allows undefined behaviour if you have an undefined value. An undefined value has no live range so it doesn't correspond to a reserved register with a preserved value and can vary between reads. That means something like |
@thestinger That's a good point, but that just makes it like the other bugs that aren't in 1.0. |
Programs can be written depending on the value of undefined behaviour, and changing it to either fail or provide a specific result will break those programs. This isn't C where undefined behaviour is a problem in user code. |
We may need a UB label for such issues IMO |
Can anybody reproduce this undefined behaviour? In #![crate_type="rlib"]
const f:f64 = 1.0E+300;
pub static ffull:f64 = f;
pub static ftrunc:f32 = f as f32;
pub static f2i:u64 = f as u64;
pub static i2f:f32 = 0xFFFFFFFFFFFFFFFFu64 as f32;
I asked for additional information on llvm-dev |
@ranma42 From what I understood from the reference, the LLVM |
(moving this back to P-medium and letting the |
My thought is to define this as resulting as infinity. |
@drbo But doing that could be potentially more expensive than just making the result unspecified but without causing undefined behavior. |
I believe this ("if it doesn't fit in the destination type, you get UB/undef") is and always has been FUD caused by individual LLVM developers misunderstanding IEEE 754, just like with signalling NaNs. LLVM's actual long-standing policy (now finally documented) — and the only policy that makes sense for an optimizing C compiler IMO — is that everything happens in the default floating point environment. This means among other things that rounding is always ties-to-even, the status flags are never inspected, and floating point exception handling always uses the default behavior rather than any custom handling. Consequently, it is clear as day that a floating point truncation that exceeds the range of the target type should result in positive or negative infinity. And indeed that is what LLVM's constant folding will do (specifically, what APFloat will do). FWIW this operation is a standard operation (formatOf-convertFormat), defined in §5.4.2 of IEEE 754-2008, but it would not really matter if this was a non-standard operation since those follow the same basic rules. |
So I recommend:
|
@nagisa kindly filed an LLVM bug https://bugs.llvm.org/show_bug.cgi?id=36966 |
Commit https://reviews.llvm.org/rL329065 removed the quoted statement (and also the stuff about undefined rounding mode) and replaced it with
Since this was just a doc clarification and in reality LLVM always behaved as we wanted it to, there's no need to wait until an LLVM update to pick up any code changes related to this. So we can close this issue now. |
As discussed in rust-lang#15536, the LLVM documentation incorrect described overflowing f64->f32 casts as being undefined behavior. LLVM never treated them as such, and the documentation has been adjusted in https://reviews.llvm.org/rL329065. As such, this warning can now be removed. Closes rust-lang#49622.
Remove warning about f64->f32 cast being potential UB As discussed in rust-lang#15536, the LLVM documentation incorrect described overflowing f64->f32 casts as being undefined behavior. LLVM never treated them as such, and the documentation has been adjusted in https://reviews.llvm.org/rL329065. As such, this warning can now be removed. Closes rust-lang#49622. --- I could not find any existing test checking for this warning. Should I be adding a test for the absence of the warning instead?
rust-lang/rust#15536 has been closed, there's no UB there, so let's stop linking to it. And for the same reasons (LLVM's assumption of the default floating point environment), f64->f32 and int->float casts do actually have a defined rounding mode, ties-to-even.
Thanks @rkruppe for clearing this up, however the reference still says this is UB. |
@dhardy Thanks for pointing this out, filed a PR to update the reference. |
184: Update AsPrimitive Safety docs for rust 1.45 r=cuviper a=martin-t Fixes #174 The safety section should not be removed entirely since people might be using older compilers (as was pointed out to me in a [related issue](yoanlcq/vek#59) in the vek crate). However, [this](rust-lang/rust#15536 (comment)) and followup comments indicate that the second case (float to float) was never UB in the first place - should the second example be removed? Co-authored-by: Martin Taibr <[email protected]>
The implementation of `<f64 as ToPrimitive>::to_f32` was written at a time when float-to-float overflow was though to be undefined behavior, per rust-lang/rust#15536, but this was later determined to be fine. Casting a large `f64` to `f32` just results in an infinity with the matching sign. The sign gives more information than if `to_f32` just returns `None`, so now we let these infinities through as a result. See also rust-num/num-bigint#163 and rust-num/num-rational#83.
185: Trust the "i128" feature r=cuviper a=cuviper If the "i128" feature is explicity requested, don't bother probing for it. It will still cause a build error if that was set improperly. 186: Allow large f64-to-f32 to saturate to infinity r=cuviper a=cuviper The implementation of `<f64 as ToPrimitive>::to_f32` was written at a time when float-to-float overflow was though to be undefined behavior, per rust-lang/rust#15536, but this was later determined to be fine. Casting a large `f64` to `f32` just results in an infinity with the matching sign. The sign gives more information than if `to_f32` just returns `None`, so now we let these infinities through as a result. See also rust-num/num-bigint#163 and rust-num/num-rational#83. 190: Normalize the comment style r=cuviper a=cuviper Co-authored-by: Josh Stone <[email protected]>
http://llvm.org/docs/LangRef.html#fptrunc-to-instruction
e.g.
1e300f64 as f32
cc #10184, #10185
The text was updated successfully, but these errors were encountered: