Question: Note that the `target_env = "p1"` condition first appeared in Rust 1.80. Prior to Rust 1.80 the `target_env` condition was not set. <ins> ## Enabled WebAssembly features The default set of WebAssembly features enabled for compilation is currently the same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the documentation there for more information. </ins>

<!-- 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 to build a wasm binary with MVP opcode only, so I disabled the features: I expected to see no in the wasm binary. Instead, this happened: <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summaryBacktrace</summary<p</p</details
You can not deactivate default features, because std is prebuilt. You need to build std yourself. Also these features are considered the default by LLVM ever since the recent upgrade to LLVM 16: This should possibly be mentioned in the Rust 1.70 release notes though?
cc to confirm that we're fine with inheriting this change to default target features in Rust.
More context for this change can be found in these locations: - discussion about enabling new features in both Emscripten and LLVM. - the original LLVM patch for this - more follow-up discussion on LLVM In that sense this is an expected change, but at the same time the change was made with the expectation that most users are running on an engine that implements sign-extension. could you expand a bit more on your motivation for excluding these sign-extension instructions? I do agree, though, that this should be mentioned in the detailed release notes. It's unfortunately a bit opaque since not all users of wasm are intimately familiar with proposals and whether or not engines support them, but it's a change nonetheless worth mentioning.
I have tried to use , still not work: Our blockchain platform has used Wasm as a virtual machine running smart contracts and has been running steadily for many years. The MVP opcodes is fully sufficient for our use case. I hope there are ways to turn off these default extension features to avoid frequent upgrades every time a new feature is introduced.
Could you share the code used to reproduce this? These upgrades will not be frequent. This is the first time it's changed in 5 years.


Question: Note that the `target_env = "p1"` condition first appeared in Rust 1.80. Prior to Rust 1.80 the `target_env` condition was not set. <ins> ## Enabled WebAssembly features The default set of WebAssembly features enabled for compilation is currently the same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the documentation there for more information. </ins>

The use case I have for wanting to build without these extensions isn't critical (servers for a game which don't support the extensions in the old version of nodejs they're running), but a way to successfully disable them to be able to build for such environments would be appreciated!
It would be helpful to have a reproduction of this to run to test out fixes. I tested something locally and was sufficient to disable sign extension instructions. I don't know why isn't working and that may be an LLVM bug. I can't confirm whether this works for others though without a means of reproduction.
I just tried the following: compiled with: to make sure std being precompiled isn't causing problems, and it totally still contains the sign-ext instructions: So you are right, this is some sort of LLVM bug.
Confirming that results in a file without the sign-ext opcodes, while does not, in my testing as well.
would you perhaps know more about ? I would expect that with on the function then even without sign-extension instructions wouldn't get generated, but I'm not sure.
I wonder if this is a consequence of It looks like that might be unioning the module-level features along with the per-function features to form the effective feature set to use.
It can also be reproduced with:
FWIW, the above flags did not work for me with - the resulting binary still had sign-extension opcodes (namely ) - but this served as a workaround (): Command: ^ With the wasm-opt pass, sign-extension ops were gone; without the pass, still there. From the thread above, it sounds like those flags work for some people but not for others. My use case is (was) supporting old Apple devices stuck on iOS 12 and thus Safari 12. Now past this, the binary can load, but performance is enough of a problem to suggest dropping support anyway.
A slightly related issue is that the WebAssembly extensions used by default by the Rust compiler are not documented (besides in the change log, but new users won't look at it), I opened a specific issue for that () and just want to link it here.
As a heads up I've documentation about features to which I've currently got as flagged to close this issue. The documented solution for targetting MVP wasm is: which should solve the original OP of this issue.


Question: Note that the `target_env = "p1"` condition first appeared in Rust 1.80. Prior to Rust 1.80 the `target_env` condition was not set. <ins> ## Enabled WebAssembly features The default set of WebAssembly features enabled for compilation is currently the same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the documentation there for more information. </ins>

Other solutions in this issue such as using or that in conjunction with or others don't work for one reason or another. Using the target-cpu, however, plus recompiling the standard library with , does work.


Question: /// ``` /// /// ```rust <del> /// #![feature(fmt_as_str)] /// </del> /// assert_eq!(format_args!("hello").as_str(), Some("hello")); /// assert_eq!(format_args!("").as_str(), Some("")); /// assert_eq!(format_args!("{}", 1).as_str(), None); /// ``` <del> #[unstable(feature = "fmt_as_str", issue = "74442")] </del> <ins> #[stable(feature = "fmt_as_str", since = "1.52.0")] </ins> #[inline] pub fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) {

Tracking issue for (), gated by .
I don't quite understand fmt internals, but Make fmt::Arguments::asstr() return a 'static str. seems unnecessarily restrictive. And it breaks which depends on hidden apis e.g. Arguments::newv1
cannot be generated at runtime because it cannot safely be done. So returns makes sense.
I'd like to be able to use this in the log crate to correctly implement a codegen optimization that doesn't really work otherwise: fcp merge
Team member has proposed to merge this. The next step is review by the rest of the tagged team members: [x] [x] [x] [x] [x] [x] [ ] No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
This SGTM. One question though. Are we sure that the bound will always be correct here?
is the result from parsing a formatting string at compile time. In the future, this might not always be a literal but might be a too. But a non-static/constant format string will be a very different beast.
That's what I figured, but wanted to make sure it was explicitly addressed.
:bell: This is now entering its final comment period, as per the . :bell:
Does this make any guarantees about when is returned? I've been interested in redoing the macro to be much more intelligent (and thus performant), but obviously don't know when it's possible to return something statically knowable.
Currently it returns Some for only. But my plan is to extend that also to , , and possibly also things like , etc. See
Yeah, I see that from looking at the source code. I was more inquiring about whether it would be considered breaking to go from returning to returning . I don't suspect anything would be out-of-reach when reimplementing the macro, but you never know.
The final comment period, with a disposition to merge, as per the , is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC will be merged soon.


Question: /// ``` /// /// ```rust <del> /// #![feature(fmt_as_str)] /// </del> /// assert_eq!(format_args!("hello").as_str(), Some("hello")); /// assert_eq!(format_args!("").as_str(), Some("")); /// assert_eq!(format_args!("{}", 1).as_str(), None); /// ``` <del> #[unstable(feature = "fmt_as_str", issue = "74442")] </del> <ins> #[stable(feature = "fmt_as_str", since = "1.52.0")] </ins> #[inline] pub fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) {

I think you'd generally want to use it as an optimization only, but we can probably guarantee that it will return Some for certain cases in particular (e.g. ).
This function seems particularly bad for compressed formatting strings and breaks the otherwise clean abstraction.


Question: write!(f, "{}: ", input.name)?; input.type_.print(cx).fmt(f)?; } <ins> match (line_wrapping_indent, last_input_index) { (_, None) => (), (None, Some(last_i)) if i != last_i => write!(f, ", ")?, (None, Some(_)) => (), (Some(n), Some(last_i)) if i != last_i => write!(f, ",n{}", Indent(n + 4))?, (Some(_), Some(_)) => write!(f, ",n")?, } </ins> } if self.c_variadic { match line_wrapping_indent { None => write!(f, ", ...")?, <del> Some(n) => write!(f, "n{}...", Indent(n + 4))?, </del> <ins> Some(n) => write!(f, "{}...n", Indent(n + 4))?, </ins> }; } match line_wrapping_indent { None => write!(f, ")")?, <del> Some(n) => write!(f, "n{})", Indent(n))?, </del> <ins> Some(n) => write!(f, "{})", Indent(n))?, </ins> }; self.print_output(cx).fmt(f)

Take a look at the docs for : Rustdoc is making good choices for whether to wrap the declarations ! But when it wraps, it doesn't include a trailing comma on the last parameter. I think it should, because the default style guide wants a comma there. (And rustdoc should continue not putting a trailing comma when the declaration is shown as a single line.) <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
claim


Question: #![feature(const_float_bits_conv)] #![feature(const_float_classify)] <ins> #![feature(f16)] #![feature(f128)] </ins> #![allow(unused_macro_rules)] // Don't promote const fn nop<T>(x: T) -> T { x }

This file is only and : , but we should add the other float types to this test. The change should wait for since that changes some of these semantics (this PR is almost merged). There are probably a handful of tests that only check and but could use updates with the new types. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Okay will do that
FYI you can comment to assign yourself an issue
claim


Question: <ins> error: constant expression depends on a generic parameter --> $DIR/issue-50439.rs:25:22 | LL |         let _ = [(); 0 - !!(<Bears<T> as ReflectDrop>::REFLECT_DROP) as usize]; |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this may fail depending on what value the parameter takes error: aborting due to previous error </ins>

