Question:
Hello, I'm trying to build a pure-LLVM Rust (no linking to at all). Building rust with set as in returns failure since Clang (the C compiler) doesn't allow . Here's my : Here are the relevant bits of the log: Thanks. A complete log is available here:
I think I may have found the culprit. I'm not well-versed in building rustc (I particularly don't know why rust can build its own LLVM instance, but I assume this is to accommodate systems where LLVM doesn't even exist?), but isn't the choice between and is pretty much irrelevant per libc? And by the way, using gcc as , while it does accept the command, it warns (instead of erroring out like clang-9) because isn't supported in the C compiler.

pub fn compile() { let target = env::var("TARGET").expect("TARGET was not set"); let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); <del> let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big"; let cfg = &mut cc::Build::new(); cfg.cpp(true); cfg.cpp_set_stdlib(None); cfg.warnings(false); </del> <ins> let mut cc_cfg = cc::Build::new(); let mut cpp_cfg = cc::Build::new(); let root = Path::new("../../src/llvm-project/libunwind"); </ins> <del> // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765 if target_endian_little { cfg.define("__LITTLE_ENDIAN__", Some("1")); </del> <ins> cpp_cfg.cpp(true); cpp_cfg.cpp_set_stdlib(None); cpp_cfg.flag("-nostdinc++"); cpp_cfg.flag("-fno-exceptions"); cpp_cfg.flag("-fno-rtti"); cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); // Don't set this for clang // By default, Clang builds C code in GNU C17 mode. // By default, Clang builds C++ code according to the C++98 standard, // with many C++11 features accepted as extensions. if cpp_cfg.get_compiler().is_like_gnu() { cpp_cfg.flag("-std=c++11"); cc_cfg.flag("-std=c99"); </ins> } <del> if target_env == "msvc" { // Don't pull in extra libraries on MSVC cfg.flag("/Zl"); cfg.flag("/EHsc"); cfg.define("_CRT_SECURE_NO_WARNINGS", None); cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); } else if target.contains("x86_64-fortanix-unknown-sgx") { cfg.cpp(false); cfg.static_flag(true); cfg.opt_level(3); cfg.flag("-nostdinc++"); cfg.flag("-fno-exceptions"); cfg.flag("-fno-rtti"); cfg.flag("-fstrict-aliasing"); cfg.flag("-funwind-tables"); cfg.flag("-fvisibility=hidden"); cfg.flag("-fno-stack-protector"); cfg.flag("-ffreestanding"); cfg.flag("-fexceptions"); // easiest way to undefine since no API available in cc::Build to undefine cfg.flag("-U_FORTIFY_SOURCE"); cfg.define("_FORTIFY_SOURCE", "0"); cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); </del> <ins> if target.contains("x86_64-fortanix-unknown-sgx") || target_env == "musl" { // use the same GCC C compiler command to compile C++ code so we do not need to setup the // C++ compiler env variables on the builders. // Don't set this for clang++, as clang++ is able to compile this without libc++. if cpp_cfg.get_compiler().is_like_gnu() { cpp_cfg.cpp(false); } } </ins> <del> cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); cfg.define("RUST_SGX", "1"); cfg.define("__NO_STRING_INLINES", None); cfg.define("__NO_MATH_INLINES", None); cfg.define("_LIBUNWIND_IS_BAREMETAL", None); cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None); cfg.define("NDEBUG", None); } else { cfg.flag("-std=c99"); cfg.flag("-std=c++11"); cfg.flag("-nostdinc++"); cfg.flag("-fno-exceptions"); cfg.flag("-fno-rtti"); </del> <ins> for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() { cfg.warnings(false); </ins> cfg.flag("-fstrict-aliasing"); cfg.flag("-funwind-tables"); cfg.flag("-fvisibility=hidden"); <del> cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); </del> cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); <ins> cfg.include(root.join("include")); cfg.cargo_metadata(false); if target.contains("x86_64-fortanix-unknown-sgx") { cfg.static_flag(true); cfg.opt_level(3); cfg.flag("-fno-stack-protector"); cfg.flag("-ffreestanding"); cfg.flag("-fexceptions"); // easiest way to undefine since no API available in cc::Build to undefine cfg.flag("-U_FORTIFY_SOURCE"); cfg.define("_FORTIFY_SOURCE", "0"); cfg.define("RUST_SGX", "1"); cfg.define("__NO_STRING_INLINES", None); cfg.define("__NO_MATH_INLINES", None); cfg.define("_LIBUNWIND_IS_BAREMETAL", None); cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None); cfg.define("NDEBUG", None); } </ins> } <del> let mut unwind_sources = vec![ "Unwind-EHABI.cpp", "Unwind-seh.cpp", </del> <ins> let mut c_sources = vec![ </ins> "Unwind-sjlj.c", "UnwindLevel1-gcc-ext.c", "UnwindLevel1.c", "UnwindRegistersRestore.S", "UnwindRegistersSave.S", <del> "libunwind.cpp", </del> ]; <del> if target_vendor == "apple" { unwind_sources.push("Unwind_AppleExtras.cpp"); } </del> <ins> let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"]; let cpp_len = cpp_sources.len(); </ins> if target.contains("x86_64-fortanix-unknown-sgx") { <del> unwind_sources.push("UnwindRustSgx.c"); </del> <ins> c_sources.push("UnwindRustSgx.c"); </ins> } <del> let root = Path::new("../../src/llvm-project/libunwind"); cfg.include(root.join("include")); for src in unwind_sources { cfg.file(root.join("src").join(src)); </del> <ins> for src in c_sources { cc_cfg.file(root.join("src").join(src).canonicalize().unwrap()); </ins> } <del> if target_env == "musl" { // use the same C compiler command to compile C++ code so we do not need to setup the // C++ compiler env variables on the builders cfg.cpp(false); // linking for musl is handled in lib.rs cfg.cargo_metadata(false); println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap()); </del> <ins> for src in cpp_sources { cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap()); </ins> } <del> cfg.compile("unwind"); </del> <ins> let out_dir = env::var("OUT_DIR").unwrap(); println!("cargo:rustc-link-search=native={}", &out_dir); cpp_cfg.compile("unwind-cpp"); let mut count = 0; for entry in std::fs::read_dir(&out_dir).unwrap() { let obj = entry.unwrap().path().canonicalize().unwrap(); if let Some(ext) = obj.extension() { if ext == "o" { cc_cfg.object(&obj); count += 1; } } } assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir); cc_cfg.compile("unwind"); </ins> } }


Question:
Hello, I'm trying to build a pure-LLVM Rust (no linking to at all). Building rust with set as in returns failure since Clang (the C compiler) doesn't allow . Here's my : Here are the relevant bits of the log: Thanks. A complete log is available here:
I think I may have found the culprit. I'm not well-versed in building rustc (I particularly don't know why rust can build its own LLVM instance, but I assume this is to accommodate systems where LLVM doesn't even exist?), but isn't the choice between and is pretty much irrelevant per libc? And by the way, using gcc as , while it does accept the command, it warns (instead of erroring out like clang-9) because isn't supported in the C compiler.

} #[cfg(target_env = "musl")] <del> #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))] #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))] extern "C" {} </del> <ins> cfg_if::cfg_if! { if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] { compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time"); } else if #[cfg(feature = "llvm-libunwind")] { #[link(name = "unwind", kind = "static")] extern "C" {} } else if #[cfg(feature = "system-llvm-libunwind")] { #[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))] #[link(name = "unwind", cfg(not(target_feature = "crt-static")))] extern "C" {} } else { #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))] #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))] extern "C" {} } } </ins> // When building with crt-static, we get `gcc_eh` from the `libc` crate, since // glibc needs it, and needs it listed later on the linker command line. We


Question:
Hello, I'm trying to build a pure-LLVM Rust (no linking to at all). Building rust with set as in returns failure since Clang (the C compiler) doesn't allow . Here's my : Here are the relevant bits of the log: Thanks. A complete log is available here:
I think I may have found the culprit. I'm not well-versed in building rustc (I particularly don't know why rust can build its own LLVM instance, but I assume this is to accommodate systems where LLVM doesn't even exist?), but isn't the choice between and is pretty much irrelevant per libc? And by the way, using gcc as , while it does accept the command, it warns (instead of erroring out like clang-9) because isn't supported in the C compiler.

extern "C" {} #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] <del> #[link(name = "unwind", kind = "static-nobundle")] </del> <ins> #[link(name = "unwind", kind = "static")] </ins> extern "C" {}


Question:
The page currently talks only about the use of move with closures. The keyword is also valid before an async block. For example: . This page could be updated to include that usage. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --This issue has been assigned to via . <!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Edit  and make the text talk about async blocks as well.
claim

/// // x is no longer available /// ``` /// <ins> /// `move` is also valid before an async block. /// /// ```rust /// let capture = "hello"; /// let block = async move { ///     println!("rust says {} from async block", capture); /// }; /// ``` /// </ins> /// For more information on the `move` keyword, see the [closure]'s section /// of the Rust book or the [threads] section ///


Question:
Summary from : used as a tuple-struct constructor function should use the fully type-substituted form from the block, but does not. Thus, today this code is accepted, but it should not be. (Fixing this would be a breaking-change, so we should take care in how we deploy it.) Original bug report follows: <!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: In nightly rustc, compiles while yields a type mismatch error:
The one is incorrect, has all its generic parameters substituted, i.e. it's / in both cases, type or constructor function.
To be 100% clear here: I believe what is saying is that the compiler has a bug, and that the bug is that the code should be treated as a short-hand for: and thus should be yielding the same error that one sees for the cases in the code from the description. However, the code is not yielding an error at all.
T-compiler triage: leaving nominated for T-lang. Tagging as P-high priority to resolve whether the semantics described by is indeed what we want, and if so, how to address deploying a breaking-change to fix it.
cc I thought we had fixed this bug in (and to be clear, it's clearly a bug (as noted by in ). It should not compile.
Just to simplify a bit (still passes but shouldn't):
Just checked on godbolt and it seems to compile in every stable release since it was stabilized (). I haven't looked into the code again, but I don't really understand how didn't cover this. Did we forget to add a test with errors, and only tried to prevent ICEs, or something?

.unwrap_or(false); let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { <del> let ty = self.impl_self_ty(span, impl_def_id).ty; let adt_def = ty.ty_adt_def(); </del> <ins> let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); </ins> match ty.kind { ty::Adt(adt_def, substs) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant();


Question:
Summary from : used as a tuple-struct constructor function should use the fully type-substituted form from the block, but does not. Thus, today this code is accepted, but it should not be. (Fixing this would be a breaking-change, so we should take care in how we deploy it.) Original bug report follows: <!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: In nightly rustc, compiles while yields a type mismatch error:
The one is incorrect, has all its generic parameters substituted, i.e. it's / in both cases, type or constructor function.
To be 100% clear here: I believe what is saying is that the compiler has a bug, and that the bug is that the code should be treated as a short-hand for: and thus should be yielding the same error that one sees for the cases in the code from the description. However, the code is not yielding an error at all.
T-compiler triage: leaving nominated for T-lang. Tagging as P-high priority to resolve whether the semantics described by is indeed what we want, and if so, how to address deploying a breaking-change to fix it.
cc I thought we had fixed this bug in (and to be clear, it's clearly a bug (as noted by in ). It should not compile.
Just to simplify a bit (still passes but shouldn't):
Just checked on godbolt and it seems to compile in every stable release since it was stabilized (). I haven't looked into the code again, but I don't really understand how didn't cover this. Did we forget to add a test with errors, and only tried to prevent ICEs, or something?

span, "the `Self` constructor can only be used with tuple or unit structs", ); <del> if let Some(adt_def) = adt_def { </del> <ins> if let Some(adt_def) = ty.ty_adt_def() { </ins> match adt_def.adt_kind() { AdtKind::Enum => { err.help("did you mean to use one of the enum's variants?");


Question:
Summary from : used as a tuple-struct constructor function should use the fully type-substituted form from the block, but does not. Thus, today this code is accepted, but it should not be. (Fixing this would be a breaking-change, so we should take care in how we deploy it.) Original bug report follows: <!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: In nightly rustc, compiles while yields a type mismatch error:
The one is incorrect, has all its generic parameters substituted, i.e. it's / in both cases, type or constructor function.
To be 100% clear here: I believe what is saying is that the compiler has a bug, and that the bug is that the code should be treated as a short-hand for: and thus should be yielding the same error that one sees for the cases in the code from the description. However, the code is not yielding an error at all.
T-compiler triage: leaving nominated for T-lang. Tagging as P-high priority to resolve whether the semantics described by is indeed what we want, and if so, how to address deploying a breaking-change to fix it.
cc I thought we had fixed this bug in (and to be clear, it's clearly a bug (as noted by in ). It should not compile.
Just to simplify a bit (still passes but shouldn't):
Just checked on godbolt and it seems to compile in every stable release since it was stabilized (). I haven't looked into the code again, but I don't really understand how didn't cover this. Did we forget to add a test with errors, and only tried to prevent ICEs, or something?

<ins> fn main() {} struct S0<T>(T); impl<T> S0<T> { const C: S0<u8> = Self(0); //~^ ERROR mismatched types //~| ERROR mismatched types fn foo() { Self(0); //~^ ERROR mismatched types } } // Testing normalization. trait Fun { type Out; } impl<T> Fun for S0<T> { type Out = Self; } trait Foo<T> { fn foo(); } impl<T> Foo<T> for <S0<T> as Fun>::Out { fn foo() { Self(0); //~ ERROR mismatched types } } struct S1<T, U>(T, U); impl<T> S1<T, u8> { const C: S1<u8, u8> = Self(0, 1); //~^ ERROR mismatched types //~| ERROR mismatched types } struct S2<T>(T); impl<T> S2<T> { fn map<U>(x: U) -> S2<U> { Self(x) //~^ ERROR mismatched types //~| ERROR mismatched types } } </ins>


Question:
Summary from : used as a tuple-struct constructor function should use the fully type-substituted form from the block, but does not. Thus, today this code is accepted, but it should not be. (Fixing this would be a breaking-change, so we should take care in how we deploy it.) Original bug report follows: <!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: In nightly rustc, compiles while yields a type mismatch error:
The one is incorrect, has all its generic parameters substituted, i.e. it's / in both cases, type or constructor function.
To be 100% clear here: I believe what is saying is that the compiler has a bug, and that the bug is that the code should be treated as a short-hand for: and thus should be yielding the same error that one sees for the cases in the code from the description. However, the code is not yielding an error at all.
T-compiler triage: leaving nominated for T-lang. Tagging as P-high priority to resolve whether the semantics described by is indeed what we want, and if so, how to address deploying a breaking-change to fix it.
cc I thought we had fixed this bug in (and to be clear, it's clearly a bug (as noted by in ). It should not compile.
Just to simplify a bit (still passes but shouldn't):
Just checked on godbolt and it seems to compile in every stable release since it was stabilized (). I haven't looked into the code again, but I don't really understand how didn't cover this. Did we forget to add a test with errors, and only tried to prevent ICEs, or something?

<ins> error[E0308]: mismatched types --> $DIR/issue-69306.rs:5:28 | LL | impl<T> S0<T> { |      - this type parameter LL |     const C: S0<u8> = Self(0); |                            ^ expected type parameter `T`, found integer | = note: expected type parameter `T` found type `{integer}` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:5:23 | LL | impl<T> S0<T> { |      - this type parameter LL |     const C: S0<u8> = Self(0); |                       ^^^^^^^ expected `u8`, found type parameter `T` | = note: expected struct `S0<u8>` found struct `S0<T>` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:10:14 | LL | impl<T> S0<T> { |      - this type parameter ... LL |         Self(0); |              ^ expected type parameter `T`, found integer | = note: expected type parameter `T` found type `{integer}` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:27:14 | LL | impl<T> Foo<T> for <S0<T> as Fun>::Out { |      - this type parameter LL |     fn foo() { LL |         Self(0); |              ^ expected type parameter `T`, found integer | = note: expected type parameter `T` found type `{integer}` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:33:32 | LL | impl<T> S1<T, u8> { |      - this type parameter LL |     const C: S1<u8, u8> = Self(0, 1); |                                ^ expected type parameter `T`, found integer | = note: expected type parameter `T` found type `{integer}` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:33:27 | LL | impl<T> S1<T, u8> { |      - this type parameter LL |     const C: S1<u8, u8> = Self(0, 1); |                           ^^^^^^^^^^ expected `u8`, found type parameter `T` | = note: expected struct `S1<u8, _>` found struct `S1<T, _>` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:41:14 | LL | impl<T> S2<T> { |      - expected type parameter LL |     fn map<U>(x: U) -> S2<U> { |            - found type parameter LL |         Self(x) |              ^ expected type parameter `T`, found type parameter `U` | = note: expected type parameter `T` found type parameter `U` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:41:9 | LL | impl<T> S2<T> { |      - found type parameter LL |     fn map<U>(x: U) -> S2<U> { |            -           ----- expected `S2<U>` because of return type |            | |            expected type parameter LL |         Self(x) |         ^^^^^^^ expected type parameter `U`, found type parameter `T` | = note: expected struct `S2<U>` found struct `S2<T>` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0308`. </ins>


Question:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: This runs correctly (i.e. doesn't assert) when run with rust nightly, but fails at when run with miri on nightly (2020-02-20). It seems like miri just truncated the f64 to get the f32 and therefore converted the nan2 to a floating point zero instead of a floating point NaN
(Miri-the-tool has its own bugtracker at , where I see things earlier than when they are burried here.) Cc this could also be an apfloat issue as that's what Miri uses to implement casts. I don't think we are doing any truncation . Would be interesting to see the bit patterns involved.
for returns . So, this doesn't look like just a truncated to me, it looks like apfloat did something but that something is not correct (or at least, not nan-preserving -- I am not sure if that is a guarantee).
cc
Sorry, I should have said truncated the fraction there. The is the floating point exponent being set to all ones, the (plus the empty bottom 3 bits in the 8) is a truncation of the original fraction in the f64. By removing all the non-zero bits in the fraction it converted the NaN to an infinity. For reference for returns where the (plus the empty bottom 3 bits in the 8) is a truncation of the original fraction from 52 to 23 bits Note that the normal Rust compiler seems to always set the MSB in the fraction of a NaN during its conversion to avoid this problem. There is and is
Assuming that f64-to-f32 on NaN has fully defined semantics, we should probably have a test asserting these exact bit patterns for Miri. But what you wrote makes it sound even more like the bug is in apfloat, and not in the Miri code that feeds data to/from apfloat. FWIW, the float casting code is .
Yes, it does sound to me like an apfloat issue rather than something unique in Miri. Reading that casting method I can't see anything that is special casing the fraction truncation for NaNs, only for an 80bit extended precision type that has different NaN semantics. Sorry, I've not dealt with the bug workflow on Rust before - is it possible to move this bug to apfloat? Would you like me to create a separate bug on apfloat?
apfloat does not have a separate issue tracker, no need to move anything. However, if I understood correctly then apfloat is a direct Rust port of LLVM's apfloat -- so likely they have the same bug, and a fix would have to happen upstream as well.
Yes, rustcapfloat is a port of LLVM's APFloat, but (also in older versions, back to before started the Rust port). Note that the MSB of the significand is set, so this is indeed a NaN. It seems LLVM does not have the same bug. Something strange is up.
Hm, that's still not the same as the that we see at run-time though?
I think the LLVM C++ code doing the same cast is .
Sure, but that's intentional. Optimizations need to preserve whether something is a NaN but (by default) the payload bits, quiet/signaling distinction and sign bit are not generally preserved or guaranteed to match between compile time evaluation and run time evaluation.
So the semantics would be something like "if the result is a NaN, non-deterministically pick any legal NaN representation"?
That sounds about right. Kind of off-topic here, though -- if you want to discuss further, we have
The category should still be , but it looks like we don't enforce the significand is non-: <hr/ Wait, I just looked at your link and LLVM prints - that's a bitpattern, not a , lol. But with a to integer, it matches : (if you hover over the decimal value, helpfully shows it as hex)
Note that converting floats to double bit patterns happens when printing textual IR: I'm reasonably sure the constant folding produces a proper float (). But perhaps the non-zero bits in its significand are in bit positions 32? Then the bitcast code would silently drop them.
Just remembered I wanted to look at assembly or machine code to see what the LLVM lowers to and show that it's buggy in LLVM even outside of constant-folded bitcasts.
Also isn't a +Infinity, showing the had already truncated the significand?
. And I just realized that while the high half of is a f32 NaN, the whole bit string as an f64 is in fact a NaN and setting just one bit more (e.g. ) does make llc (and presumably bitcast folding) produce (an f32 NaN). So I guess that I interpreted incorrectly and the fptrunc folding is at fault after all.
So... what does this mean? Is it an LLVM bug, and do we have enough information to report it upstream?
Yes, either truncation needs to result in a non- (e.g. becoming when losing lower bits could be "rounded up" by setting it to ), or extracting the IEEE representation from should handle the situation by setting some bit. cc (I don't know who does upstream LLVM bug reports nowadays most often)
actually I misremembered what this bug is about. This is not just "surprising NaN payload", indeed the result here is not a NaN when it should be. So that is quite clearly a bug in LLVM's APfloat, or in the Rust port of it (but we seem confident the problem is upstream). It would be great if we could report this against LLVM, but I have no idea how to reproduce the problem with LLVM. Do we need to write a C++ program using APfloat, or can we somehow make this happen just with the right LLVM IR? was previously posted as an example, does this show an incorrect compilation? These bit patterns mean nothing to me.^^
Wow! That's extremely wrong! It turns a NaN into positive infinity! Poking it gives a bit more insight into the issue: shows that all bits in the NaN payload below the 29th bit are truncated here. Mercifully, I can repro this in rustcapfloat, which is easier for me to experiment with than LLVM's (okay, I also remember what a headache it was trying to make changes to LLVM in the past, and it's now not something I'm interested in doing in my spare time) That is, it reports has , but then turns it into . Doing some further digging shows points me to , where we call with a number that comes from the difference between (bits of significand) of the source and target, e.g. 53 - 22, or 29 (which all-but-confirms that this is the issue). (The branch where there's the sig::shiftleft is wrong too, FWIW). It's also pretty wrong — IEEE wants you to truncate the payload here, not shift it out. e.g. I think what you want to do is something like (this code intentionally doesn't compile, and is assuming is the target type and that things are beautifully simple enough that there's just a function which returns something I can bitand...): That said, this is possibly hopelessly wrong? I don't thing so but I don't have a copy of IEEE754 around to verify. ... ... Okay I tried to make it compile, and if you drop this beast in before the shifts (e.g. line 1488 as of commit ) the tests pass (Sorry, I foolishly did this in a github download of rustcapfloat, since my rustc is in the middle of other things, and so I can't easily just give you a patch) That said it could still have other issues. And the fix could be extremely wrong for other reasons, it's the result of not-very-long spent debugging. Someone who understands the code better should audit it for this issue ( It says you wrote ). Ditto for LLVM's version which I can hardly follow since my C++ is so rusty. That said, LLVM is a popular enough project that someone hopefully could take it from here? E.g. Turning a NaN into an infinity is extremely bad — obviously so. Masking away the bottom bits like this is an obvious bug (nothing anywhere does that), and so even if they don't care about preserving NaNs specifically I suspect they'd want to fix this. Edit: I wrote this without carefully reading the rest of this issue. I think you uncovered some of this? Maybe? I don't know. Maybe this helped, sorry if not.
Yeah that sounds wrong. :D I'm afraid I cannot comment on the internals of apfloat that you are getting into for the rest of your post. That stuff is way beyond me.^^ I understand you won't work on fixing this in LLVM, but could you make this a bugreport for them, in their bugzilla? I feel a bit awkward making a bugreport that basically says "look I don't know what I am talking about but I have it on good authority that what LLVM is doing is wrong". Would be better if someone who knows what they are talking about does that I think. ;) Chances are, they'll have someone who can fix it.
says I'll send them an email, but...
Argh. :/ I think this worked fine for me though. If they don't respond in a few days, we can also use me as a proxy.^^
That sounds fine. In the meantime it maybe be good for someone more familiar with the rustc_apfloat code to take a look at what I wrote anyway...
There was already a bug, but I a comment for it:
There's a fix on the LLVM side now, somewhere in -- there are multiple reviews, we should figure out which one actually landed. Anyone up for porting this back to the Rust apfloat?
I guess would be the page to check for what happened in apfloat upstream.
Done:
The fix on the LLVM side is the minimal possible fix to avoid the linked miscompilation here: It doesn't fix this bug in the general case.
is a more correct fix. But note that it's not just the change to APFloat that makes it correct (in fact, that change alone is arguably wrong), but at usage sites changing things to be (for example): I think we should probably do this inside our function, otherwise it would be incorrect too. This is unfortunate as it causes more divergence to upstream APFloat
are you referring to this segment of your comment above? Can you quote the part of the IEEE 754 standard which mandates this? Or alternatively, come up with an example like the one at the top where there is a mismatch between what happens at runtime vs during miri evaluation? Apparently hardware implementations shift out payloads as well: prints:
Larger example that compares runtime and const eval (as of nightly master): prints: Edit: apparently on the hardware it always unconditionally sets the highest bit of the mantissa when a NaN truncation is performed to work around the issue. Edit2: which is nothing other than turning the sNaN into a qNaN.
IEEE754-2019 6.2.3 (NaN Propagation) states that This seems impossible if the implementation shifts the payload out. But I guess this only applies to qNaN, although in my testing earlier it seemed to happen on sNaN on my machines. Anyway, I'm a bit busy at the moment, or I'd dig further into this.
I knew there were two patches but I have no idea which one landed... so far the plan was to only port things that have landed on the LLVM side. If there is still a bug left there, that seems worth reporting?
If the implementation shifts to the left on conversion to the wider format and back to the right on conversion to the narrower format, then the NaN payload will be the same. So I think that shifting is conformant with that rule of the standard. Otherwise hardware would be nonconformant as well. But maybe there's still some rule in the standard that LLVM apfloat violates.
Hmm, fair enough. Unfortunately, I don't think I'm going to have time to dig further into this for at least another week, but sounds good to me. Sorry for any trouble.
No trouble caused, thanks for looking into this. :)
Yes your comments were very helpful. I wouldn't have found or thought of looking for that LLVM MR for example.
This issue will be fixed by but that there are some other interesting test-cases that would not have been fixed by a more naive approach... would be great if we could get those testcases into our test suite as well :)

sig::set_bit(&mut r.sig, T::PRECISION - 1); } <del> // gcc forces the Quiet bit on, which means (float)(double)(float_sNan) // does not give you back the same bits. This is dubious, and we // don't currently do it. You're really supposed to get // an invalid operation signal at runtime, but nobody does that. status = Status::OK; </del> <ins> // Convert of sNaN creates qNaN and raises an exception (invalid op). // This also guarantees that a sNaN does not become Inf on a truncation // that loses all payload bits. if self.is_signaling() { // Quiet signaling NaN. sig::set_bit(&mut r.sig, T::QNAN_BIT); status = Status::INVALID_OP; } else { status = Status::OK; } </ins> } else { *loses_info = false; status = Status::OK;


Question:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: This runs correctly (i.e. doesn't assert) when run with rust nightly, but fails at when run with miri on nightly (2020-02-20). It seems like miri just truncated the f64 to get the f32 and therefore converted the nan2 to a floating point zero instead of a floating point NaN
(Miri-the-tool has its own bugtracker at , where I see things earlier than when they are burried here.) Cc this could also be an apfloat issue as that's what Miri uses to implement casts. I don't think we are doing any truncation . Would be interesting to see the bit patterns involved.
for returns . So, this doesn't look like just a truncated to me, it looks like apfloat did something but that something is not correct (or at least, not nan-preserving -- I am not sure if that is a guarantee).
cc
Sorry, I should have said truncated the fraction there. The is the floating point exponent being set to all ones, the (plus the empty bottom 3 bits in the 8) is a truncation of the original fraction in the f64. By removing all the non-zero bits in the fraction it converted the NaN to an infinity. For reference for returns where the (plus the empty bottom 3 bits in the 8) is a truncation of the original fraction from 52 to 23 bits Note that the normal Rust compiler seems to always set the MSB in the fraction of a NaN during its conversion to avoid this problem. There is and is
Assuming that f64-to-f32 on NaN has fully defined semantics, we should probably have a test asserting these exact bit patterns for Miri. But what you wrote makes it sound even more like the bug is in apfloat, and not in the Miri code that feeds data to/from apfloat. FWIW, the float casting code is .
Yes, it does sound to me like an apfloat issue rather than something unique in Miri. Reading that casting method I can't see anything that is special casing the fraction truncation for NaNs, only for an 80bit extended precision type that has different NaN semantics. Sorry, I've not dealt with the bug workflow on Rust before - is it possible to move this bug to apfloat? Would you like me to create a separate bug on apfloat?
apfloat does not have a separate issue tracker, no need to move anything. However, if I understood correctly then apfloat is a direct Rust port of LLVM's apfloat -- so likely they have the same bug, and a fix would have to happen upstream as well.
Yes, rustcapfloat is a port of LLVM's APFloat, but (also in older versions, back to before started the Rust port). Note that the MSB of the significand is set, so this is indeed a NaN. It seems LLVM does not have the same bug. Something strange is up.
Hm, that's still not the same as the that we see at run-time though?
I think the LLVM C++ code doing the same cast is .
Sure, but that's intentional. Optimizations need to preserve whether something is a NaN but (by default) the payload bits, quiet/signaling distinction and sign bit are not generally preserved or guaranteed to match between compile time evaluation and run time evaluation.
So the semantics would be something like "if the result is a NaN, non-deterministically pick any legal NaN representation"?
That sounds about right. Kind of off-topic here, though -- if you want to discuss further, we have
The category should still be , but it looks like we don't enforce the significand is non-: <hr/ Wait, I just looked at your link and LLVM prints - that's a bitpattern, not a , lol. But with a to integer, it matches : (if you hover over the decimal value, helpfully shows it as hex)
Note that converting floats to double bit patterns happens when printing textual IR: I'm reasonably sure the constant folding produces a proper float (). But perhaps the non-zero bits in its significand are in bit positions 32? Then the bitcast code would silently drop them.
Just remembered I wanted to look at assembly or machine code to see what the LLVM lowers to and show that it's buggy in LLVM even outside of constant-folded bitcasts.
Also isn't a +Infinity, showing the had already truncated the significand?
. And I just realized that while the high half of is a f32 NaN, the whole bit string as an f64 is in fact a NaN and setting just one bit more (e.g. ) does make llc (and presumably bitcast folding) produce (an f32 NaN). So I guess that I interpreted incorrectly and the fptrunc folding is at fault after all.
So... what does this mean? Is it an LLVM bug, and do we have enough information to report it upstream?
Yes, either truncation needs to result in a non- (e.g. becoming when losing lower bits could be "rounded up" by setting it to ), or extracting the IEEE representation from should handle the situation by setting some bit. cc (I don't know who does upstream LLVM bug reports nowadays most often)
actually I misremembered what this bug is about. This is not just "surprising NaN payload", indeed the result here is not a NaN when it should be. So that is quite clearly a bug in LLVM's APfloat, or in the Rust port of it (but we seem confident the problem is upstream). It would be great if we could report this against LLVM, but I have no idea how to reproduce the problem with LLVM. Do we need to write a C++ program using APfloat, or can we somehow make this happen just with the right LLVM IR? was previously posted as an example, does this show an incorrect compilation? These bit patterns mean nothing to me.^^
Wow! That's extremely wrong! It turns a NaN into positive infinity! Poking it gives a bit more insight into the issue: shows that all bits in the NaN payload below the 29th bit are truncated here. Mercifully, I can repro this in rustcapfloat, which is easier for me to experiment with than LLVM's (okay, I also remember what a headache it was trying to make changes to LLVM in the past, and it's now not something I'm interested in doing in my spare time) That is, it reports has , but then turns it into . Doing some further digging shows points me to , where we call with a number that comes from the difference between (bits of significand) of the source and target, e.g. 53 - 22, or 29 (which all-but-confirms that this is the issue). (The branch where there's the sig::shiftleft is wrong too, FWIW). It's also pretty wrong — IEEE wants you to truncate the payload here, not shift it out. e.g. I think what you want to do is something like (this code intentionally doesn't compile, and is assuming is the target type and that things are beautifully simple enough that there's just a function which returns something I can bitand...): That said, this is possibly hopelessly wrong? I don't thing so but I don't have a copy of IEEE754 around to verify. ... ... Okay I tried to make it compile, and if you drop this beast in before the shifts (e.g. line 1488 as of commit ) the tests pass (Sorry, I foolishly did this in a github download of rustcapfloat, since my rustc is in the middle of other things, and so I can't easily just give you a patch) That said it could still have other issues. And the fix could be extremely wrong for other reasons, it's the result of not-very-long spent debugging. Someone who understands the code better should audit it for this issue ( It says you wrote ). Ditto for LLVM's version which I can hardly follow since my C++ is so rusty. That said, LLVM is a popular enough project that someone hopefully could take it from here? E.g. Turning a NaN into an infinity is extremely bad — obviously so. Masking away the bottom bits like this is an obvious bug (nothing anywhere does that), and so even if they don't care about preserving NaNs specifically I suspect they'd want to fix this. Edit: I wrote this without carefully reading the rest of this issue. I think you uncovered some of this? Maybe? I don't know. Maybe this helped, sorry if not.
Yeah that sounds wrong. :D I'm afraid I cannot comment on the internals of apfloat that you are getting into for the rest of your post. That stuff is way beyond me.^^ I understand you won't work on fixing this in LLVM, but could you make this a bugreport for them, in their bugzilla? I feel a bit awkward making a bugreport that basically says "look I don't know what I am talking about but I have it on good authority that what LLVM is doing is wrong". Would be better if someone who knows what they are talking about does that I think. ;) Chances are, they'll have someone who can fix it.
says I'll send them an email, but...
Argh. :/ I think this worked fine for me though. If they don't respond in a few days, we can also use me as a proxy.^^
That sounds fine. In the meantime it maybe be good for someone more familiar with the rustc_apfloat code to take a look at what I wrote anyway...
There was already a bug, but I a comment for it:
There's a fix on the LLVM side now, somewhere in -- there are multiple reviews, we should figure out which one actually landed. Anyone up for porting this back to the Rust apfloat?
I guess would be the page to check for what happened in apfloat upstream.
Done:
The fix on the LLVM side is the minimal possible fix to avoid the linked miscompilation here: It doesn't fix this bug in the general case.
is a more correct fix. But note that it's not just the change to APFloat that makes it correct (in fact, that change alone is arguably wrong), but at usage sites changing things to be (for example): I think we should probably do this inside our function, otherwise it would be incorrect too. This is unfortunate as it causes more divergence to upstream APFloat
are you referring to this segment of your comment above? Can you quote the part of the IEEE 754 standard which mandates this? Or alternatively, come up with an example like the one at the top where there is a mismatch between what happens at runtime vs during miri evaluation? Apparently hardware implementations shift out payloads as well: prints:
Larger example that compares runtime and const eval (as of nightly master): prints: Edit: apparently on the hardware it always unconditionally sets the highest bit of the mantissa when a NaN truncation is performed to work around the issue. Edit2: which is nothing other than turning the sNaN into a qNaN.
IEEE754-2019 6.2.3 (NaN Propagation) states that This seems impossible if the implementation shifts the payload out. But I guess this only applies to qNaN, although in my testing earlier it seemed to happen on sNaN on my machines. Anyway, I'm a bit busy at the moment, or I'd dig further into this.
I knew there were two patches but I have no idea which one landed... so far the plan was to only port things that have landed on the LLVM side. If there is still a bug left there, that seems worth reporting?
If the implementation shifts to the left on conversion to the wider format and back to the right on conversion to the narrower format, then the NaN payload will be the same. So I think that shifting is conformant with that rule of the standard. Otherwise hardware would be nonconformant as well. But maybe there's still some rule in the standard that LLVM apfloat violates.
Hmm, fair enough. Unfortunately, I don't think I'm going to have time to dig further into this for at least another week, but sounds good to me. Sorry for any trouble.
No trouble caused, thanks for looking into this. :)
Yes your comments were very helpful. I wouldn't have found or thought of looking for that LLVM MR for example.
This issue will be fixed by but that there are some other interesting test-cases that would not have been fixed by a more naive approach... would be great if we could get those testcases into our test suite as well :)

} #[test] <ins> fn issue_69532() { let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128); let mut loses_info = false; let sta = f.convert(&mut loses_info); let r: Single = sta.value; assert!(loses_info); assert!(r.is_nan()); assert_eq!(sta.status, Status::INVALID_OP); } #[test] </ins> fn min_num() { let f1 = Double::from_f64(1.0); let f2 = Double::from_f64(2.0);


Question:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: This runs correctly (i.e. doesn't assert) when run with rust nightly, but fails at when run with miri on nightly (2020-02-20). It seems like miri just truncated the f64 to get the f32 and therefore converted the nan2 to a floating point zero instead of a floating point NaN
(Miri-the-tool has its own bugtracker at , where I see things earlier than when they are burried here.) Cc this could also be an apfloat issue as that's what Miri uses to implement casts. I don't think we are doing any truncation . Would be interesting to see the bit patterns involved.
for returns . So, this doesn't look like just a truncated to me, it looks like apfloat did something but that something is not correct (or at least, not nan-preserving -- I am not sure if that is a guarantee).
cc
Sorry, I should have said truncated the fraction there. The is the floating point exponent being set to all ones, the (plus the empty bottom 3 bits in the 8) is a truncation of the original fraction in the f64. By removing all the non-zero bits in the fraction it converted the NaN to an infinity. For reference for returns where the (plus the empty bottom 3 bits in the 8) is a truncation of the original fraction from 52 to 23 bits Note that the normal Rust compiler seems to always set the MSB in the fraction of a NaN during its conversion to avoid this problem. There is and is
Assuming that f64-to-f32 on NaN has fully defined semantics, we should probably have a test asserting these exact bit patterns for Miri. But what you wrote makes it sound even more like the bug is in apfloat, and not in the Miri code that feeds data to/from apfloat. FWIW, the float casting code is .
Yes, it does sound to me like an apfloat issue rather than something unique in Miri. Reading that casting method I can't see anything that is special casing the fraction truncation for NaNs, only for an 80bit extended precision type that has different NaN semantics. Sorry, I've not dealt with the bug workflow on Rust before - is it possible to move this bug to apfloat? Would you like me to create a separate bug on apfloat?
apfloat does not have a separate issue tracker, no need to move anything. However, if I understood correctly then apfloat is a direct Rust port of LLVM's apfloat -- so likely they have the same bug, and a fix would have to happen upstream as well.
Yes, rustcapfloat is a port of LLVM's APFloat, but (also in older versions, back to before started the Rust port). Note that the MSB of the significand is set, so this is indeed a NaN. It seems LLVM does not have the same bug. Something strange is up.
Hm, that's still not the same as the that we see at run-time though?
I think the LLVM C++ code doing the same cast is .
Sure, but that's intentional. Optimizations need to preserve whether something is a NaN but (by default) the payload bits, quiet/signaling distinction and sign bit are not generally preserved or guaranteed to match between compile time evaluation and run time evaluation.
So the semantics would be something like "if the result is a NaN, non-deterministically pick any legal NaN representation"?
That sounds about right. Kind of off-topic here, though -- if you want to discuss further, we have
The category should still be , but it looks like we don't enforce the significand is non-: <hr/ Wait, I just looked at your link and LLVM prints - that's a bitpattern, not a , lol. But with a to integer, it matches : (if you hover over the decimal value, helpfully shows it as hex)
Note that converting floats to double bit patterns happens when printing textual IR: I'm reasonably sure the constant folding produces a proper float (). But perhaps the non-zero bits in its significand are in bit positions 32? Then the bitcast code would silently drop them.
Just remembered I wanted to look at assembly or machine code to see what the LLVM lowers to and show that it's buggy in LLVM even outside of constant-folded bitcasts.
Also isn't a +Infinity, showing the had already truncated the significand?
. And I just realized that while the high half of is a f32 NaN, the whole bit string as an f64 is in fact a NaN and setting just one bit more (e.g. ) does make llc (and presumably bitcast folding) produce (an f32 NaN). So I guess that I interpreted incorrectly and the fptrunc folding is at fault after all.
So... what does this mean? Is it an LLVM bug, and do we have enough information to report it upstream?
Yes, either truncation needs to result in a non- (e.g. becoming when losing lower bits could be "rounded up" by setting it to ), or extracting the IEEE representation from should handle the situation by setting some bit. cc (I don't know who does upstream LLVM bug reports nowadays most often)
actually I misremembered what this bug is about. This is not just "surprising NaN payload", indeed the result here is not a NaN when it should be. So that is quite clearly a bug in LLVM's APfloat, or in the Rust port of it (but we seem confident the problem is upstream). It would be great if we could report this against LLVM, but I have no idea how to reproduce the problem with LLVM. Do we need to write a C++ program using APfloat, or can we somehow make this happen just with the right LLVM IR? was previously posted as an example, does this show an incorrect compilation? These bit patterns mean nothing to me.^^
Wow! That's extremely wrong! It turns a NaN into positive infinity! Poking it gives a bit more insight into the issue: shows that all bits in the NaN payload below the 29th bit are truncated here. Mercifully, I can repro this in rustcapfloat, which is easier for me to experiment with than LLVM's (okay, I also remember what a headache it was trying to make changes to LLVM in the past, and it's now not something I'm interested in doing in my spare time) That is, it reports has , but then turns it into . Doing some further digging shows points me to , where we call with a number that comes from the difference between (bits of significand) of the source and target, e.g. 53 - 22, or 29 (which all-but-confirms that this is the issue). (The branch where there's the sig::shiftleft is wrong too, FWIW). It's also pretty wrong — IEEE wants you to truncate the payload here, not shift it out. e.g. I think what you want to do is something like (this code intentionally doesn't compile, and is assuming is the target type and that things are beautifully simple enough that there's just a function which returns something I can bitand...): That said, this is possibly hopelessly wrong? I don't thing so but I don't have a copy of IEEE754 around to verify. ... ... Okay I tried to make it compile, and if you drop this beast in before the shifts (e.g. line 1488 as of commit ) the tests pass (Sorry, I foolishly did this in a github download of rustcapfloat, since my rustc is in the middle of other things, and so I can't easily just give you a patch) That said it could still have other issues. And the fix could be extremely wrong for other reasons, it's the result of not-very-long spent debugging. Someone who understands the code better should audit it for this issue ( It says you wrote ). Ditto for LLVM's version which I can hardly follow since my C++ is so rusty. That said, LLVM is a popular enough project that someone hopefully could take it from here? E.g. Turning a NaN into an infinity is extremely bad — obviously so. Masking away the bottom bits like this is an obvious bug (nothing anywhere does that), and so even if they don't care about preserving NaNs specifically I suspect they'd want to fix this. Edit: I wrote this without carefully reading the rest of this issue. I think you uncovered some of this? Maybe? I don't know. Maybe this helped, sorry if not.
Yeah that sounds wrong. :D I'm afraid I cannot comment on the internals of apfloat that you are getting into for the rest of your post. That stuff is way beyond me.^^ I understand you won't work on fixing this in LLVM, but could you make this a bugreport for them, in their bugzilla? I feel a bit awkward making a bugreport that basically says "look I don't know what I am talking about but I have it on good authority that what LLVM is doing is wrong". Would be better if someone who knows what they are talking about does that I think. ;) Chances are, they'll have someone who can fix it.
says I'll send them an email, but...
Argh. :/ I think this worked fine for me though. If they don't respond in a few days, we can also use me as a proxy.^^
That sounds fine. In the meantime it maybe be good for someone more familiar with the rustc_apfloat code to take a look at what I wrote anyway...
There was already a bug, but I a comment for it:
There's a fix on the LLVM side now, somewhere in -- there are multiple reviews, we should figure out which one actually landed. Anyone up for porting this back to the Rust apfloat?
I guess would be the page to check for what happened in apfloat upstream.
Done:
The fix on the LLVM side is the minimal possible fix to avoid the linked miscompilation here: It doesn't fix this bug in the general case.
is a more correct fix. But note that it's not just the change to APFloat that makes it correct (in fact, that change alone is arguably wrong), but at usage sites changing things to be (for example): I think we should probably do this inside our function, otherwise it would be incorrect too. This is unfortunate as it causes more divergence to upstream APFloat
are you referring to this segment of your comment above? Can you quote the part of the IEEE 754 standard which mandates this? Or alternatively, come up with an example like the one at the top where there is a mismatch between what happens at runtime vs during miri evaluation? Apparently hardware implementations shift out payloads as well: prints:
Larger example that compares runtime and const eval (as of nightly master): prints: Edit: apparently on the hardware it always unconditionally sets the highest bit of the mantissa when a NaN truncation is performed to work around the issue. Edit2: which is nothing other than turning the sNaN into a qNaN.
IEEE754-2019 6.2.3 (NaN Propagation) states that This seems impossible if the implementation shifts the payload out. But I guess this only applies to qNaN, although in my testing earlier it seemed to happen on sNaN on my machines. Anyway, I'm a bit busy at the moment, or I'd dig further into this.
I knew there were two patches but I have no idea which one landed... so far the plan was to only port things that have landed on the LLVM side. If there is still a bug left there, that seems worth reporting?
If the implementation shifts to the left on conversion to the wider format and back to the right on conversion to the narrower format, then the NaN payload will be the same. So I think that shifting is conformant with that rule of the standard. Otherwise hardware would be nonconformant as well. But maybe there's still some rule in the standard that LLVM apfloat violates.
Hmm, fair enough. Unfortunately, I don't think I'm going to have time to dig further into this for at least another week, but sounds good to me. Sorry for any trouble.
No trouble caused, thanks for looking into this. :)
Yes your comments were very helpful. I wouldn't have found or thought of looking for that LLVM MR for example.
This issue will be fixed by but that there are some other interesting test-cases that would not have been fixed by a more naive approach... would be great if we could get those testcases into our test suite as well :)

assert_eq!(4294967295.0, test.to_f64()); assert!(!loses_info); <del> let test = Single::snan(None); let x87_snan = X87DoubleExtended::snan(None); let test: X87DoubleExtended = test.convert(&mut loses_info).value; assert!(test.bitwise_eq(x87_snan)); assert!(!loses_info); </del> let test = Single::qnan(None); let x87_qnan = X87DoubleExtended::qnan(None); let test: X87DoubleExtended = test.convert(&mut loses_info).value; assert!(test.bitwise_eq(x87_qnan)); assert!(!loses_info); <del> let test = X87DoubleExtended::snan(None); let test: X87DoubleExtended = test.convert(&mut loses_info).value; assert!(test.bitwise_eq(x87_snan)); </del> <ins> let test = Single::snan(None); let sta = test.convert(&mut loses_info); let test: X87DoubleExtended = sta.value; assert!(test.is_nan()); assert!(!test.is_signaling()); </ins> assert!(!loses_info); <ins> assert_eq!(sta.status, Status::INVALID_OP); </ins> let test = X87DoubleExtended::qnan(None); let test: X87DoubleExtended = test.convert(&mut loses_info).value; assert!(test.bitwise_eq(x87_qnan)); assert!(!loses_info); <ins> let test = X87DoubleExtended::snan(None); let sta = test.convert(&mut loses_info); let test: X87DoubleExtended = sta.value; assert!(test.is_nan()); assert!(!test.is_signaling()); assert!(!loses_info); assert_eq!(sta.status, Status::INVALID_OP); </ins> } #[test]


Question:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: This runs correctly (i.e. doesn't assert) when run with rust nightly, but fails at when run with miri on nightly (2020-02-20). It seems like miri just truncated the f64 to get the f32 and therefore converted the nan2 to a floating point zero instead of a floating point NaN
(Miri-the-tool has its own bugtracker at , where I see things earlier than when they are burried here.) Cc this could also be an apfloat issue as that's what Miri uses to implement casts. I don't think we are doing any truncation . Would be interesting to see the bit patterns involved.
for returns . So, this doesn't look like just a truncated to me, it looks like apfloat did something but that something is not correct (or at least, not nan-preserving -- I am not sure if that is a guarantee).
cc
Sorry, I should have said truncated the fraction there. The is the floating point exponent being set to all ones, the (plus the empty bottom 3 bits in the 8) is a truncation of the original fraction in the f64. By removing all the non-zero bits in the fraction it converted the NaN to an infinity. For reference for returns where the (plus the empty bottom 3 bits in the 8) is a truncation of the original fraction from 52 to 23 bits Note that the normal Rust compiler seems to always set the MSB in the fraction of a NaN during its conversion to avoid this problem. There is and is
Assuming that f64-to-f32 on NaN has fully defined semantics, we should probably have a test asserting these exact bit patterns for Miri. But what you wrote makes it sound even more like the bug is in apfloat, and not in the Miri code that feeds data to/from apfloat. FWIW, the float casting code is .
Yes, it does sound to me like an apfloat issue rather than something unique in Miri. Reading that casting method I can't see anything that is special casing the fraction truncation for NaNs, only for an 80bit extended precision type that has different NaN semantics. Sorry, I've not dealt with the bug workflow on Rust before - is it possible to move this bug to apfloat? Would you like me to create a separate bug on apfloat?
apfloat does not have a separate issue tracker, no need to move anything. However, if I understood correctly then apfloat is a direct Rust port of LLVM's apfloat -- so likely they have the same bug, and a fix would have to happen upstream as well.
Yes, rustcapfloat is a port of LLVM's APFloat, but (also in older versions, back to before started the Rust port). Note that the MSB of the significand is set, so this is indeed a NaN. It seems LLVM does not have the same bug. Something strange is up.
Hm, that's still not the same as the that we see at run-time though?
I think the LLVM C++ code doing the same cast is .
Sure, but that's intentional. Optimizations need to preserve whether something is a NaN but (by default) the payload bits, quiet/signaling distinction and sign bit are not generally preserved or guaranteed to match between compile time evaluation and run time evaluation.
So the semantics would be something like "if the result is a NaN, non-deterministically pick any legal NaN representation"?
That sounds about right. Kind of off-topic here, though -- if you want to discuss further, we have
The category should still be , but it looks like we don't enforce the significand is non-: <hr/ Wait, I just looked at your link and LLVM prints - that's a bitpattern, not a , lol. But with a to integer, it matches : (if you hover over the decimal value, helpfully shows it as hex)
Note that converting floats to double bit patterns happens when printing textual IR: I'm reasonably sure the constant folding produces a proper float (). But perhaps the non-zero bits in its significand are in bit positions 32? Then the bitcast code would silently drop them.
Just remembered I wanted to look at assembly or machine code to see what the LLVM lowers to and show that it's buggy in LLVM even outside of constant-folded bitcasts.
Also isn't a +Infinity, showing the had already truncated the significand?
. And I just realized that while the high half of is a f32 NaN, the whole bit string as an f64 is in fact a NaN and setting just one bit more (e.g. ) does make llc (and presumably bitcast folding) produce (an f32 NaN). So I guess that I interpreted incorrectly and the fptrunc folding is at fault after all.
So... what does this mean? Is it an LLVM bug, and do we have enough information to report it upstream?
Yes, either truncation needs to result in a non- (e.g. becoming when losing lower bits could be "rounded up" by setting it to ), or extracting the IEEE representation from should handle the situation by setting some bit. cc (I don't know who does upstream LLVM bug reports nowadays most often)
actually I misremembered what this bug is about. This is not just "surprising NaN payload", indeed the result here is not a NaN when it should be. So that is quite clearly a bug in LLVM's APfloat, or in the Rust port of it (but we seem confident the problem is upstream). It would be great if we could report this against LLVM, but I have no idea how to reproduce the problem with LLVM. Do we need to write a C++ program using APfloat, or can we somehow make this happen just with the right LLVM IR? was previously posted as an example, does this show an incorrect compilation? These bit patterns mean nothing to me.^^
Wow! That's extremely wrong! It turns a NaN into positive infinity! Poking it gives a bit more insight into the issue: shows that all bits in the NaN payload below the 29th bit are truncated here. Mercifully, I can repro this in rustcapfloat, which is easier for me to experiment with than LLVM's (okay, I also remember what a headache it was trying to make changes to LLVM in the past, and it's now not something I'm interested in doing in my spare time) That is, it reports has , but then turns it into . Doing some further digging shows points me to , where we call with a number that comes from the difference between (bits of significand) of the source and target, e.g. 53 - 22, or 29 (which all-but-confirms that this is the issue). (The branch where there's the sig::shiftleft is wrong too, FWIW). It's also pretty wrong — IEEE wants you to truncate the payload here, not shift it out. e.g. I think what you want to do is something like (this code intentionally doesn't compile, and is assuming is the target type and that things are beautifully simple enough that there's just a function which returns something I can bitand...): That said, this is possibly hopelessly wrong? I don't thing so but I don't have a copy of IEEE754 around to verify. ... ... Okay I tried to make it compile, and if you drop this beast in before the shifts (e.g. line 1488 as of commit ) the tests pass (Sorry, I foolishly did this in a github download of rustcapfloat, since my rustc is in the middle of other things, and so I can't easily just give you a patch) That said it could still have other issues. And the fix could be extremely wrong for other reasons, it's the result of not-very-long spent debugging. Someone who understands the code better should audit it for this issue ( It says you wrote ). Ditto for LLVM's version which I can hardly follow since my C++ is so rusty. That said, LLVM is a popular enough project that someone hopefully could take it from here? E.g. Turning a NaN into an infinity is extremely bad — obviously so. Masking away the bottom bits like this is an obvious bug (nothing anywhere does that), and so even if they don't care about preserving NaNs specifically I suspect they'd want to fix this. Edit: I wrote this without carefully reading the rest of this issue. I think you uncovered some of this? Maybe? I don't know. Maybe this helped, sorry if not.
Yeah that sounds wrong. :D I'm afraid I cannot comment on the internals of apfloat that you are getting into for the rest of your post. That stuff is way beyond me.^^ I understand you won't work on fixing this in LLVM, but could you make this a bugreport for them, in their bugzilla? I feel a bit awkward making a bugreport that basically says "look I don't know what I am talking about but I have it on good authority that what LLVM is doing is wrong". Would be better if someone who knows what they are talking about does that I think. ;) Chances are, they'll have someone who can fix it.
says I'll send them an email, but...
Argh. :/ I think this worked fine for me though. If they don't respond in a few days, we can also use me as a proxy.^^
That sounds fine. In the meantime it maybe be good for someone more familiar with the rustc_apfloat code to take a look at what I wrote anyway...
There was already a bug, but I a comment for it:
There's a fix on the LLVM side now, somewhere in -- there are multiple reviews, we should figure out which one actually landed. Anyone up for porting this back to the Rust apfloat?
I guess would be the page to check for what happened in apfloat upstream.
Done:
The fix on the LLVM side is the minimal possible fix to avoid the linked miscompilation here: It doesn't fix this bug in the general case.
is a more correct fix. But note that it's not just the change to APFloat that makes it correct (in fact, that change alone is arguably wrong), but at usage sites changing things to be (for example): I think we should probably do this inside our function, otherwise it would be incorrect too. This is unfortunate as it causes more divergence to upstream APFloat
are you referring to this segment of your comment above? Can you quote the part of the IEEE 754 standard which mandates this? Or alternatively, come up with an example like the one at the top where there is a mismatch between what happens at runtime vs during miri evaluation? Apparently hardware implementations shift out payloads as well: prints:
Larger example that compares runtime and const eval (as of nightly master): prints: Edit: apparently on the hardware it always unconditionally sets the highest bit of the mantissa when a NaN truncation is performed to work around the issue. Edit2: which is nothing other than turning the sNaN into a qNaN.
IEEE754-2019 6.2.3 (NaN Propagation) states that This seems impossible if the implementation shifts the payload out. But I guess this only applies to qNaN, although in my testing earlier it seemed to happen on sNaN on my machines. Anyway, I'm a bit busy at the moment, or I'd dig further into this.
I knew there were two patches but I have no idea which one landed... so far the plan was to only port things that have landed on the LLVM side. If there is still a bug left there, that seems worth reporting?
If the implementation shifts to the left on conversion to the wider format and back to the right on conversion to the narrower format, then the NaN payload will be the same. So I think that shifting is conformant with that rule of the standard. Otherwise hardware would be nonconformant as well. But maybe there's still some rule in the standard that LLVM apfloat violates.
Hmm, fair enough. Unfortunately, I don't think I'm going to have time to dig further into this for at least another week, but sounds good to me. Sorry for any trouble.
No trouble caused, thanks for looking into this. :)
Yes your comments were very helpful. I wouldn't have found or thought of looking for that LLVM MR for example.
This issue will be fixed by but that there are some other interesting test-cases that would not have been fixed by a more naive approach... would be great if we could get those testcases into our test suite as well :)

<ins> // run-pass #![feature(const_fn_transmute)] const fn make_nans() -> (f64, f64, f32, f32) { let nan1: f64 = unsafe { std::mem::transmute(0x7FF0_0001_0000_0001u64) }; let nan2: f64 = unsafe { std::mem::transmute(0x7FF0_0000_0000_0001u64) }; let nan1_32 = nan1 as f32; let nan2_32 = nan2 as f32; (nan1, nan2, nan1_32, nan2_32) } static NANS: (f64, f64, f32, f32) = make_nans(); fn main() { let (nan1, nan2, nan1_32, nan2_32) = NANS; assert!(nan1.is_nan()); assert!(nan2.is_nan()); assert!(nan1_32.is_nan()); assert!(nan2_32.is_nan()); } </ins>


Question: Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool clippy-driver no longer builds. A follow-up PR to the repository is needed to fix the fallout. cc do you think you would have time to do the follow-up work? If so, that would be great! And nominating for compiler team prioritization.

<del> Subproject commit 23549a8c362a403026432f65a6cb398cb10d44b7 </del> <ins> Subproject commit d8e6e4cfcd83d555bd7717ea24224b777ed75773 </ins>


Question:
The following code causes an ICE: As far as I can tell: Any number of characters can be inserted between and and the error will still happen. can be replaced with any unicode character and the error will still happen. No escape sequences other than cause the error. The error is reproducible on the stable or nightly compiler at outputs the following on my machine: <details<summary<strongBacktrace</strong</summary<p</p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Godbolt says this regressed in 1.29.0.
pre-triage: this doesn't seem to be very important but would be of course nice to fix. Tagging it as .
claim Time to try an easy issue
I tried a few things and I will document what I found, so hopefully this can jumpstart some ideas: I removed the assert that was initiating the panic, and I see: Notice the OBOE on the positioning of the So, I tried different escape sequences, and got mildly confusing results Here we have an off by two error in the other direction Now, I tried the unicode escape that should (assuming I didn't misremember something) be equivalent to r: And that seems to work just fine. So, I suspect we somehow interpret escape sequences as the character they represent, but not other times. If this causes us to be offcut in the middle of a UTF-8 multibyte sequence, then we ICE, but there are cases where the will end up in the wrong spot even if we don't ICE. EDIT: a few more observations Turns out the OBOE can be seen with just old fashioned ASCII (no multi-byte utf-8 characters needed): In addition, springboarding off what found, going from 1.28.0 to.1.29.0 the ` in the error messages got a lot more specific, e.g. in 1.28.0 we see:
After a bunch of debug prints, and counting bytes, I am now convinced that the code in the function that is panicing, is not the problem. The inputs to that function are faulty. In particular the is OBO, potentially putting it in the middle of a UTF-8 sequence. I chased down the source of the bad data, and I think it is from in . The code appears to be computing the difference between how many bytes it takes in the source to represent an escape sequence vs how many the interpreted value takes. There are a number of match statements that seem to leave out. Adding them seems to fix the original problem. In addition the code for dealing with doesn't seem to take into account the varying number bytes the UTF-8 value will take. This seems to line up with what I was seeing. Also, I suspect the escape might need some tweaking for code points = 0x80 I forked and branched with what I have done so far:
unclaim I've been too distracted, and it seems has done most of the bug chasing
claim I'd like to take this up if this is still open.
It is open, go ahead :)
, FYI what is in my branch: seems to solve the r issue just fine, but does not address the u{} issue at all. My quick dirty attempts at that failed. You are welcome to leverage off of my stuff if you are taking this over. This has just been a fun distraction when I have time, but I can't reliably dedicate time to it. Also, I have not addressed unit tests at all yet. Also, I am beginning to suspect there may be a larger (yet subtle) underlying confusion somewhere else in the code about bytes vs characters. The findskips function I just updated has comments talking about characters, but data derived from what it generates is later fed into (in ) where we are dealing with bytes. So, perhaps there is a simplification if we can always deal with either just one of bytes or chars (and avoid any conversions). Or, on the other hand there may be a lot of comments that could use clarification.
I have also found that this off by n error will occur with any unicode character whose display width is non-standardized and non one. I have not yet checked the source to try to fix the issue, but I have worked with in my own code, and as it is a compiler dependency is probably the source of this problem. The largest issue with this is as far as I could find there is no standardization for the display width of these characters.
Hi, are you still working on this issue
release-assignment

(' ' | 'n' | 't', _) if eat_ws => { skips.push(pos); } <del> ('', Some((next_pos, 'n' | 't' | '0' | '' | ''' | '"'))) => { </del> <ins> ('', Some((next_pos, 'n' | 't' | 'r' | '0' | '' | ''' | '"'))) => { </ins> skips.push(*next_pos); let _ = s.next(); }


Question:
The following code causes an ICE: As far as I can tell: Any number of characters can be inserted between and and the error will still happen. can be replaced with any unicode character and the error will still happen. No escape sequences other than cause the error. The error is reproducible on the stable or nightly compiler at outputs the following on my machine: <details<summary<strongBacktrace</strong</summary<p</p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Godbolt says this regressed in 1.29.0.
pre-triage: this doesn't seem to be very important but would be of course nice to fix. Tagging it as .
claim Time to try an easy issue
I tried a few things and I will document what I found, so hopefully this can jumpstart some ideas: I removed the assert that was initiating the panic, and I see: Notice the OBOE on the positioning of the So, I tried different escape sequences, and got mildly confusing results Here we have an off by two error in the other direction Now, I tried the unicode escape that should (assuming I didn't misremember something) be equivalent to r: And that seems to work just fine. So, I suspect we somehow interpret escape sequences as the character they represent, but not other times. If this causes us to be offcut in the middle of a UTF-8 multibyte sequence, then we ICE, but there are cases where the will end up in the wrong spot even if we don't ICE. EDIT: a few more observations Turns out the OBOE can be seen with just old fashioned ASCII (no multi-byte utf-8 characters needed): In addition, springboarding off what found, going from 1.28.0 to.1.29.0 the ` in the error messages got a lot more specific, e.g. in 1.28.0 we see:
After a bunch of debug prints, and counting bytes, I am now convinced that the code in the function that is panicing, is not the problem. The inputs to that function are faulty. In particular the is OBO, potentially putting it in the middle of a UTF-8 sequence. I chased down the source of the bad data, and I think it is from in . The code appears to be computing the difference between how many bytes it takes in the source to represent an escape sequence vs how many the interpreted value takes. There are a number of match statements that seem to leave out. Adding them seems to fix the original problem. In addition the code for dealing with doesn't seem to take into account the varying number bytes the UTF-8 value will take. This seems to line up with what I was seeing. Also, I suspect the escape might need some tweaking for code points = 0x80 I forked and branched with what I have done so far:
unclaim I've been too distracted, and it seems has done most of the bug chasing
claim I'd like to take this up if this is still open.
It is open, go ahead :)
, FYI what is in my branch: seems to solve the r issue just fine, but does not address the u{} issue at all. My quick dirty attempts at that failed. You are welcome to leverage off of my stuff if you are taking this over. This has just been a fun distraction when I have time, but I can't reliably dedicate time to it. Also, I have not addressed unit tests at all yet. Also, I am beginning to suspect there may be a larger (yet subtle) underlying confusion somewhere else in the code about bytes vs characters. The findskips function I just updated has comments talking about characters, but data derived from what it generates is later fed into (in ) where we are dealing with bytes. So, perhaps there is a simplification if we can always deal with either just one of bytes or chars (and avoid any conversions). Or, on the other hand there may be a lot of comments that could use clarification.
I have also found that this off by n error will occur with any unicode character whose display width is non-standardized and non one. I have not yet checked the source to try to fix the issue, but I have worked with in my own code, and as it is a compiler dependency is probably the source of this problem. The largest issue with this is as far as I could find there is no standardization for the display width of these characters.
Hi, are you still working on this issue
release-assignment

<ins> // Test that multi-byte unicode characters with missing parameters do not ICE. fn main() { println!("r¡{}") //~^ ERROR 1 positional argument in format string } </ins>


Question:
The following code causes an ICE: As far as I can tell: Any number of characters can be inserted between and and the error will still happen. can be replaced with any unicode character and the error will still happen. No escape sequences other than cause the error. The error is reproducible on the stable or nightly compiler at outputs the following on my machine: <details<summary<strongBacktrace</strong</summary<p</p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Godbolt says this regressed in 1.29.0.
pre-triage: this doesn't seem to be very important but would be of course nice to fix. Tagging it as .
claim Time to try an easy issue
I tried a few things and I will document what I found, so hopefully this can jumpstart some ideas: I removed the assert that was initiating the panic, and I see: Notice the OBOE on the positioning of the So, I tried different escape sequences, and got mildly confusing results Here we have an off by two error in the other direction Now, I tried the unicode escape that should (assuming I didn't misremember something) be equivalent to r: And that seems to work just fine. So, I suspect we somehow interpret escape sequences as the character they represent, but not other times. If this causes us to be offcut in the middle of a UTF-8 multibyte sequence, then we ICE, but there are cases where the will end up in the wrong spot even if we don't ICE. EDIT: a few more observations Turns out the OBOE can be seen with just old fashioned ASCII (no multi-byte utf-8 characters needed): In addition, springboarding off what found, going from 1.28.0 to.1.29.0 the ` in the error messages got a lot more specific, e.g. in 1.28.0 we see:
After a bunch of debug prints, and counting bytes, I am now convinced that the code in the function that is panicing, is not the problem. The inputs to that function are faulty. In particular the is OBO, potentially putting it in the middle of a UTF-8 sequence. I chased down the source of the bad data, and I think it is from in . The code appears to be computing the difference between how many bytes it takes in the source to represent an escape sequence vs how many the interpreted value takes. There are a number of match statements that seem to leave out. Adding them seems to fix the original problem. In addition the code for dealing with doesn't seem to take into account the varying number bytes the UTF-8 value will take. This seems to line up with what I was seeing. Also, I suspect the escape might need some tweaking for code points = 0x80 I forked and branched with what I have done so far:
unclaim I've been too distracted, and it seems has done most of the bug chasing
claim I'd like to take this up if this is still open.
It is open, go ahead :)
, FYI what is in my branch: seems to solve the r issue just fine, but does not address the u{} issue at all. My quick dirty attempts at that failed. You are welcome to leverage off of my stuff if you are taking this over. This has just been a fun distraction when I have time, but I can't reliably dedicate time to it. Also, I have not addressed unit tests at all yet. Also, I am beginning to suspect there may be a larger (yet subtle) underlying confusion somewhere else in the code about bytes vs characters. The findskips function I just updated has comments talking about characters, but data derived from what it generates is later fed into (in ) where we are dealing with bytes. So, perhaps there is a simplification if we can always deal with either just one of bytes or chars (and avoid any conversions). Or, on the other hand there may be a lot of comments that could use clarification.
I have also found that this off by n error will occur with any unicode character whose display width is non-standardized and non one. I have not yet checked the source to try to fix the issue, but I have worked with in my own code, and as it is a compiler dependency is probably the source of this problem. The largest issue with this is as far as I could find there is no standardization for the display width of these characters.
Hi, are you still working on this issue
release-assignment

<ins> error: 1 positional argument in format string, but no arguments were given --> $DIR/issue-70381.rs:4:16 | LL |   println!("r¡{}") |                ^^ error: aborting due to previous error </ins>


Question:
https://crater- cc
Possibly accidentally injected by Would be good to find out why this is happening, so let's ping cleanup and see if we can bisect / shrink the problem down to something usable for finding a fix.
ping cleanup
Hey Cleanup Crew ICE-breakers! This bug has been identified as a good "Cleanup ICE-breaking candidate". In case it's useful, here are some [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 [instructions]: https://rustc-dev- cc
Failed to confirm that is the cause: Seems like it regressed prior to
For code I used:
modify labels: -E-needs-bisection
Reduced example: () Errors:
Split the macro in two parts to make it easier to follow, and removed the special lifetime : () Error: I think we can now modify labels: -E-needs-mcve
I believe that the most probable culprit is , cc
is indeed the culprit, I can reproduce the bug on
This was . Assigning for now until we have a better understanding of what's going on.
Fixed in

/// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { match *nt { <del> token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) => false, </del> <ins> token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_) => false, </ins> _ => true, } }


Question:
https://crater- cc
Possibly accidentally injected by Would be good to find out why this is happening, so let's ping cleanup and see if we can bisect / shrink the problem down to something usable for finding a fix.
ping cleanup
Hey Cleanup Crew ICE-breakers! This bug has been identified as a good "Cleanup ICE-breaking candidate". In case it's useful, here are some [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 [instructions]: https://rustc-dev- cc
Failed to confirm that is the cause: Seems like it regressed prior to
For code I used:
modify labels: -E-needs-bisection
Reduced example: () Errors:
Split the macro in two parts to make it easier to follow, and removed the special lifetime : () Error: I think we can now modify labels: -E-needs-mcve
I believe that the most probable culprit is , cc
is indeed the culprit, I can reproduce the bug on
This was . Assigning for now until we have a better understanding of what's going on.
Fixed in

<ins> // check-pass macro_rules! foo { ($(: $p:path)? $(: $l:lifetime)? ) => { bar! {$(: $p)? $(: $l)? } }; } macro_rules! bar { ($(: $p:path)? $(: $l:lifetime)? ) => {}; } foo! {: 'a } fn main() {} </ins>


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

}; let sp = cx.with_def_site_ctxt(sp); <del> let e = match env::var(&var.as_str()) { Err(..) => { </del> <ins> let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern); cx.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value)); let e = match value { None => { </ins> let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); cx.expr_path(cx.path_all( sp,


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

))], )) } <del> Ok(s) => cx.expr_call_global( </del> <ins> Some(value) => cx.expr_call_global( </ins> sp, cx.std_path(&[sym::option, sym::Option, sym::Some]), <del> vec![cx.expr_str(sp, Symbol::intern(&s))], </del> <ins> vec![cx.expr_str(sp, value)], </ins> ), }; MacEager::expr(e)


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

} let sp = cx.with_def_site_ctxt(sp); <del> let e = match env::var(&*var.as_str()) { Err(_) => { </del> <ins> let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern); cx.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { </ins> cx.span_err(sp, &msg.as_str()); return DummyResult::any(sp); } <del> Ok(s) => cx.expr_str(sp, Symbol::intern(&s)), </del> <ins> Some(value) => cx.expr_str(sp, value), </ins> }; MacEager::expr(e) }


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] <ins> #![feature(inner_deref)] </ins> #![feature(nll)] #![feature(or_patterns)] #![feature(proc_macro_internals)]


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

filename.to_string().replace(" ", " ") } <ins> // Makefile comments only need escaping newlines and ``. // The result can be unescaped by anything that can unescape `escape_default` and friends. fn escape_dep_env(symbol: Symbol) -> String { let s = symbol.as_str(); let mut escaped = String::with_capacity(s.len()); for c in s.chars() { match c { 'n' => escaped.push_str(r"n"), 'r' => escaped.push_str(r"r"), '' => escaped.push_str(r""), _ => escaped.push(c), } } escaped } </ins> fn write_out_deps( sess: &Session, boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

for path in files { writeln!(file, "{}:", path)?; } <ins> // Emit special comments with information about accessed environment variables. let env_depinfo = sess.parse_sess.env_depinfo.borrow(); if !env_depinfo.is_empty() { let mut envs: Vec<_> = env_depinfo .iter() .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env))) .collect(); envs.sort_unstable(); writeln!(file)?; for (k, v) in envs { write!(file, "# env-dep:{}", k)?; if let Some(v) = v { write!(file, "={}", v)?; } writeln!(file)?; } } </ins> Ok(()) })();


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

pub symbol_gallery: SymbolGallery, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. pub reached_eof: Lock<bool>, <ins> /// Environment variables accessed during the build and their values when they exist. pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>, </ins> } impl ParseSess {


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), reached_eof: Lock::new(false), <ins> env_depinfo: Default::default(), </ins> } }


Question:
This is still in 's build script: But the use site has been moved here: This means that won't be rebuilt when that env var changes. For the record, I haven't seen a bug from this, was just curious where may be used and spotted the mismatch. cc
Found another one: is used in but it's still mentioned by . cc Could we automate ensuring this? e.g. by searching for in tidy.
Yeah, we can try I guess. Not sure :) Maybe the right solution is that Cargo would, other than some whitelist, remove unknown variables from rustc's environment -- and the whitelist can be expanded via the build script env-tracking.
hmm I wonder if abusing the file format (from ) or encoding this extra info in a comment, would be a good idea.
You mean such that if you use we automatically tell Cargo to rebuild on changes? (That's ). But yeah, I think that would be good. Ideally this would be "well-integrated" vs. the current state of everyone having to remember to do it.

<ins> -include ../../run-make-fulldeps/tools.mk all: EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs $(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d $(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d $(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d $(CGREP) "# env-dep:ESCAPEnESCAPE" < $(TMPDIR)/main.d </ins>