Testcase: I was mostly fooling around trying to see if there was any way I could get rustc to believe that it would always know whether Bears<Twas Drop regardless of T; for the test case, I changed it to Clone and got rid of actually setting the constant to true in the default case, as well as some unsafe keywords, to avoid muddying the waters with Drop's semantics. Note that the array trick for turning a constant into a compile time error comes from , so it's not as contrived as it initially appears. Stacktrace:
The test case overflows on ` <details</details
The code doesn't produce ICE anymore (tested on ), instead, the following error is produced: ()
this no longer crashes , marking as needs-test modify labels: E-needs-test


Question: use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::mem; <del> use crate::sync::atomic::{AtomicBool, Ordering}; </del> use crate::sys::cvt; use crate::sys_common::AsInner;

Good question! There are 6 workarounds in for older Linux versions (that I could find). Increasing the minimum version to 2.6.32 (aka 3rd Kernel LTS, aka RHEL 6) would fix 5 of them. Code links are inline: uses the flag with  (mentioned above, in 2.6.23) uses with  ( in 2.6.24, there is also the mention of a bug occuring on "some linux kernel at some point") uses  to atomically set the flag on the pipe fds ( in 2.6.27) uses with  ( in 2.6.27) uses  to permit use of ( in 2.6.28) ~ ( in 4.5, not fixed by this proposal)~ As you can see, the workarounds fixed by this proposal all have a similar flavor. Originally posted by in
Kernel updated in .
As noted, needs a much newer kernel 4.5, so we'll still need that fallback. But all the stuff should be ok to assume available now.
The new minimal version is 2.6.27 from what I can see, so "Socket::accept uses accept4(2) to permit use of SOCK_CLOEXEC" still needs a fallback, right?
The builder is using 2.6.32 headers, so I would call that our new minimum.
Ah right; I am actually not sure where I got the 27 from...
The title of suggested 2.6.27, but we went a little higher to match the actual distros in use.
I know this is ancient history, but do you recall the problem with ? You introduced that comment about "some kernel" in , and you were the last to update it in . If the problem kernels were before 2.6.32, then I'd like to clean that up now.
Just digging in kernel history, I did find one hiccup in , but that bug was introduced and resolved during the 3.7 development cycle, not in a release.
IIRC we just mirrored what musl did at the time, which looks like it : Looks like the original mailing list thread is gone and there's no comments in the musl source, and I don't recall what happened here. I suspect it would be safe to remove those workarounds and just assume works one the first try until someone says differently.


Question: A(i32), B(i32), } <del> // CHECK: %Enum4 = type { [2 x i32] } </del> <ins> // CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } </ins> pub enum Enum64 { A(Align64), B(i32), } <del> // CHECK: %Enum64 = type { [16 x i64] } </del> <ins> // CHECK: %Enum64 = type { [0 x i32], i32, [31 x i32] } </ins> // CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] } // CHECK-LABEL: @align64

In the 2017-12-14 Nightly I've seen a significant (almost 20%) compilation-time increase when I use on my code. And the successive day (2017-12-15) the compilation got a bit slower still and the run-time of the binary also got about 8% slower. The successive days the situation kept going slightly worse. Extracting parts of my code to show compiler/code performance is not easy, so I've composed this benchmark function (that solves an Euler problem. If this code isn't enough I will write other similar benchmarks): <details<summarySource code</summary</detailsCompiled with: host: x86_64-pc-windows-gnu Runtime: 2017-12-13: 0.30 seconds 2017-12-20: 0.53 seconds Asm from the the 2017-12-13 compiler: Asm from the the 2017-12-20 compiler:
Could someone try to reproduce and bisect this?
cc I think
We shouldn't have such big asm differences between successive nightlies, and I don't see anything suspicious in the middle, so it would be good to try and nail down the commit that made the difference.
I see a regression with this code (note: this is distinct from ). the bad code accesses the stack pointer (%rsp) You have a fast network connection and know how to use . Could you please do so? You should grep for to tell if the code is bad - the bad code includes the following line:
I bisected original example, just testing the speed of the executable created by a stage 1 and came upon (PR ) as the culprit: the runtime on my machine is around 0.3 seconds before that commit and around 0.7 seconds after. latest example also has a clear difference. The code before that commit (just disassembling the ): And after:
That's unfortunate. cc
cc
Thanks We're looking into it
just testing the speed of the executable I am not sure if they share the same cause, first a significant compiler performance decrease using --emit=metadata , then the successive Nightly the decrease of the produced binary performance.
They should not. However, quite a few big commits landed in the Dec 14 nightly.


Question: A(i32), B(i32), } <del> // CHECK: %Enum4 = type { [2 x i32] } </del> <ins> // CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } </ins> pub enum Enum64 { A(Align64), B(i32), } <del> // CHECK: %Enum64 = type { [16 x i64] } </del> <ins> // CHECK: %Enum64 = type { [0 x i32], i32, [31 x i32] } </ins> // CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] } // CHECK-LABEL: @align64

If you could provide an example that exhibits the slowdown with , that would allow us to fix it (is the Dec 13 nightly faster than the Dec 14 nightly which has the same speed, but worse runtime performance, than the Dec 15 nightly?)
The last nightly (2017-12-21) has fixed all three problems. Despite some attempts I failed finding a small amount of code that shows a significant compilation slowdown from 2017-12-14 to 2017-12-20, perhaps it's a more diffuse problem that emerges from compiling my whole big amount of code. I am sorry. I don't fully understand your question, but I try to answer creating a table with some data for some of the last Nightlies: Rustc version --emit=metadata Opt build Binary size Run-time 1.24.0-nightly 2017-12-11 4.32 49.78 12.93 1.24.0-nightly 2017-12-12 4.31 48.50 12.84 1.24.0-nightly 2017-12-13 5.15 50.69 12.86 1.24.0-nightly 2017-12-15 5.33 52.98 14.04 1.24.0-nightly 2017-12-17 5.44 53.31 14.03 1.24.0-nightly 2017-12-20 5.47 54.49 14.14 1.24.0-nightly 2017-12-21 4.28 48.82 12.96 The --emit=metadata is a check time. The Opt build is the compilation time for a well optimized build. The binary size is stripped and in bytes. The times are all in seconds.
EDIT: told me about , so the range is .... EDIT2: at a quick glance, none of those changes should affect binary size or run time. How many times have you run each of these? How much do they vary?


Question: A(i32), B(i32), } <del> // CHECK: %Enum4 = type { [2 x i32] } </del> <ins> // CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } </ins> pub enum Enum64 { A(Align64), B(i32), } <del> // CHECK: %Enum64 = type { [16 x i64] } </del> <ins> // CHECK: %Enum64 = type { [0 x i32], i32, [31 x i32] } </ins> // CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] } // CHECK-LABEL: @align64

They should be: rustc 1.24.0-nightly ( 2017-12-20) binary: rustc commit-hash: commit-date: 2017-12-20 host: x8664-pc-windows-gnu release: 1.24.0-nightly LLVM version: 4.0 rustc 1.24.0-nightly ( 2017-12-21) binary: rustc commit-hash: commit-date: 2017-12-21 host: x8664-pc-windows-gnu release: 1.24.0-nightly LLVM version: 4.0 Mixing up things seems quite easy here.
Ah, that's why I asked, so the range is .... Still not seeing anything clearly relevant, but maybe someone else from does?
The --emit=metadata times are computed as the minimum of four tries. Their variance is very small (on the order of +-0.05) so I think they are reliable. The binary run-time is the minimum of 5 runs, their variance is higher perhaps because they do some I/O, despite using a SSD, about +-0.12. The compilation is slow so there I've done only one time, so those values are the less reliable, but differences above 1.5 seconds should be reliable.
For the compilation time issue, maybe there was a bug in NLL that made it active without it being enabled. For the run-time issue, we need to actually investigate this.
As in, investigate the cause of the run-time fluctuations and how it unregressed?
This is my good old friend the torpedo. LLVM optimizes into this: This is basically equivalent to this pseudo-Rust code After the "non-constant-address" write is generated, LLVM is sunk - LLVM has no way of getting rid of the non constant address, and no way of optimizing accesses to the target with that non-constant address.
Upstream LLVM (that's the yet-to-be-released LLVM 6) has this patch, which avoids the SimplifyCfg sink problem by not running sinking before inlining I have confirmed that - e.g. this code is optimized correctly with the new Until then, I think representing small enums using a struct (rather than an array) should work around this problem.


Question: A(i32), B(i32), } <del> // CHECK: %Enum4 = type { [2 x i32] } </del> <ins> // CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } </ins> pub enum Enum64 { A(Align64), B(i32), } <del> // CHECK: %Enum64 = type { [16 x i64] } </del> <ins> // CHECK: %Enum64 = type { [0 x i32], i32, [31 x i32] } </ins> // CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] } // CHECK-LABEL: @align64

With the 2017-12-22 Nightly all the problems are back: Rustc version --emit=metadata Opt build Binary size Run-time 1.24.0-nightly 2017-12-22 5.36 53.57 13.96
Coud you open a PR that turns small unions into LLVM structs (rather than arrays)? That should fix the problem.
The binaries generated by the last Nightly (1.24.0-nightly 2017-12-25) is further few percents slower (perhaps because of thinLTO?), the compilation times can't be compared now.
Is there more stable measure besides compile time / run time? They can be affected too easily by the environment especially when the run time is expected to take less than 1 second. The generated assembly size seems to be a good measure.
Please re-test next nightly and reopen if not fixed.
The run-time of the binary is now OK. The compilation time with --emit=metadata is still quite large.
Can you open a separate one for compilation times? Seems to be a separate issue.
, I've tried here:


Question: A(i32), B(i32), } <del> // CHECK: %Enum4 = type { [2 x i32] } </del> <ins> // CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } </ins> pub enum Enum64 { A(Align64), B(i32), } <del> // CHECK: %Enum64 = type { [16 x i64] } </del> <ins> // CHECK: %Enum64 = type { [0 x i32], i32, [31 x i32] } </ins> // CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] } // CHECK-LABEL: @align64

I was looking at the generated asm for to see what happens to the array, and was surprised to see a large function with 5(!) call sites for . The generated code doesn't seem to vary with the number of elements in the array. That got me to compare with the functionally equivalent code: which doesn't yield the same assembly at all. The first difference being that the latter doesn't even store the array (only the strs) while the former does. That got me even further in comparing with equivalent loops, up to the extreme (and stupid): vs. The latter generates the simplest code possible: The former not so much:
Documenting my thinking in the hopes that it will be useful, or at least that someone will correct me via Campbell's Law. We know that the ASM outputs are different, so let's go back a few steps until we can find where in the toolchain we want to add our improvement. I compiled this on 1.19 with , but the important thing to note is that while iterany is quite bloated, it looks like the for loop has already been optimized: So is just as trivial in LLVM bytecode as it is in assembler - whatever optimizations we needed to do have already happened. We need to go back farther. . Notice that the tables have turned! is more concise than , so the code we need to add should change the MIR output. Note that . So the problem here seems to be that we aren't inlining before we generate LLVM bytecode. But that answer doesn't satisfy me either, because neither the nor the has any calls to , and in fact . So... one of these things is happening: 're failing to inline , and we haven't noticed because LLVM's been inlining this code for us. LLVM doesn't have as much knowledge as we do, so it can't do as good a job as we theoretically could. 've been looking at unoptimized MIR this whole time. This hypothesis seems to be borne out by the fact that when I rerun rustc without optimizations, I get exactly the same MIR output. But , and ? It's possible that both of these hypotheses are correct; maybe this is unoptimized MIR, because the MIR optimizations are doing absolutely nothing to this file!


Question: A(i32), B(i32), } <del> // CHECK: %Enum4 = type { [2 x i32] } </del> <ins> // CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } </ins> pub enum Enum64 { A(Align64), B(i32), } <del> // CHECK: %Enum64 = type { [16 x i64] } </del> <ins> // CHECK: %Enum64 = type { [0 x i32], i32, [31 x i32] } </ins> // CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] } // CHECK-LABEL: @align64

I'm still cloning rustc, but once I do I'll comment out the MIR optimizations and see where that gets us.
Well, I can oblige that in one aspect :) You put far too much hope into MIR optimizations. They do very little right now—inlining, for example, isn't even enabled by default (only with ). Even in the future, when all the MIR optimizations we've ever wanted are implemented, they will only cover a small subset of what LLVM does (there's no point in duplicating all the work that went into LLVM, and that would be impractical anyway). This code looks sufficiently messy that I don't expect MIR optimizations to ever fully optimize it away. For example, that would probably require loop unrolling, which hasn't ever been proposed AFAIK (and if it was, I'd be skeptical of it). In any case, the more interesting question is why LLVM can't optimize the iterator version as well as the alternative. Whatever goes awry in optimizing this, it happens in one of LLVM's many passes.
The LLVM IR you posted is very weird. It has multiple branches on constants, and presumably dead code consequently. There's also several branches on values?!? These should all have been cleaned up. After running it through again, I get this IR (names are all messed up cause I did it on , which insists on applying C++ name demangling): <details</detailsThat's... less code, but still very stupid. Why are the adjacent loads and stores not folded away?! A third pass (just at this point) gets rid of them, constant folds the rest, and winds up with . Looks like a nasty phase ordering issue. But what about this IR confuses LLVM so much?
Neat discovery. Should we move this discussion to LLVM's bug tracker and close this task, then?
Not necessarily, no. In the past people have tweaked the definitions of iterator methods to help the optimizer. rustc might also be able to help by changing the pass pipeline or by generating better/different IR in the first place.
This did optimize out in LLVM 3.9, and was broken by LLVM 4.0.


Question: A(i32), B(i32), } <del> // CHECK: %Enum4 = type { [2 x i32] } </del> <ins> // CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } </ins> pub enum Enum64 { A(Align64), B(i32), } <del> // CHECK: %Enum64 = type { [16 x i64] } </del> <ins> // CHECK: %Enum64 = type { [0 x i32], i32, [31 x i32] } </ins> // CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] } // CHECK-LABEL: @align64

In more detail, LLVM 3.9 generates the following small code for ( metadata stripped - it doesn't matter, with this function substituted in both 3.9 and 4.0 manage to optimize everything out): While LLVM 4.0 manages to screw up and generate this monstrosity: I think the somehow prevents SROA.
Going closer to the root: LLVM 3.9 optimizes the closure in to this: While LLVM 4.0 for some reason generates this:
caused by
The initial nonequivalence in the filing of the bug report is due to the slice iterator's explicit manual unrolling by 4 in its implementation of any. That might seem bad but as soon as llvm learns to loop optimize a loop with two exits (either the element was found or the iterator reached the end), the explicit unrolling can be removed.
is the PR that fixed this intended to be a permanent solution, or is it just a workaround? IOW, should we open a new bug to track reevaluating this fix when LLVM is resolved?
Hmmm, mentioned this bug, but you're right, this is older so me "fixing it" is probably more coincidental than anything else.
That LLVM bug is now tracked at and appears to have had no motion on it in the past 5 years. Assembly in the initial comparison cases remains identical per No other changes, as far as I can tell.
This was nominally resolved on our end, but was left open in the possibility that the LLVM issue was going to be resolved, so as to remove the "temporary" workaround. However, if we wish to track LLVM-side bugs that are not currently an impact on us, but may allow upgrades later, then I believe we may wish to consider tracking them in another form than an issue on the GH tracker, as they are "not an issue", so to speak. Alternatively, if we want to track them on this tracker, we may wish to track them in a more organized fashion (e.g. a metabug). I am going to close this issue. Do feel free to reopen this if it regresses again, or it becomes otherwise currently actionable, or if there is a particular reason we must have an open issue on our end to track this LLVM issue for potential improvements as opposed to any of the other currently-open LLVM issues we could be potentially waiting on in order to make an improvement.


Question: A(i32), B(i32), } <del> // CHECK: %Enum4 = type { [2 x i32] } </del> <ins> // CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } </ins> pub enum Enum64 { A(Align64), B(i32), } <del> // CHECK: %Enum64 = type { [16 x i64] } </del> <ins> // CHECK: %Enum64 = type { [0 x i32], i32, [31 x i32] } </ins> // CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] } // CHECK-LABEL: @align64

The LLVM issue has long since been fixed, so it's possible that the workaround may be removed.
I think any workarounds here are long gone, since moved to internal iteration way back in


Question: }, ); <del> // Construct the list of in-scope lifetime parameters for async lowering. // We include all lifetime parameters, either named or "Fresh". // The order of those parameters does not matter, as long as it is // deterministic. if let Some((async_node_id, _)) = async_node_id { let mut extra_lifetime_params = this .r .extra_lifetime_params_map .get(&fn_id) .cloned() .unwrap_or_default(); for rib in this.lifetime_ribs.iter().rev() { extra_lifetime_params.extend( rib.bindings .iter() .map(|(&ident, &(node_id, res))| (ident, node_id, res)), ); match rib.kind { LifetimeRibKind::Item => break, LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { if let Some(earlier_fresh) = this.r.extra_lifetime_params_map.get(&binder) { extra_lifetime_params.extend(earlier_fresh); } } _ => {} } } this.r .extra_lifetime_params_map .insert(async_node_id, extra_lifetime_params); } </del> <ins> this.record_lifetime_params_for_async(fn_id, async_node_id); </ins> if let Some(body) = body { // Ignore errors in function bodies if this is rustdoc

Example: yields <details<summaryBacktrace</summary</details
cc and
This has to do with late-bound regions and RPITITs. I have a fix, but it's probably not right nor is it cleaned up much. I'll put it up for scrutiny soon though.
Actually nvm, it was a silly little resolver bug.
label +I-ICE +C-bug


Question: }, ); <del> // Construct the list of in-scope lifetime parameters for async lowering. // We include all lifetime parameters, either named or "Fresh". // The order of those parameters does not matter, as long as it is // deterministic. if let Some((async_node_id, _)) = async_node_id { let mut extra_lifetime_params = this .r .extra_lifetime_params_map .get(&fn_id) .cloned() .unwrap_or_default(); for rib in this.lifetime_ribs.iter().rev() { extra_lifetime_params.extend( rib.bindings .iter() .map(|(&ident, &(node_id, res))| (ident, node_id, res)), ); match rib.kind { LifetimeRibKind::Item => break, LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { if let Some(earlier_fresh) = this.r.extra_lifetime_params_map.get(&binder) { extra_lifetime_params.extend(earlier_fresh); } } _ => {} } } this.r .extra_lifetime_params_map .insert(async_node_id, extra_lifetime_params); } </del> <ins> this.record_lifetime_params_for_async(fn_id, async_node_id); </ins> if let Some(body) = body { // Ignore errors in function bodies if this is rustdoc

I'm seeing an internal compiler error on the following input (found by ):
Report from : regressed nightly: nightly-2020-02-07
It looks like caused the regression. (The error happens at but not at .) cc
The specific commit where the error starts happening is .
triage: P-high. Removing nomination. Added regression stable-to-nightly tag.
Fixed by


Question: self.truncate(0) } <del> /// Returns the number of elements in the vector. </del> <ins> /// Returns the number of elements in the vector, also referred to /// as its 'length'. </ins> /// /// # Examples ///

This ensures that someone looking at the documentation who searches for the word "length" to find the method which returns the length of the method will be able to find the method, and also explains the origin of the name if someone is unaware. I bring this up because one of my coworkers came to me asking for the name of the method, because they were having trouble finding it in the documentation.
The problem with this is that it's generally bad to include this in the summary, as it's just repeating what's already been said. So I didn't do this on purpose. I'm not sure what exact text rustdoc searches though.... i'd be against putting this in the summary, but for putting it in the longer description
We seem to be very inconsistent about what summaries to use for methods: Some say "length" and some say "number of elements". Perhaps changing them all to say something like "Returns the number of elements in / length of the slice." would help here.
It doesn't need to be in the summary(?), it can be in the body of the doc. already finds and and so on, so the focus is simply in Ctrl+F search inside the doc page itself (if I understand correctly?).


Question: <ins> fn main() { transmute(); // does not ICE } extern "rust-intrinsic" fn transmute() {} //~^ ERROR intrinsic has wrong number of type parameters: found 0, expected 2 //~| ERROR intrinsics are subject to change //~| ERROR intrinsic must be in `extern "rust-intrinsic" { ... }` block </ins>

<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --(reduced) (original) <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Please try to minimize the example as much as possible:
claim
heads up that already put up a fix
Thanks Just want to add that some other intrinsics also ICE. For example: ICEs as well.
Interesting -- I wonder if we should perhaps fix this in a less specific way than . I wonder if we should instead detect that the declaration is not valid b/c has not been enabled in the crate... If not, then I'd be glad to review a PR that fixes whatever other intrinsics you find to make too many assumptions in the compiler.
Even adding does not prevent the ICE unfortunately. It happens in due to the wrong number of arguments e.g. here for : occurs for a lot of intrinsics in this file. I'm guessing all of them will ICE under the conditions in this issue. To fix it, we could extend what's done for in to all intrinsics, maybe leveraging this code to know how many args are expected for any given intrinsic:
I have opened
Looks like intrinsics are expected to ICE if used wrongly (see comment: ) so I opened has been rightly closed. But that mean that should also ICE in these conditions. However, in the present issue it was ICEing for the wrong reason i.e. out of bound access . So does the right thing by stopping that. However, IMHO it should not taint the context and let it go to MIR lowering and then let it ICE there. That keeps consistent with other intrinsics' behaviour as noted above. Thoughts & If you guys agree I can open a PR to remove the tainting.
See which takes a different approach
Nice!


Question: // Types of fields (other than the last) in a struct must be sized. FieldSized, <ins> // Constant expressions must be sized. ConstSized, </ins> // static items must have `Sync` type SharedStatic,

This looks unintentional, and has been broken in all cases, until a few releases ago, AFAICT. Should this be covered by WF rules? cc Unsized constants cause an ICE, in both old trans and MIR trans: Unsized statics appear to work, but only in old trans: I believe this is possible because a constant DST lvalue in old trans is merely the fat pointer. It seems useful to allow an unsized , but IMO it should require a sized RHS instead, i.e.: And, of course, this should all go through the RFC process, to figure out all the finer details.
Should it be ? I don't think A needs to be an lvalue.
It makes more sense for constants, but I gave the example with because that's the only one that works today (although by accident).
Hmm? I mean the static is desugared into a const. works today.
The idea being that a static and a const reference both give access to one lvalue.
No, has different semantics: it allows an somewhere within and is guaranteed not to be duplicated.
Hmm? Both of these gives me a "error: cannot borrow a constant which contains interior mutability, create a static instead". This is what I'd suspect as the lvalue from the promoted has nothing to do with being a or a .
Let me rewrite my desugaring to account for that, oops.
Oh and my confusion really just stemmed from forgetting about the constants referring to statics rule. [Kind of a funny rule when works, but this is an orthogonal issue.]
I think in the meantime unsized statics should probably error, perhaps dependent on a crater run, though I doubt there's many people relying on said bug. It's much easier to relax restrictions than tighten them.
Will prepare a patch to turn this into an error, hopefully nobody has been abusing it.


Question: pub fn list_file_metadata(os: Os, path: &Path, out: &mut io::Writer) -> io::IoResult<()> { match get_metadata_section(os, path) { <del> Some(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out), None => write!(out, "could not find metadata in {}.n", path.display()) </del> <ins> Some(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out), None => { write!(out, "could not find metadata in {}.n", path.display()) } </ins> } }

Built glfw-rs using rust 0.10-pre. When referencing this crate in another source file and building, I get error: internal compiler error: unexpected failure This message reflects a bug in the Rust compiler. We would appreciate a bug report: note: the compiler hit an unexpected failure path. this is a bug Ok(task 'rustc' failed at 'assertion failed: ()', ) This is on OSX 10.9: rustc 0.10-pre ( 2014-02-18 10:16:48 -0800) host: x8664-apple-darwin
This means that you've got two versions of the same lying around, and doesn't like having two versions. This will be fixed by , I just need to land it :(
I have just build the library for the first time, and I can only find one dylib for it on my system (next to the rlib, but I gues that shouldn't cause any problems). Is there another possibility for this error? Gesendet: Mittwoch, 19. Februar 2014 um 01:09 UhrVon: "Alex Crichton" : mozilla/rust hhildebr : Re: [rust] Compiler error when referencing crate "glfw-rs" () This means that you've got two versions of the same libglfw- lying around, and rustc doesn't like having two versions. This will be fixed by , I just need to land it :( — Reply to this email directly or view it on GitHub.
my reading of is that having a dylib and an rlib simultaneously is a problem.
Having a dylib and an rlib simultaneously should not be a problem, it is in fact quite common. Having 2 dylibs and 1 rlib or 2 rlibs and 1 dylib however is a problem.
sorry, my mistake in parsing the title of .
Yes, indeed, I had several identical dylibs, but it wasn't the glfw-rs.. there were rust libs in /usr/local/lib and /usr/local/lib/rustlib/... Thanks! Gesendet: Mittwoch, 19.


Question: pub fn list_file_metadata(os: Os, path: &Path, out: &mut io::Writer) -> io::IoResult<()> { match get_metadata_section(os, path) { <del> Some(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out), None => write!(out, "could not find metadata in {}.n", path.display()) </del> <ins> Some(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out), None => { write!(out, "could not find metadata in {}.n", path.display()) } </ins> } }

Februar 2014 um 17:15 UhrVon: "Alex Crichton" : mozilla/rust hhildebr : Re: [rust] Compiler error when referencing crate "glfw-rs" () Having a dylib and an rlib simultaneously should not be a problem, it is in fact quite common. Having 2 dylibs and 1 rlib or 2 rlibs and 1 dylib however is a problem. — Reply to this email directly or view it on GitHub.
so can we close this ticket now, in that case? Or do you want to wait for alexcrichton's patches to land, and see what things look like for you then?
Nono, the ticket can be closed for now. Thanks for your help! Gesendet: Mittwoch, 19. Februar 2014 um 21:30 UhrVon: "Felix S Klock II" : mozilla/rust hhildebr : Re: [rust] Compiler error when referencing crate "glfw-rs" () so can we close this ticket now, in that case? Or do you want to wait for alexcrichton's patches to land, and see what things look like for you then? — Reply to this email directly or view it on GitHub.


Question: # is a separate choice from whether to pass `-g` when building the # compiler and standard library themselves. CTEST_RUSTC_FLAGS := $$(subst -g,,$$(CTEST_RUSTC_FLAGS)) <ins> CTEST_RUSTC_FLAGS := $$(subst -Cdebuginfo=1,,$$(CTEST_RUSTC_FLAGS)) </ins> ifdef CFG_ENABLE_DEBUGINFO_TESTS CTEST_RUSTC_FLAGS += -g endif

Failure happens in the crate: This probably has to do with how we're calling the "custom resume" function, unsure what's going on.
Duplicate of
Indeed!


Question: <ins> --- name: Documentation problem about: Create a report for a documentation problem. labels: A-docs --- <!-- Thank you for finding a documentation problem! 📚 Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present. --> ### Location ### Summary </ins>

This is unfortunate because: gives the impression that documentation fixes should not be submitted here, or are not welcome. prevents you from gathering commonly requested information (link to docs, rust version number, suggested fixes) in an automatic fashion. prevents automatic labelling for documentation-relevant issues. To fix this, . <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
label A-meta
claim


Question: <ins> error: lifetime may not live long enough --> $DIR/account-for-lifetimes-in-closure-suggestion.rs:13:22 | LL |     Thing.enter_scope(|ctx| { |                        --- |                        | |                        has type `TwoThings<'_, '1>` |                        has type `TwoThings<'2, '_>` LL |         SameLifetime(ctx); |                      ^^^ this usage requires that `'1` must outlive `'2` | = note: requirement occurs because of the type `TwoThings<'_, '_>`, which makes the generic argument `'_` invariant = note: the struct `TwoThings<'a, 'b>` is invariant over the parameter `'a` = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to 1 previous error </ins>

<!-- ICE: Rustc '' 'thread 'rustc' panicked at 'expected region for ('a//0) but found Type(&'{erased} mut FooImpl<'{erased}, '{erased}, T/) when instantiating args=[&'{erased} mut FooImpl<'{erased}, '{erased}, T/, '?27, ?2t, Closure(DefId(0:22 ~ a[a197]::{impl}::foo::{closure}), ['{erased}, '{erased}, T/, i32, Binder(fn((&ReLateParam(DefId(0:22 ~ a[a197]::{impl}::foo::{closure}), BrAnon) mut FooImpl<'{erased}, '{erased}, T/,)), []), ()])]'', 'thread 'rustc' panicked at 'expected region for ('a//0) but found Type(&'{erased} mut FooImpl<'{erased}, '{erased}, T/) when instantiating args=[&'{erased} mut FooImpl<'{erased}, '{erased}, T/, '?27, ?2t, Closure(DefId(0:22 ~ a[a197]::{impl}::foo::{closure}), ['{erased}, '{erased}, T/, i32, Binder(fn((&ReLateParam(DefId(0:22 ~ a[a197]::{impl}::foo::{closure}), BrAnon) mut FooImpl<'{erased}, '{erased}, T/,)), []), ()])]'' File: --auto-reduced (treereduce-rust): original: Version information ` Command: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongProgram output</strong</summary<p</p</details<!-- query stack: [mirborrowck] borrow-checking [mirborrowck] borrow-checking --
ICEs on nightly and beta, but not on stable. Minimized further: <details<summaryProgram output</summary</details
The ICE is another one from , cc
Still reproduces on 1.81.0-nightly (2024-06-13 ) -E-needs-test
I'll look into it later today.


Question: <ins> error: lifetime may not live long enough --> $DIR/account-for-lifetimes-in-closure-suggestion.rs:13:22 | LL |     Thing.enter_scope(|ctx| { |                        --- |                        | |                        has type `TwoThings<'_, '1>` |                        has type `TwoThings<'2, '_>` LL |         SameLifetime(ctx); |                      ^^^ this usage requires that `'1` must outlive `'2` | = note: requirement occurs because of the type `TwoThings<'_, '_>`, which makes the generic argument `'_` invariant = note: the struct `TwoThings<'a, 'b>` is invariant over the parameter `'a` = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to 1 previous error </ins>

: <details<summary<strongBacktrace</strong</summary<p</p</details
This looks to be a recent regression from cc and is on beta 1.79, but is just in diagnostics.


Question: <ins> // Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // compile-flags: -D warnings -D unknown-lints #![allow(unknown_lints)] #![allow(random_lint_name)] fn main() {} </ins>

The following snippet works fine before but now it reports a warning: Steps to reproduce: clone rustup override set nightly-2017-08-11 cargo test Is this an expected behavior, or a bug? Thank you!
cc -- probably related to the new lint implementation
Yes this was caused by The bug is on . The check for whether is in scope is not checking the current set of attributes being linted. For example this does not warn: but this warns: (as you've noticed) The fix is to just take the local variable into account which has the up-to-that-point set of lint attributes collected.
I've opened a PR for this at


Question: #[inline] fn plain_summary_line(s: Option<&str>) -> String { <del> let md = markdown::plain_summary_line(s.unwrap_or("")); shorter(Some(&md)).replace("n", " ") </del> <ins> let line = shorter(s).replace("n", " "); markdown::plain_summary_line(&line[..]) </ins> } fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {

A documentation comment like the one cited verbatim below, produces a main page summary that includes the first line of the code in the example. This is very surprising since there's an empty line in between, and the code example inserts a large colored box in the overview page (the parent module). cc since it's probably related to PR /// A tuple or fixed size array that can be used to index an array. /// /// /// /// Note the blanket implementation that's not visible in rustdoc: /// !


Question: }; debug!("make_shim({:?}) = untransformed {:?}", instance, result); <del> pm::run_passes( </del> <ins> // We don't validate MIR here because the shims may generate code that's // only valid in a reveal-all param-env. However, since we do initial // validation with the MirBuilt phase, which uses a user-facing param-env. // This causes validation errors when TAITs are involved. pm::run_passes_no_validate( </ins> tcx, &mut result, &[

<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: Not posting the entire 1.7K lines backtrace :upsidedownface: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details
You can also reproduce this in the rustc repo itself where will encounter the error with
Reduced: label F-typealiasimpl_trait
Found another repro I think: this one bisects to
`
prioritize
going to also link and as other reports of the same issue
WG-prioritization assigning priority (). label -I-prioritize +P-medium
Ok, after a bit more back ond forth , I'm tentatively bumping this issue to P-critical and raise these questions (echoing the comments from the discussion): would it make sense to revert ? cc or would it make sense to revert (which IIUC leaked in the std library an unstable nightly only feature) ? cc Next week Rust 1.72 will be released, artifacts are going to be build real soon, I think. Thanks for additional comments to help improve my understanding of the context here. label -P-medium +P-critical
The underlying issue here is an issue with TAIT. was an implementation-only change simplifying some backtrace code in that was made under the assumption that TAIT was reliable enough to be used inside . As it is not user-facing it should be easily revertible. So the question here is whether it is safer to get TAIT working (potentially by reverting ?) so it can be used internally or to just hold off on using it until the issue has been resolved, reapplying once that happens. I have no compiler experience, but my initial hunch would be that the library change is preferable for now. I'll get a PR ready until tomorrow, unless someone beats me to it.
should not be reverted.


Question: }; debug!("make_shim({:?}) = untransformed {:?}", instance, result); <del> pm::run_passes( </del> <ins> // We don't validate MIR here because the shims may generate code that's // only valid in a reveal-all param-env. However, since we do initial // validation with the MirBuilt phase, which uses a user-facing param-env. // This causes validation errors when TAITs are involved. pm::run_passes_no_validate( </ins> tcx, &mut result, &[

All it does is cause us to now eagerly reveal opaques that were being skipped over during normalization, which means that we're just not hitting this code anymore: It does not introduce a bug, it just reveals one that already existed. I'm gonna use the minimized example () here. What's happening here is that we're generating a drop shim for that looks like: which then tries to validate that . However, it has type , where is a , which does not hit the code I linked above. Before , we'd emit something that looks like: which is a field that is incompletely normalized, but does* hit the code above.
Submitted the PR reverting : .
fixes this issue by not considering mir validity on shims until they have been optimized, which uses the reveal-all param-env for that shim. This ICE shouldn't be possible to trigger without , since it has to do with one of the intra-pass mir validations that are only done when that flag is active: I don't personally think that needs to be reverted, either.
This was also possible to trigger even before using an associated type. The test in exercises this too.


Question: | LL |     opaque!; |           + <ins> help: a unit struct with a similar name exists | LL |     Opaque; |     ~~~~~~ </ins> error: aborting due to 3 previous errors

Given the following code: The current output is: <!-- The following is not always necessary. --Ideally the output should include a note suggesting the variant with the same name (but different case):
label +C-enhancement +D-newcomer-roadblock
This only doesn't Just Work because the Levenshtein thing is case sensitive, right? There is some special-casing for case-insensitive suggestions but afaict it only applies if the case-sensitive Levenshtein distance is also already low, which seems wrong at first glance.
im working on this Edit: I'm not working on this anymore because I ran out of time getting past incremental compilation / llvm errors after a rebase.
Okay, judging by , this is explicitly not supposed to work. shrug emoji Edit: Okay, maybe that test case didn't really care. The use of case-insensitive match as tie breaker for equal levenshtein distance only was introduced with afaict.


Question: } } } else if let &Safety::Unsafe(span) = safety { <del> this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); </del> <ins> let mut diag = this .dcx() .create_err(errors::UnsafeItem { span, kind: "extern block" }); rustc_session::parse::add_feature_diagnostics( &mut diag, self.session, sym::unsafe_extern_blocks, ); diag.emit(); </ins> } if abi.is_none() {

With the following code: We get this error: Making the block then gives: cc
:+1:, this should error in both cases but the diagnostics are misleading. Going to fix it. r?


Question: <ins> // Regression test for <https://github.com/rust-lang/rust/issues/98658> #![no_std] // @has blanket_impls.json // @has - "$.index[*][?(@.name=='Error')].kind" "assoc_type" // @has - "$.index[*][?(@.name=='Error')].inner.default.kind" "resolved_path" // @has - "$.index[*][?(@.name=='Error')].inner.default.inner.name" "Infallible" pub struct ForBlanketTryFromImpl; </ins>

Run with this in : and inspect . There is an item for the of the blanket impl  and it's default value is . There is an item but the default value is missing. It looks like this: When using instead of the information about the default value is present. It looks like this: This change, which in practice is a regression, is caused by But we can't revert it of course because that will result in ICEs which is even worse. So we need some kind of follow-up fix. labels +A-rustdoc-json +T-rustdoc +C-bug +requires-nightly
It seems like you already suggested a fix. Want to open a PR for it?
Yep I will do that as soon as I get time. Probably today.
It's not in a hurry. Don't hesitate to ask if you need help.


Question: <del> Subproject commit 3bf51f591f7ffdd45f51cd1d42a4002482af2bd5 </del> <ins> Subproject commit c388361cc2db82568d5e90fefea864f0af8d35e9 </ins>

Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool miri has failing tests. 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! cc the PR reviewer, and nominating for compiler team prioritization.
This test is failing:
might give a hint what needs to be updated. I haven't gotten a chance to look closely yet.
Yeah, we'll need to emulate that new static thing by Unfortunately I don't entirely understand the static magic that goes on there... there's just a fn ptr stored in a particular section and somehow that is enough?!?
Yes, all platforms have sections that they treat as an array of pointers, filling the entire section, which makes it easy to append more entries, as linkers will happily concatenate sections with the same name. This is how C++ global constructors are implemented everywhere. So I guess there's two levels to this: miri should collect the platform-specific global ctors/dtors (on Linux I think there's also init/fini which work similarly) and execute them before C main (and after, in the case of dtors) when is , the ctors (or just the init flavor?) can also take 1, 2 or 3 arguments, not only 0 arguments (I believe this is also how C main technically works)
Okay. This is basically I hoped we'd never have to do this... For dtors, we already run TLS dtors, but those are entirely separate (we hook the pthread calls where dtors are set, and then run those functions later). There's no way those can be unified to one mechanism, is there? Also, this begs the question in which order stuff is called before/after main.
C++ asks itself the same question and I personally haven't heard of there being an answer. The safe thing to do is to make sure any order is safe (in Rust you have to initialize global state before any runtime initialization, so it's safer than C++ where before the constructor runs, the fields are uninitialized). The implementations just go through the sections in order, so the unknown quantity is what order the linker concatenates all of these sections.


Question: <del> Subproject commit 3bf51f591f7ffdd45f51cd1d42a4002482af2bd5 </del> <ins> Subproject commit c388361cc2db82568d5e90fefea864f0af8d35e9 </ins>

In miri you don't have the linker to think about, but you do need a mechanisms to access all statics from all crates.
Wait, why can't libstd initialize the args from the start lang item as well? Surely there's an inexpensive way to do so?
That's what I did originally, but said not to.
Reverting should fix this.
We could either adjust the 's to no use the new method when is set, or we could implement those initializers. Seems like we'll want them eventually anyway... What would be the best way to do that?
In the short term, excluding from the new mechanism seems like a reasonable solution to unbreak miri. That depends on two factors: what order functions get placed into the sections, and what order they get called. The default linker scripts will collect all sections in sorted order, followed by the section itself, into a single section. Likewise for and . The sort order here uses the linker's , which takes a numeric section suffix as a numeric priority, and sorts sections with non-numeric suffixes asciibetically. (There are also a couple of special cases to make sure that glibc can guarantee its own functions run first/last in a couple of those. And there are some very careful special cases to handle the old , , , and sections, which get translated into corresponding , , , and sections respectively in the final binary to preserve the behavior of those sections, keeping in mind that ctors sections get run in reverse order and the dtors sections get run in forwards order. translates the priority in numbered ctors and dtors sections by subtracting it from .) When loading a program or library, glibc calls the function pointers in in order, then the (single) function (which executes the contents of the section), then the function pointers in in order. At shutdown, glibc calls the function pointers in in reverse order, then the (single) function (which executes the contents of the section). Does that help?
It is a great reference, thanks! So far I have no idea how to wire up all these sections in Miri, but I guess we'll see about that. ;) On a separate note, also broke Miri by removing the getter from . I am not sure yet if there is a replacement that we can use instead.


Question: <del> Subproject commit 3bf51f591f7ffdd45f51cd1d42a4002482af2bd5 </del> <ins> Subproject commit c388361cc2db82568d5e90fefea864f0af8d35e9 </ins>

Leaving that here just so that I hopefully can find it later.
I don't see any way to actually do that.
I would prefer to avoid duplicate initialization of arguments. I'd like to make Rust executables smaller, not larger.
I agree, I would accept this change.
I opened a PR for that:
Done. I set it to close this issue since we already have to track the more elaborate approach.
Well, actually closing the issue will require also bumping the submodule to include
I don't understand, this would only be a few bytes with ? To unbreak miri it's probably fine but I'm increasingly worried about , as it allows divergence to exist in ways which are not controlled within miri itself.
I was talking about a user of these facilities, not miri implementation. To expand a bit (although it's kind of offtopic): Rust forces you to mutate a that started out with a constant value (e.g. ), which means nothing else would observe an uninitialized value, just the initial constant value, if it happened to ran before the runtime initialization (which would e.g. replace the with a ). This makes Rust + safer in general than C++ with global constructors.
Ack.
Aand now we also need to wait for to land. That's the third independent Miri-breaking PR in 24h, impressive. ;)


Question: // build-fail <ins> // revisions: normal mir-opt // [mir-opt]compile-flags: -Zmir-opt-level=4 </ins> trait C { const BOO: usize;

File: /tmp/icemaker/issue--2.rs auto-reduced (treereduce-rust): original: Version information ` Command: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongProgram output</strong</summary<p</p</details
cc


Question: <del> Subproject commit 412fb00b37afb6b7f7fa96a35f2315c7e640b916 </del> <ins> Subproject commit d9aa23a43ad29e3a10551a1425ef5d5baef28d70 </ins>

Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool rls 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! cc the PR reviewer, and -- nominating for prioritization.
Upstream fix has landed:


Question: // figure out which generic parameter it corresponds to and return // the relevant type. let generics = match path.res { <del> Res::Def(DefKind::Ctor(..), def_id) => { </del> <ins> Res::Def(DefKind::Ctor(..), def_id) | Res::Def(DefKind::AssocTy, def_id) => { </ins> tcx.generics_of(tcx.parent(def_id).unwrap()) } Res::Def(_, def_id) => tcx.generics_of(def_id), <del> Res::Err => return tcx.types.err, </del> res => { tcx.sess.delay_span_bug( DUMMY_SP, <del> &format!("unexpected const parent path def {:?}", res,), </del> <ins> &format!( "unexpected const parent path def, parent: {:?}, def: {:?}", parent_node, res ), </ins> ); return tcx.types.err; }

results in an ICE (): <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --This issue has been assigned to via . <!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
claim


Question: impl Deref for Thing { //~^ ERROR not all trait items implemented, missing: `Target` [E0046] fn deref(&self) -> i8 { self.0 } <del> //~^ ERROR method `deref` has an incompatible type for trait: expected &-ptr, found i8 [E0053] </del> <ins> //~^ ERROR method `deref` has an incompatible type for trait //~| expected &-ptr //~| found i8 [E0053] </ins> } let thing = Thing(72);

The multi-line errors should be extended to include this testcase. missed this because the didn't go through . I tried but that didn't work either. If someone can point me to to where to catch it, I can probably fix this too. cc Code: Error: Change to:


Question: let mut span = None; let mut accum = 0u64; <del> for (index, arg_def) in fn_sig.inputs().iter().enumerate() { let layout = tcx.layout_of(ParamEnv::reveal_all().and(*arg_def.skip_binder()))?; </del> <ins> // this type is only used for layout computation, which does not rely on regions let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); for (index, ty) in fn_sig.inputs().iter().enumerate() { let layout = tcx.layout_of(ParamEnv::reveal_all().and(*ty))?; </ins> let align = layout.layout.align().abi.bytes(); let size = layout.layout.size().bytes();

<!-- ICE: Rustc '' 'thread 'rustc' panicked at ' has escaping bound vars, so it cannot be wrapped in a dummy binder.'', 'thread 'rustc' panicked at ' has escaping bound vars, so it cannot be wrapped in a dummy binder.'' File: --auto-reduced (treereduce-rust): original: Version information ` Command: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongProgram output</strong</summary<p</p</details<!-- query stack: [issizedraw] computing whether is [layoutof] computing layout of -- label +F-impltraitinassoctype +F-inherentassociated_types
ah lol this regressed in cc


Question: fn visit_item(&mut self, item: &'tcx Item) { let mut item_hir_id = None; self.lctx.with_hir_id_owner(item.id, |lctx| { <del> if let Some(hir_item) = lctx.lower_item(item) { item_hir_id = Some(hir_item.hir_id); lctx.insert_item(hir_item); } </del> <ins> lctx.without_in_scope_lifetime_defs(|lctx| { if let Some(hir_item) = lctx.lower_item(item) { item_hir_id = Some(hir_item.hir_id); lctx.insert_item(hir_item); } }) </ins> }); if let Some(hir_id) = item_hir_id {

The diagnostics ("use of undeclared lifetime name") are bad, but this indeed must be an error because the inner is an illegal use of the outer rather than an implicitly defined fresh lifetime.
Hm, I don't think that's quite what I'd expect: previously using in that context would be fine because there is no shadowing so to speak, that is, this compiles:
From Similarly, if a fn definition is nested inside another fn definition, it is an error to mention lifetimes from that outer definition (without binding them explicitly). This is again intended for future-proofing and clarity, and is an edge case. (In the second example there's an explicit definition that shadows the previous definition for following uses, in the first example there's no second definition, only use)
I see that this is in the RFC, but I think I more or less disagree with the reasoning given. Disallowing the use of inband lifetimes when nesting function seems arbitrary and not entirely helpful; it also makes a mechanical change from "old" to "new" more difficult because shadowing is visible only based on indent levels.
IMO it should be an error, with a helpful note like the one you get when writing . Let's not make in-band lifetimes any more confusing than they already are.
The distinction is that inband lifetime's selling point is that you don't need to declare lifetimes. If we say that, and then clarify it with "except" then I think the feature feels incomplete. Inband lifetimes confusion does not increase with permitting this, IMO.
The problem is if it's allowed, then has a different meaning than This seems unfortunate and confusing. Even unergonomic if I may say so. There's no way that the distinction between and won't be missed in a quick scan of the second one. But, like, the RFC process did decide that isn't important, so whatever.
Well, somewhat, but not really. Nothing outside of imports/definitions inherits into the inner function, unlike the impl where there is a history and multiple things which inherit (, lifetimes, generics).


Question: self.resolve_expr(elem, Some(expr)); self.visit_expr(idx); } <del> ExprKind::Assign(..) => { let old = self.diagnostic_metadata.in_assignment.replace(expr); visit::walk_expr(self, expr); self.diagnostic_metadata.in_assignment = old; </del> <ins> ExprKind::Assign(ref lhs, ref rhs, _) => { if !self.diagnostic_metadata.is_assign_rhs { self.diagnostic_metadata.in_assignment = Some(expr); } self.visit_expr(lhs); self.diagnostic_metadata.is_assign_rhs = true; self.diagnostic_metadata.in_assignment = None; self.visit_expr(rhs); self.diagnostic_metadata.is_assign_rhs = false; </ins> } _ => { visit::walk_expr(self, expr);

<!-- 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. If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur. --Given the following code: The current output is: <!-- The following is not always necessary. --Ideally the output should first check the RHS, before suggest adding . It should also avoid suggesting when code is invalid. Thanks. Something like this should also not suggest adding : cc <!-- If the problem is not self-explanatory, please provide a rationale for the change. --<!-- If dramatically different output is caused by small changes, consider also adding them here. If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition. --<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
I'm not convinced the second example should be something we need to fix, but the first example should be very easy to fix.
claim


Question: return Ok(cycle_result); } <del> let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); </del> <ins> let (result, dep_node) = self.in_task(|this| { let mut result = this.evaluate_stack(&stack)?; // fix issue #103563, we don't normalize // nested obligations which produced by `TraitDef` candidate // (i.e. using bounds on assoc items as assumptions). // because we don't have enough information to // normalize these obligations before evaluating. // so we will try to normalize the obligation and evaluate again. // we will replace it with new solver in the future. if EvaluationResult::EvaluatedToErr == result && fresh_trait_pred.has_projections() && fresh_trait_pred.is_global() { let mut nested_obligations = Vec::new(); let predicate = try_normalize_with_depth_to( this, param_env, obligation.cause.clone(), obligation.recursion_depth + 1, obligation.predicate, &mut nested_obligations, ); if predicate != obligation.predicate { let mut nested_result = EvaluationResult::EvaluatedToOk; for obligation in nested_obligations { nested_result = cmp::max( this.evaluate_predicate_recursively(stack.list(), obligation)?, nested_result, ); } if nested_result.must_apply_modulo_regions() { let obligation = obligation.with(this.tcx(), predicate); result = cmp::max( nested_result, this.evaluate_trait_predicate_recursively(stack.list(), obligation)?, ); } } } Ok::<_, OverflowError>(result) }); </ins> let result = result?; if !result.must_apply_modulo_regions() {

<!-- 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: <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summaryBacktrace</summary<p</p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
It doesn't seem to be related to GAT, only influenced by TAIT.
seems like another version of
claim


Question: !source_file.is_imported() }) .map(|source_file| { <del> // When exporting SourceFiles, we expand all paths to absolute // paths because any relative paths are potentially relative to // a wrong directory. // However, if a path has been modified via // `--remap-path-prefix` we assume the user has already set // things up the way they want and don't touch the path values // anymore. </del> match source_file.name { <ins> // This path of this SourceFile has been modified by // path-remapping, so we use it verbatim (and avoid // cloning the whole map in the process). _  if source_file.name_was_remapped => source_file.clone(), // Otherwise expand all paths to absolute paths because // any relative paths are potentially relative to a // wrong directory. </ins> FileName::Real(ref name) => { <del> if source_file.name_was_remapped || (name.is_relative() && working_dir_was_remapped) { // This path of this SourceFile has been modified by // path-remapping, so we use it verbatim (and avoid cloning // the whole map in the process). source_file.clone() } else { let mut adapted = (**source_file).clone(); adapted.name = Path::new(&working_dir).join(name).into(); adapted.name_hash = { let mut hasher: StableHasher<u128> = StableHasher::new(); adapted.name.hash(&mut hasher); hasher.finish() }; Lrc::new(adapted) } </del> <ins> let mut adapted = (**source_file).clone(); adapted.name = Path::new(&working_dir).join(name).into(); adapted.name_hash = { let mut hasher: StableHasher<u128> = StableHasher::new(); adapted.name.hash(&mut hasher); hasher.finish() }; Lrc::new(adapted) </ins> }, // expanded code, not from a file _ => source_file.clone(), }

STR (on Linux): file that has generics usage () code DWARF info Notice that contains such entries as , possibly produced by the fact that "" is a relative path and DWATcompdir is set to "/home/yury". It is expected for core files to have absolute path e.g. ""
cc I wonder what interaction (path rewriting?) causes this result.
FWIW, produces that shows that !DIFile entries has the directory field empty (and the filename is relative)
It is a regression, since +stable has absolute locations, e.g.
could this have to do with
Likely so! I'll try to look into this in the near future
Ok so the change here can be exhibited with this script: If you execute that script you see: but if you remove you see: It appears that if upstream crates (like libstd) use then their filename is listed as the original relative source file instead of the absolute path name that it had previous to when it wasn't compiled with . So somehow using to compile libstd is affecting downstream crates to have relative path names instead of old absolute path names. It makes sense to me that the absolute path name goes away with (that is the whole point after all) but ideally it'd still be an absolute path, just applying the mapping. would you be able to help point me in the direction of where this change in logic might happen? If so I can test out a patch!
This should be what you're looking for: One solution would be to compile libstd with absolute paths and apply proper remapping to those.
Ah that's perfect! I'll see if I can work up a solution to that soon


Question: impl<T: for<'a> ApplyL<'a>> LambdaL for T {} <del> // HACK(eddyb) work around projection limitations with a newtype // FIXME(#52812) replace with `&'a mut <T as ApplyL<'b>>::Out` pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut <T as ApplyL<'b>>::Out); impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> { type Target = <T as ApplyL<'b>>::Out; fn deref(&self) -> &Self::Target { self.0 } } impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.0 } } </del> pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>); impl<T: LambdaL> ScopedCell<T> {

() As you can see, calling directly doesn't instantiate the HRTB (even though it needs to AFAIK) or if it does it doesn't normalize the resulting bound, whereas going through normalizes the instantiated argument types of , while 's definition can be type-checked as-is. EDIT: you can also get an ICE by uncommenting the use in : cc (this might be a duplicate)
Duplicate of (at least the ICE case)? A lot of analysis wad did in the other issue. Maybe it would help. I doubt that, in such cases the associate type do normalize at all. My assumption is: In the case that you marked as "working", it is just delayed the normalization to the later stage. So if the later stage consider this is dead code it is passed and compile, otherwise, when it really need to normalize it, run into ICE. So when called explicitly like , the compiler have no choice but to normalize with . If you instead though, the compiler checked that the requirement to match the argument can in theory fullfill, but the lifetime parameter was not free in the function body so it can consider this is a late bound. So the normalization is not happen right away. Later on, when you add the code in to call , the compiler have to do normalization again, but it is already in codegen (see the backtrace messages) phase, so normalization is unexpected and ICE occurs. Given all that, I guess a proper solution is to add a "late normalization" pass to normalize any postponed normalization like this.
This is a probably a duplicate of and/or ?
closing as duplicate of , which is where I will try to track future instances of this field of ICE.


Question: // mir. match tcx.at(expr.span).lit_to_const(lit_input) { Ok(c) => return Some(c), <ins> Err(_) if lit_input.ty.has_aliases() => { // allow the `ty` to be an alias type, though we cannot handle it here return None; } </ins> Err(e) => { tcx.dcx().span_delayed_bug( expr.span,

<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --This issue has been assigned to via . <!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Regression in nightly-2023-06-03 Regression in Regression in ?
This is fixed by .
assign


Question: assert-css: ("#help-button .popover", {"display": "block"}) press-key: "Escape" assert-css: ("#help-button .popover", {"display": "none"}) <ins> // Checking doc collapse and expand. // It should be displaying a "-": assert-text: ("#toggle-all-docs", "[u2212]") press-key: "-" wait-for-text: ("#toggle-all-docs", "[+]") assert-attribute: ("#toggle-all-docs", {"class": "will-expand"}) // Pressing it again shouldn't do anything. press-key: "-" assert-text: ("#toggle-all-docs", "[+]") assert-attribute: ("#toggle-all-docs", {"class": "will-expand"}) // Expanding now. press-key: "+" wait-for-text: ("#toggle-all-docs", "[u2212]") assert-attribute: ("#toggle-all-docs", {"class": ""}) // Pressing it again shouldn't do anything. press-key: "+" assert-text: ("#toggle-all-docs", "[u2212]") assert-attribute: ("#toggle-all-docs", {"class": ""}) </ins>

Take any page in the Rust docs, for example . When you press the or keyboard shortcuts on your keyboard, they are supposed to either collapse or expand all items on the page, but not both (according to the instructions that you can find by clicking on your keyboard (or on the screen). Please make the + and - keyboard shortcuts idempotent, otherwise it would be redundant to have two buttons that do the same thing.
What do you think about this ?
Yeah we should do this.
I'll send a patch in the next days then.


Question: } } } <ins> fn expr_as_call_operand( &mut self, mut block: BasicBlock, scope: Option<region::Scope>, expr: Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr); let this = self; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { this.as_call_operand(block, scope, value) }); } let tcx = this.hir.tcx(); if tcx.features().unsized_locals { let ty = expr.ty; let span = expr.span; let param_env = this.hir.param_env; if !ty.is_sized(tcx.at(span), param_env) { // !sized means !copy, so this is an unsized move assert!(!ty.is_copy_modulo_regions(tcx, param_env, span)); // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. if let ExprKind::Deref { ref arg } = expr.kind { let arg = this.hir.mirror(arg.clone()); // Generate let tmp0 = arg0 let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut)); // Return the operand *tmp0 to be used as the call argument let place = Place { local: operand, projection: tcx.intern_place_elems(&[PlaceElem::Deref]), }; return block.and(Operand::Move(place)); } } } this.expr_as_operand(block, scope, expr) } </ins> }

The following code fails on stable: When compiled in release mode, the assert is optimized out by LLVM even though it checks the exact same condition as the other assert, as can be verified by testing in debug mode. Note that it's theoretically possible for the stack to be aligned correctly such that the bug is suppressed, but that's not likely. The 256's can be replaced with larger alignments if that happens. The bug is caused by the impl of copying to the stack with the default alignment of 16. ()
and seem related
This is a soundness hole.
So... I guess the problem is that the that rustc emits for the unsized local doesn't use ? That's... kind of bad, because it doesn't look like even supports dynamically setting the alignment: If this is correct, the issue should be renamed to something like "unsized locals do not respect alignment".
A way to fix this would be to change the ABI for dynamic trait calls that take by value to always pass by address. When the trait object is created is where the trampoline function would be generated, so there is no additional cost for static calls.
This can also be fixed by not allowing dynamically-sized local variables with an alignment more than some maximum value and having all dynamically-sized locals use that maximum alignment unless optimizations can prove that a smaller alignment suffices.
Messing with the ABI wouldn't help with unsized locals in general (assuming is correct), since e.g. will also need an alloca with dynamic alignment in general. Given only a value, there is no static way to say anything about its alignment, so how would you distinguish whether calling a method on it is OK?
Can we call and then align the pointer for the local ourselves as a workaround until we come up with a good solution?
In clang there's a function which might or might not be useful in this case.
requires a constant alignment. Non constant alignments are . This matches semantics of LLVM instruction, so it's not helping, as alignment of value in is unknown at compile time when moving from .
I think that overallocating for unsized locals of unknown alignment may make sense. You can and then make use of to compute the offset. Sure, it increases stack requirements, but it seems acceptable for , and in most cases you end up with extra 7 bytes on stack or less. 256 alignment seems like an edge case where wasting 255 bytes doesn't matter.


Question: } } } <ins> fn expr_as_call_operand( &mut self, mut block: BasicBlock, scope: Option<region::Scope>, expr: Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr); let this = self; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { this.as_call_operand(block, scope, value) }); } let tcx = this.hir.tcx(); if tcx.features().unsized_locals { let ty = expr.ty; let span = expr.span; let param_env = this.hir.param_env; if !ty.is_sized(tcx.at(span), param_env) { // !sized means !copy, so this is an unsized move assert!(!ty.is_copy_modulo_regions(tcx, param_env, span)); // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. if let ExprKind::Deref { ref arg } = expr.kind { let arg = this.hir.mirror(arg.clone()); // Generate let tmp0 = arg0 let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut)); // Return the operand *tmp0 to be used as the call argument let place = Place { local: operand, projection: tcx.intern_place_elems(&[PlaceElem::Deref]), }; return block.and(Operand::Move(place)); } } } this.expr_as_operand(block, scope, expr) } </ins> }

if we keep setting as the default alignment we can skip the overallocating and offset dance for types with an alignment below that.
My idea was that rustc would prohibit coercing overaligned types to a dyn trait that takes by value. So:
The alignment is dynamically determined though, not sure if saving 15 bytes of stack space is worth the conditional branch?
Oh right. Yea that's probably not helpful.
Since , this would be backwards incompatible (at latest) once trait object upcasting is finally implemented: and trait objects would have to have the same alignment restriction (because you can upcast to ), but today you can freely create such objects with any alignment.
I was under the impression that calling didn't require dynamic , is that related to missing MIR optimizations, meaning we have unnecessary moves which end up duplicating the data on the stack using a dynamic ?
Correctness shouldn't rely on optimizations to fire...
Sure, I was just hoping we weren't relying on "unsized locals", only unsized parameters (i.e. ), for what we're exposing as stable. And I was hoping an optimization wouldn't need to be involved to get there. I wonder if it would even be possible to restrict "unsized locals" to the subset where we can handle it entirely through ABI, and not actually have dynamic s anywhere, since that would make me far more comfortable with 's implementation or even stabilization. Ironically, if that works, it's also the subset we could've implemented years earlier than we did, since most of the complexity, unknowns (and apparently bugs) are around dynamic s, not calling trait object methods on a dereference of .
That should be possible. I think everything that is necessary is performing the deref of the box as argument () instead of moving the box contents to a local first () That would also make it possible to call in cg_clif. Cranelift doesn't have alloca support, so the current MIR is untranslatable.
Hmm, but that's not trivially sound because it could lead to MIR calls where argument and return places overlap, which is UB. We'd potentially have to special-case it to derefs, but even then what's to stop someone from doing ? Maybe we could introduce a temporary for the return value instead, for these kinds of virtual calls? That should remove any potential overlap while allowing the call.


Question: } } } <ins> fn expr_as_call_operand( &mut self, mut block: BasicBlock, scope: Option<region::Scope>, expr: Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr); let this = self; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { this.as_call_operand(block, scope, value) }); } let tcx = this.hir.tcx(); if tcx.features().unsized_locals { let ty = expr.ty; let span = expr.span; let param_env = this.hir.param_env; if !ty.is_sized(tcx.at(span), param_env) { // !sized means !copy, so this is an unsized move assert!(!ty.is_copy_modulo_regions(tcx, param_env, span)); // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. if let ExprKind::Deref { ref arg } = expr.kind { let arg = this.hir.mirror(arg.clone()); // Generate let tmp0 = arg0 let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut)); // Return the operand *tmp0 to be used as the call argument let place = Place { local: operand, projection: tcx.intern_place_elems(&[PlaceElem::Deref]), }; return block.and(Operand::Move(place)); } } } this.expr_as_operand(block, scope, expr) } </ins> }

(Unrelatedly, I just realize we use a copying-out shim for vtable entries that take by value, even when would be passed as at the call ABI level. We would probably have to make computing the call ABI a query for this microopt to not be expensive)
That would result in being moved to a temp first before dropping and calling the boxed closure. If it wasn't moved first before the drop of , then borrowck would give an error. (I meant for this change to be done at mir construction level, not as an optimization pass, so borrowck should catch any soundness issues)
We can try it, I guess, but right now a lot relies on many redundant copies/moves being created by MIR building and may not catch edge cases like this. But also I don't think moving out of a moves the itself today. Me too, but I was going with the "correct by construction" approach of creating a redundant copy/move, just on the return side, instead of the argument side, of the call.
After revisiting on triage, removing nomination.
pre-triage: nominated for discussion in the next weekly meeting.
I just checked and, a function call roughly this (touched up for clarity): Some of my previous comments assumed the wasn't there and the call would use the destination directly, but given that there is a move, that simplifies my suggestion. <hr/For virtual by-value calls, we can skip one move when building the MIR, specifically the move out of the dereference of a for the argument. Given that we already move the result of the call, there should be no aliasing caused by this, but if we decide to change anything about how we build MIR calls, we'd need to be extra careful. We can also make this pattern be gated by a separate feature-gate (rather than ), and make sure the standard library only uses that feature-gate and not . This should solve any alignment issues might have, because we'd not be using dynamic unless the broader feature is used.
OK, if I understand what's being proposed here, it is to excerpt a subset of the "original unsized-locals plan" -- specifically, to permit locals with unsized types, but only in contexts where we can be guaranteed that we can point to the original storage and don't actually have to move any value (and hence we don't require variable size stack frames).


Question: } } } <ins> fn expr_as_call_operand( &mut self, mut block: BasicBlock, scope: Option<region::Scope>, expr: Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr); let this = self; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { this.as_call_operand(block, scope, value) }); } let tcx = this.hir.tcx(); if tcx.features().unsized_locals { let ty = expr.ty; let span = expr.span; let param_env = this.hir.param_env; if !ty.is_sized(tcx.at(span), param_env) { // !sized means !copy, so this is an unsized move assert!(!ty.is_copy_modulo_regions(tcx, param_env, span)); // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. if let ExprKind::Deref { ref arg } = expr.kind { let arg = this.hir.mirror(arg.clone()); // Generate let tmp0 = arg0 let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut)); // Return the operand *tmp0 to be used as the call argument let place = Place { local: operand, projection: tcx.intern_place_elems(&[PlaceElem::Deref]), }; return block.and(Operand::Move(place)); } } } this.expr_as_operand(block, scope, expr) } </ins> }

I'm in favor of this proposal, but I do think we want to be slightly careful to ensure we're not violating soundness. The main concern would be if there is some way to access or re-use the variable that was moved. I attempted to do so with this example () but it fails to compile: The error here arises because the closure would need to capture a to do anything, which prevents a later move. But maybe there is some kind of tricky example that can arise where we re-assign the value during argument evaluation?
compiles and does before , where is the result of .
Borrowck should prevent that, right?
borrowck may rely on MIR building creating extraneous copies, so we can't just assume it helps us. IMO we should limit it to functions taking unsized parameters and function calls passing such parameters or dereferences of es (any other pointer/reference doesn't support moving out of).
Well, I think is right that borrowck would catch violations of soundness in some strict sense, but I guess what I meant is that we might be breaking backwards compatibility.
The example that feels pretty relevant. If I understood your proposal, it would no longer compile. If I recall (thinking back), I had a plan to handle this by save the to an alternate location in the actual call, we pass ownership of and then do a shallow free of the This still seems like it would work, though I'm not sure how easy/elegant it is to formulate. In a sense we'd be rewriting to .
Isn't example dependent on doing a direct virtual call? My understanding is that you can't do this on stable with because the virtual call exists in one place, in libstd, and it doesn't do anything weird, so it would work with a restricted ruleset. EDIT: if it can work on stable, it's because calling 's will move the whole before the assignment is evaluated, which is fine, because the shallow drop is actually inside that , not its caller.
I agree that this code doesn't compile on stable today, but I'm not sure if that's the point. I guess you're saying it's ok for it to stop compiling? I think what I would like is that our overall behavior is as consistent as possible between Sized and Unsized parameters. I think we could actually do a more general change that doesn't special case Sized vs Unsized or anything else.


Question: } } } <ins> fn expr_as_call_operand( &mut self, mut block: BasicBlock, scope: Option<region::Scope>, expr: Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr); let this = self; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { this.as_call_operand(block, scope, value) }); } let tcx = this.hir.tcx(); if tcx.features().unsized_locals { let ty = expr.ty; let span = expr.span; let param_env = this.hir.param_env; if !ty.is_sized(tcx.at(span), param_env) { // !sized means !copy, so this is an unsized move assert!(!ty.is_copy_modulo_regions(tcx, param_env, span)); // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. if let ExprKind::Deref { ref arg } = expr.kind { let arg = this.hir.mirror(arg.clone()); // Generate let tmp0 = arg0 let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut)); // Return the operand *tmp0 to be used as the call argument let place = Place { local: operand, projection: tcx.intern_place_elems(&[PlaceElem::Deref]), }; return block.and(Operand::Move(place)); } } } this.expr_as_operand(block, scope, expr) } </ins> }

I think I am basically proposing the same thing as earlier, but with a twist: Today, when building the parameters, we introduce a temporary for each parameter. So if we had we might do: What I am saying is that we could say: If the argument is moved (not copied), and the "place" has outer derefs (e.g., we are passing where is some place), then we assign the place to a temporary and we make the argument to the function be : I don't believe this is observable to end-users, except potentially for when the destructor on runs. I believe that it accepts all the same code we used to accept. It also has nothing specific to or types at all. Does that make sense? I'm very curious to know if anyone sees any problems with it. (One obvious thing: if we ever add , its design would have to accommodate this requirement, but I think that's fine, in fact the complications around getting moves right for precisely this case are one of the reasons we've held off on thus far.)
Can you not reinitialize today? If you move the whole , it is indeed more conservative (and should let us skip unnecessary moves even in cases). But also, do you want to move the locals check from typeck to borrowck? I don't have an intuition for when your approach wouldn't create unsized MIR locals, from the perspective of typeck. However, this is only relevant if we want a stricter feature-gate. At the very least it seems like it would be easier to implement a change only to MIR building, and it should fix problems with for the time being, even without a separate feature-gate.
Hmm, that's a good point, I think do that. Sigh. I knew that seemed too easy. I remember we used to try and prevent that, but we never did it fully, and in the move to NLL we loosened those rules back up, so this compiles: Still, you could do my proposal for unsized types, though it would introduce an incongruity. UPDATE: Oh, wait, I remember now. For unsized types, reinitialization is not possible, because you can't do with an unsized rvalue (we wouldn't know how many bytes to move). So in fact there isn't really the same incongruity.