Question: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

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: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

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: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

(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: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

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: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

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.


Question: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

To be clear, I wasn't proposing changing anything apart from MIR building either, I don't think. IIUC, what you proposed is that would be compiled to: whereas under my proposal (limited to apply to unsized parameters, instead of moved parameters) would yield: I think I mis-stated the problem earlier. It's not so much that your proposal will introduce compilation errors, it's that I think it changes the semantics of code like this in what I see as a surprising way: I believe that this code would compile to the following under your proposal: which means that would be invoked with the new value of , right? Under my proposal, the code would still compile, but it would behave in what I see as the expected fashion. Specifically, it would generate:
Isn't there a way to "lock" that value through the borrow-checker, so further accesses would be disallowed, until the call returns? I'd rather be stricter here. <hr/My point was that if your proposal affects sized moves, you're breaking stable reinitialization. If it doesn't affect sized moves, I don't see how this applies anymore:
Let me just chime in here and say that this is a pain in Miri. Unsized locals are pretty different from sized locals, I had to introduce a bunch of special hacks to make them work. MIR locals even needed a new state just for them: Lazily allocating locals seems odd to me, but at least we can consistently do that for all locals. Elsewhere however to make this lazy initialization actually work out and catch mistakes where an unsized local is "overwritten" with a value of different size: This all feels really unprincipled, and it would be great if at some point we could come up with a coherent semantics for unsized locals in MIR. The worst part is that the size of a local is implicitly determined on the first write to it. It would be much better to be explicit about that, e.g. at time.
I don't think we have anything like this today, but presumably we could add such a thing, but I'm not quite sure what you have in mind. When does this prohibition on further accesses take effect?


Question: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

In particular, the IR for under your proposal, if I understood, would be But the access to that (I believe) we wish to prevent takes place in the "evaluate remaining arguments" part of things. So I think we'd have to add some sort of "pseudo-move" that tells borrowck that should not be assignable from that point forward, right? Well, it depends on your perspective. It's true that, given the need to permit reinitialization, the check is now specific to unsized values -- i.e., MIR construction will be different depending on whether we know the type to be sized or not. That's unfortunate. However, I think we still maintain a degree of congruence, from an end-user perspective. In particular, users could not have reinitialized a anyhow. However, under my proposal, users can write things like and the code works as expected (versus either having an unexpected result or getting an error). In any case, it seems like we're sort of "narrowing in" on a proposal here: when we see a function call with a parameter that is , and the value being passed is a deref, we want to modify the IR to not introduce a temporary and instead pass that parameter directly from its location, either we do some sort of "no more assignments" lock, or we move the pointer and introduce a temporary (and then pass in a deref of that temporary) Does that sound right so far?
If it's easier to do the more flexible approach (by moving the pointer) than the "locking" approach (which is a bit like borrowing the pointer until all arguments are evaluated, then releasing the borrow and doing a move instead), I don't mind it, I was only arguing with the "uniformity" aspect. Something important here: your approach is stabilizable, while mine is meant more for that one in the standard library, and not much else.
Yes, I was kind of shooting for something that we could conceivably stabilize.
Removing nomination, this was already discussed in triage meeting and it's under control.
So should we maybe try out the approach I proposed and see how well it works?
yes, going to try that out.
For the record, the "new plan" is this.


Question: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

When generating the arguments to a call, we ordinarily will make a temporary containing the value of each argument: But we will modify this such that, for arguments that meet the following conditions: The argument is moved (not copied), and its type is not known to be , and the "place" has outer derefs (e.g., we are passing P where P is some place), then we assign the place P (instead of ) to a temporary and we make the argument to the function be (instead of ). This means that given where , we used to generate but now we generate We are now moving the box itself, which is slightly different than the semantics for values known to be sized. In particular, it does not permit of the box after having moved its contents. But that is not supported for unsized types anyway. The change does permit modifications to the callee during argument evaluation and they will work in an analogous way to how they would work with sized values. So given something like: we will find that we (a) save the old value of to a temporary and then (b) overwrite while evaluating the arguments and then (c) invoke the with the old value of .
Update: There is also
is a perfectly normal operand, I don't know what you mean. It's the same kind of as we currently have in (on the RHS)
Oh sorry, somehow I thought operands could only refer directly to locals, not also dereference them. I think I am beginning to see the pieces here -- together with function argument handling, this entirely avoids having to dynamically determine the size of a local. I have to agree that is quite elegant, even though baking "pass-by-reference" into MIR semantics still seems like a heavy hammer to me. On the other hand this places a severe restriction on now unsized locals may be used, basically taking back large parts of Is there some long-term plan to bring that back (probably requires with dynamic alignment in LLVM)? Or should we amend the RFC or at least the tracking issue with the extra restrictions?
I would keep the more general feature but use two different feature-gates (if we can). And just like with a few other feature-gates () we could warn that (the general one) is incomplete and could lead to misaligned variables (or something along those lines).


Question: LL |         y.foo(); |         ^ value used here after move <del> error[E0382]: use of moved value: `*x` </del> <ins> error[E0382]: use of moved value: `x` </ins> --> $DIR/double-move.rs:45:9 | LL |         let _y = *x; |                  -- value moved here LL |         x.foo(); <del> |         ^ value used here after move </del> <ins> |         ^ value used here after partial move </ins> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | <ins> LL |         let x = "hello".to_owned().into_boxed_str(); |             - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait </ins> LL |         x.foo(); |         - value moved here LL |         let _y = *x; |                  ^^ value used here after move <del> | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> error: aborting due to 6 previous errors

We could also add runtime asserts that the (dynamic) alignment is respected, once we know could never trigger them (e.g. from stable code).
I was wondering about that too. It seems like it'd be good to review the more general feature in any case. This is partly why I brought up the idea of wanting a guaranteed "no alloca" path -- this was something I remember us discussing long ago, and so in some sense I feel like the work we're doing here isn't just working around LLVM's lack of dynamic alignment support (though it is doing that, too) but also working to complete the feature as originally envisioned.
I two notes to the tracking issue so we don't overlook this in the future.
This is probably expected, but the fix failed to actually make sound:


Question: # Complete! <del> At this point, you have successfully built the Guessing Game! Congratulations! </del> <ins> This project showed you a lot: `let`, `match`, methods, associated functions, using external crates, and more. </ins> <del> This first project showed you a lot: `let`, `match`, methods, associated functions, using external crates, and more. Our next project will show off even more. </del> <ins> At this point, you have successfully built the Guessing Game! Congratulations! </ins>

I am learning rust and reading the book for the first time The section mentions a "Next Project" at the very end We can add a link to that project ?
It's referring to the next project showed in the book (so next section if I remember well). If confirms, this issue can be closed.
Actually, this sentence is vestigial from when we had the Dining Philosophers chapter. I would actually prefer to remove this sentence. Want to submit another PR? :D
absolutely :-) on it
was interested in looking at the old . pasted here for future people was removed in
sent PR


Question: LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } <ins> extern "C" void LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } </ins> #endif // LLVM_VERSION_GE(4, 0)

I'm opening this up to serve as a tracking issue for enabling multiple codegen units in release mode by default. I've written up a before but the tl;dr; is that multiple codegen units enables us to run optimization/code generation in parallel, making use of all available computing resources often speeding up compilations by more than 2x. Historically this has not been done due to claims of a loss in performance, but the is intended to assuage such concerns. The most viable route forward seems to be to enable multiple CGUs and ThinLTO at the same time in release mode. Blocking issues: [x] Enable for libstd on all platforms - - - - Potential blockers/bugs: - -
cc
Presumably this will remain a stable compiler flag, but what else will change by default? Is the plan to make this only affect , or is the plan to also make this affect ? Do we want to make continue to use only a single CGU, to hedge against regressions for people who are already willing to trade off compiler time for runtime?
I would specifically propose that any opt level greater than 1 uses 16 codegen units and ThinLTO enabled by default for those 16 codegen units.
This is very interesting. One would think that ThinLTO-driven inlining should always have to do less work when our much more conservative pre-LLVM inlining. But that doesn't always seem to be the case, as in the . Most tests on the seem to profit though. Overall it's still not a clear picture to me.
was that comment meant for a different thread? I forget which one as well though, so I'll respond here! As a "quick benchmark" I compiled the regex test suite with 16 CGUs + ThinLTO and then toggled inlining in all CGUs on/off. Surprisingly inlining in all CGUs was 5s faster to compile, and additionally . In those timings is where inlining is only in one CGU, where is inlining in all CGUs. One benchmark, , got twice as slow!
Yeah, the comment was in response to (rust-doom) but since that was closed already, I put it here.


Question: LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } <ins> extern "C" void LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } </ins> #endif // LLVM_VERSION_GE(4, 0)

Regarding the compilation time difference between pre- and post-trans inlining, my hypothesis would be that sometimes pre-trans inlining will lead to more code being eliminated early on (as in the case of regex apparently) and sometimes it will have the opposite effect. I suspect that there's room for improvement by tuning which LLVM passes we run specifically for ThinLTO. Or do we do that already?
Heh it's true yeah, I'd imagine that there's always room for improvement in pass tuning in Rust :). Right now we perform (afaik) 0 customization of any pass manager in LLVM. All of the normal optimization passes, LTO optimization passes, and ThinLTO optimization passes are all the same as what's in LLVM itself.
I wanted to also take the time and tabulate all the results from the to make sure it's all visibile in one place. Note that all the timings below are comparing a release build to a release build with 16 CGUs and ThinLTO enabled Improvements All of the following compile times improved, sorted by most improved to least improved Regressions The following crates regressed in compile times, sorted from smallest regression to largest alexcrichton's attempt to reproduce the regressions Here I attempt to reproduce the regressions on my own machine with Unfortunately the only regression I was able to reproduce was the rust-belt regression. I'll be looking more into that.
Looking into , one interesting thing I've found is that the crate takes longer to compile with ThinLTO than it would otherwise. Looking at it appears that one codegen unit in this crate takes 99% of the time in LLVM. This codegen unit appears to be basically entirely dominated by . Almost all of the benefit of multiple codegen units is spreading out the work across all CPUs. Enabling ThinLTO to avoid losing any perf is fundamentally doing more work than what's already happening at , but we get speedups across the board in most cases. If we have one huge CGU, split it in two, and work on those in parallel then we've got 50% of the original time to run ThinLTO (in a perfect world). If ThinLTO takes more than 50% of the time then we'd have a build time regression, but that's almost never happening.


Question: LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } <ins> extern "C" void LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } </ins> #endif // LLVM_VERSION_GE(4, 0)

What's happening here is that we have one huge CGU, but when we split it up we still have one huge CGU. This means that the CGU which may take ~1% less time in LLVM only gives us a tiny sliver of a window to run ThinLTO passes. In the case of the crate this means that adding ThinLTO passes is an overall build time regression. So generalizing even further, I think that enabling ThinLTO and multiple CGUs by default is going to regress compile time performance in any crate where our paritioning implementation doesn't actually partition very well. In the case of we've got one huge function which hogs almost all the optimization time (I think) and the entire crate is basically dominated by that one function. I would be willing to conclude, however, that such a situation is likely quite rare. Almost all other crates in the ecosystem will benefit from the partitioning which should basically evenly split up a crate. maybe you have thoughts on this though?
Thank you so much for collecting and analyzing such a large amount of data, Your conclusions make sense to me. Unevenly distributed CGU sizes are also a problem for incremental compilation; e.g. the test sees 90% CGU re-use, yet compile time is almost the same as from-scratch. In the non-incremental case it might be an option to detect the problematic case right after partitioning and then switch to non-LTO mode? I'm not sure it's worth the extra complexity though. For cases where there is one big CGU but that CGU contains multiple functions, we should be able to rather easily redistribute functions to other CGUs. We'd only need a metric for the size of a . The number of MIR instructions might be a sufficient heuristic here. That would not help for but it might help for other crates. In conclusion, judging from the table above, I think we should make the default sooner rather than later. Open questions I see: What to do about ? I would have thought that it would always be a clear win to disable this when ThinLTO is enabled but that doesn't seem to be the case. Are there hardware configurations where this never is a win? E.g. should we default to traditional compilation if ?


Question: LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } <ins> extern "C" void LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } </ins> #endif // LLVM_VERSION_GE(4, 0)

FWIW, as the author of , which is a made-for-fun Piston game, I am more than happy to take a small compile regression when it seems like vast majority of crates get huge real-time improvements!
This seems like a good thing to have in our back pocket, but I'm also wary of trying to do this by default. For example the case is one where we may wish to disable ThinLTO but the one massive function could also critically rely on a function in a different CGU being inlined? That sort of case would be difficult for us to determine... In any case though I agree that we probably don't need the complexity just yet so I think we can defer this for later. Agreed! So far all the crate's I've seen the O(instructions) has been quite a good metric for "how long this takes in all LLVM-related passes", so counting MIR sounds reasonable to me as well. Again though I also feel like this is ok to have in our back pocket. I'd want dig more into the minor change example, I'm curious how awry the CGU distribution is there and whether a heuristic like this would help. Quite surprisingly I've yet to see any data that it's beneficial to compile time in release mode or doesn't hurt runtime. (all data is that it hurts both compile time and runtime performance!) That being said we're seeing such big wins from ThinLTO on big projects today that we can probably just save this as a possible optimization for the future. On the topic of inline functions I recently dug up again (later closed in favor of , but the latter may no longer be true today). I suspect that may "fix" quite a bit of the compile time issue here without coming at a loss of performance? In any case possibly lots of interesting things we could do there. Also a good question! I find this to be a difficult one, however, because the CGU number will affect the output artifact, which means that if we do this sort of probing it'll be beneficial for performance but come at the cost of more difficult deterministic builds. You'd have to specify the CGUs manually or build on the same-ish hardware to get a deterministic build I think? I think though that if you have 1 CPU then this is universaly a huge regression.


Question: LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } <ins> extern "C" void LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } </ins> #endif // LLVM_VERSION_GE(4, 0)

With one CPU we'd split the preexisting one huge CGU into N different ones, probably take roughly the same amount of time to opimize those, and then tack on ThinLTO and more optimization passes. My guess is that with one CPU we'd easily see 50% regressions. With 2+ CPUs however I'd probably expect to see benefits to compile time. Anything giving us twice the resources to churn the cgus more quickly should quickly start seeing wins in theory I think. For now though the deterministic builds wins me over in terms of leaving this as-is for all hardware configurations. That and I doubt anyone's compiling Rust on single-core machines nowadays!
One thing I think that's also worth pointing out is that up to this point we've mostly been measuring the runtime of an entire . That's actually, I believe, the absolute worst case scenario for where ThinLTO will provide benefit. Despite this, it's showing huge improvements for lots of projects! The benefit of ThinLTO and multiple CGUs is leveraging otherwise idle parallelism on the build machine. It's overall increasing the amount of work the compiler does. For a from scratch, though, you typically already have tons of crates compiling for the first half of the build in parallel. In that sense there's not actually any idle parallelism. Put another way, ThinLTO and multiple CGUs should only be beneficial for builds which dont have many crates compiling in parallel for long parts of the build. If a build is 100% parallel for the entire time then ThinLTO will likely regress compile time performance. Now you might realize, however, that one very common case where you're only building one crate is in an incremental build! Typically if you do an incremental build you're only building a handful of crates, often serially. In that sense I think that there's some massive wins of ThinLTO + multiple CGUs in incremental builds rather than entire crate builds. Although improving both is of course great as well :)
For deterministic builds you have to do some extra configuration anyway (e.g. path remapping) so I would not consider that a blocker. And I guess there are single core VMs around somewhere.


Question: LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } <ins> extern "C" void LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } </ins> #endif // LLVM_VERSION_GE(4, 0)

But all of this is such a niche case that I don't really care MIR-only RLIBs should put us into a pretty good spot regarding this, so I'm quite confident that we're on the right path overall.
That's really interesting. For incremental compilation enabled the situation might be different (because pre-trans inlining hurts re-use) but for the non-incremental case it sounds like it's pretty clear what to do.
Yeah, maybe we should revisit this at some point. Although I have to say the current solution of only and symbols and nothing in between is really nice and simple.
Hm yeah that's a good point about needing configuration anyway for deterministic builds. It now seems like a more plausible route to take! Also that's a very interesting apoint about incremental and inlining on our own end... Maybe we should dig more into those ThinLTO runtime regressions at some point! Also yeah I don't really want to change how we trans inline functions just yet, I do like the simplicity too :)
out of curiosity how did you figure out this and which function it was. I've wanted to look into why the webrender build is so slow and would welcome tips.
oh sure I'd love to explain! So I originally found as a problematic crate when compiling rust-belt as it just took awhile and I decided to dig deeper. I checked out the crate and ran: That drops in the current directory, and opening that up I see: ! The graph here isn't always the easiest to read, but we've clearly got two huge bars, both of which correspond to taking a huge amount of time for that one CGU (first is optimization, second is ThinLTO + codegen). Next I ran: and that command dumps a bunch of IR files into . Our interesting CGU is so I opened up (we sure do love our long filenames). Inside that file it was 70k lines and some poking around showed that one function was 66k lines of IR. I sort of forget now how at this point I went from that IR to determining there was a huge function in there though...
I don't know if this is the right place, but I think it should be considered whether the symbol issues reported in the Nightly section here: should be considered a blocker or not.


Question: LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } <ins> extern "C" void LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } </ins> #endif // LLVM_VERSION_GE(4, 0)

The tl;dr is that certain versions of llvm, (i've seen this on 3.8, and whatever llvm rustc nightly uses) appends seemingly random garbage to the end of some names, e.g. we get: instead of: This knocks the debuginfo out of sync (it doesn't have the garbage appended). I've been able to repro this with clang3.8 for c++ files as well (haven't tested on other llvm), and switching to 5.0 seems to have fixed the issue. I don't know if its within reach, but perhaps we should attempt upgrading to llvm 5.0 before releasing this on stable? Note I understand this is for release mode, but i see this in debug mode on rustc nightly right now as well...


Question: (&self_ty.kind, parent_pred) { if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind { <del> let id = self.tcx.hir().as_local_hir_id(def.did).unwrap(); let node = self.tcx.hir().get(id); </del> <ins> let node = self .tcx .hir() .as_local_hir_id(def.did) .map(|id| self.tcx.hir().get(id)); </ins> match node { <del> hir::Node::Item(hir::Item { kind, .. }) => { </del> <ins> Some(hir::Node::Item(hir::Item { kind, .. })) => { </ins> if let Some(g) = kind.generics() { let key = match &g.where_clause.predicates[..] { [.., pred] => {

I tried code very similar to this: and it produces some type of type checking error when uncommenting the line beginning with . : Backtrace:
The error is likely due to the fact that the trait bounds on don't include for , though the compiler/type checker crashing is still likely a bug.
That code was introduced in , cc Submitted as a quick fix.
I can't get it to work in the same crate, just with two crates, where the first one depends on the other: modify labels: -E-needs-mcve
Thanks I included a test in the PR.


Question: /// Unix-specific extensions to `Permissions` #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { <del> /// Returns the underlying raw `mode_t` bits that are the standard Unix /// permissions for this file. </del> <ins> /// Returns the underlying raw `st_mode` bits that contain the standard /// Unix permissions for this file. </ins> /// /// # Examples ///

On linux, , then run: This changes the permissions of to . Is this expected? masks away everything other than the lower 3 triads when it calls out to this code: Then sends these mode bits into into chmod which considers four triads, not three. Possibly useful references: and Should we change Metadata.permissions to preserve that triad, maybe by masking with instead of ?
I guess the solution depends on whether Unix's std::fs::Permissions is supposed to care about 9 bits or 12 (this is not an implementation detail since it's exposed to the programmer via of PermissionsExt). any thoughts on this?
It seems to me like we should extend the mask to the full 12 bits.
Seems reasonable to me to avoid masking where it makes sense!


Question: let ty::CoroutineClosure(_, parent_args) = *tcx.type_of(parent_def_id).instantiate_identity().kind() else { <del> bug!(); </del> <ins> bug!("coroutine's parent was not a coroutine-closure"); </ins> }; if parent_args.references_error() { return coroutine_def_id.to_def_id();

<!-- ICE: Rustc '-Zunstable-options --edition=2024 -ooutputfile -Zdump-mir-dir=dir' 'error: internal compiler error: impossible case reached', 'error: internal compiler error: impossible case reached' 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: [coroutinebymovebodydefid] looking up the coroutine by-move body for [analysis] running analysis passes on this crate -- label +F-asyncclosure
As a step of reducing your code examples, could you please ensure that is necessary to reproduce this ICE before mentioning it in the issue? This ICE reproduces on edition 2021, which is the current stable edition.
My project fails on nightly also while using edition 2021.
Yep, a fix is already up and it's waiting for approval. I recommend downgrading to a slightly older nightly until this is fixed.


Question: /// Sets the platform-specific value of errno #[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall! <ins> #[allow(dead_code)] // but not all target cfgs actually end up using it </ins> pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } }

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: assert!(rows.iter().all(|r| r.len() == v.len())); <del> // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). let ty = matrix.heads().next().map_or(v.head().ty(), |r| r.ty()); </del> <ins> let ty = v.head().ty(); </ins> let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };

<!-- 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. --When compiling on an Apple M1 processor: <!-- 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
Can also reproduce this when compiling on an Intel Macbook
I've encountered the same error on a different platform (x8664) when compiling . The project doesn't use cargo so repro is nontrivial, but from I can see that the ICE started occurring at which is a rollup of . <details<summary<strongBacktrace</strong</summary<p</p</details
Also seems to be hitting starlark-rust, , as per
Somewhat minimized standalone testcase: Builds on stable, fails on nightly. cc
Thanks for the minimization! Seems like we've hit again, but through a different code path. I'm investigating.
I think might be another duplicate of this, triggered when compiling the crate.


Question: let mut out = output.stderr.clone(); out.extend(&output.stdout); let out = String::from_utf8_lossy(&out); <ins> // Check to see if the link failed with "unrecognized command line option: // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so, // reperform the link step without the -no-pie option. This is safe because // if the linker doesn't support -no-pie then it should not default to // linking executables as pie. Different versions of gcc seem to use // different quotes in the error message so don't check for them. if sess.target.target.options.linker_is_gnu && (out.contains("unrecognized command line option") || out.contains("unknown argument")) && out.contains("-no-pie") && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") { info!("linker output: {:?}", out); warn!("Linker does not support -no-pie command line option. Retrying without."); for arg in cmd.take_args() { if arg.to_string_lossy() != "-no-pie" { cmd.arg(arg); } } info!("{:?}", &cmd); continue; } if !retry_on_segfault || i > 3 { break } </ins> let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; let msg_bus  = "clang: error: unable to execute command: Bus error: 10"; if !(out.contains(msg_segv) || out.contains(msg_bus)) {

I'm having trouble linking a Rust program to a non-position-independent C library. When I manually remove the flag from the ld step that rustc runs, everything works correctly. I think that should remove the flag for me, but it doesn't. Here's what I think is going on: When I run It runs ld with the flag: But when I read the rustc code , it seems like the intention is that should only be passed to ld when . That is, if we're not compiling a position independent executable, then we should not pass the position independent executable flag to ld. I think what may be happening here is that somehow the defaults from are overriding the command line options I'm setting. This happens with stable and also the nightly I tried:
and are two distinct things. is also unrelated to the option. Interestingly, I do not remember us having an option to disable PIE; we should have one.
I did a bit of reading and here's what I figured out, please correct me if any of this is wrong. Linkers are new to me! Rust builds position independent executables by default on platforms that support it. These platforms have a relocation model of pic in their target config. The is what sets that linker option, except if it's disallowed by . The correct solution to this is to add a codegen flag, or something like that. Does this sound right?
Hi, I am having the same issue. I am trying to link against non-position-independent C library, build process ends without error but results returned by Rust bindings are different (and incorrect) than those returned from clean C implementation. In order to overcome that issue currently I am setting RUSTFLAGS="-C relocation-model=dynamic-no-pic -C linker=./linker" where linker is bash script that wraps cc and filter -pie flags:
I'm also having this problem. I assumed that passing when doing a build would suppress on the linker command line. (cc:
I'm still seeing this issue. Not sure if it's a regression or I'm doing something wrong. I have a "hello world" program in , and when I run , the resulting call to includes . I'm using nightly rust on Ubuntu: .
So, the problem here isn't with rust, but with the linker.


Question: let mut out = output.stderr.clone(); out.extend(&output.stdout); let out = String::from_utf8_lossy(&out); <ins> // Check to see if the link failed with "unrecognized command line option: // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so, // reperform the link step without the -no-pie option. This is safe because // if the linker doesn't support -no-pie then it should not default to // linking executables as pie. Different versions of gcc seem to use // different quotes in the error message so don't check for them. if sess.target.target.options.linker_is_gnu && (out.contains("unrecognized command line option") || out.contains("unknown argument")) && out.contains("-no-pie") && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") { info!("linker output: {:?}", out); warn!("Linker does not support -no-pie command line option. Retrying without."); for arg in cmd.take_args() { if arg.to_string_lossy() != "-no-pie" { cmd.arg(arg); } } info!("{:?}", &cmd); continue; } if !retry_on_segfault || i > 3 { break } </ins> let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; let msg_bus  = "clang: error: unable to execute command: Bus error: 10"; if !(out.contains(msg_segv) || out.contains(msg_bus)) {

In Ubuntu 15.10 and later the default GCC toolchain installed has been compiled with which causes and to be passed to during code generation and to during linking. Now, the linking part is what is important here as rust on most platforms uses as the linker for most targets. So, though no PIC or PIE code may have been generated by , the linker will still try to link as with PIE in mind, breaking when trying to compile with and the like. To work around this will need to see that the linker has been compiled with PIE as the default and pass to the linker if using GCC or something similar for other linkers. Code to do this can be seen in for Tarpaulin though it is only meant for Linux in that state and can be improved greatly if in tree. EDIT: Don't know why Github isn't linking cross-project PRs correctly right now.
Can this issue be resolved by always passing , except when compiling with ?
Sadly, no. In testing I have seen that any build of GCC that was not built with rejects the option and fails to run. This is why in the PR that I linked the linker was queried to see if it was compiled with before tacking on .
So it's came out from the discussion on an issue related to this in tarpaulin that passing -no-pie before -shared (and maybe then -static if it exists for static linkages as well) resolves the issue. I'm going to test this tarpaulin side and I can report back but I feel it would be best if this could be solved rustc side as it can affect any user in a similar situation.


Question: | LL |     let Alias::Braced = panic!(); |         ^^^^^^^^^^^^^ not a unit struct, unit variant or constant <ins> | help: use the struct variant pattern syntax | LL |     let Alias::Braced {} = panic!(); |                       ++ </ins> error[E0164]: expected tuple struct or tuple variant, found struct variant `Alias::Braced` --> $DIR/incorrect-variant-form-through-alias-caught.rs:12:9 | LL |     let Alias::Braced(..) = panic!(); |         ^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant <ins> | help: use the struct variant pattern syntax | LL |     let Alias::Braced {} = panic!(); |                       ~~ </ins> error[E0618]: expected function, found enum variant `Alias::Unit` --> $DIR/incorrect-variant-form-through-alias-caught.rs:15:5

I wrote code that looked like this while not having my brain turned on 100%. Due to said brain not functioning, it took me a while to understand what rustc was trying to tell me with the message pointing to the pattern with the text . sure looked like a unit variant to me! What rustc was trying to tell me was that the definition of the variant was a struct variant ("found struct variant") and my pattern wasn't matching the definition ("this pattern you specified looks like it's trying to match a variant that is not a unit struct, unit variant or constant"). The change I needed to make was adding to my pattern, because I was trying to distinguish different variants from each other, not use pieces within the variants. Suggesting seems like a decent starting point to me, but there could definitely be cases I'm not considering here and I'm totally open to hearing that No response No response <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
WEIRD this PR looks like it implements what I wish rustc did: but the test files in that PR say they're for and I'm getting
Aha ok this test shows that for tuple variants, rustc will suggest adding : and that test also shows that rustc isn't suggesting anything for struct variants!
Aha and it looks like adding struct fields was more complex so that's why it wasn't done?
claim


Question: <ins> // run-rustfix struct Foo { first: Bar, _second: u32, _third: u32, } struct Bar { bar: C, } struct C { c: D, } struct D { test: E, } struct E { _e: F, } struct F { _f: u32, } fn main() { let f = F { _f: 6 }; let e = E { _e: f }; let d = D { test: e }; let c = C { c: d }; let bar = Bar { bar: c }; let fooer = Foo { first: bar, _second: 4, _third: 5 }; let _test = &fooer.first.bar.c; //~^ ERROR no field let _test2 = fooer.first.bar.c.test; //~^ ERROR no field } </ins>

I just encountered this output: We currently mention available fields when the field used isn't found. It would be nice if we peeked at the types for the available fields to see if any of them has any fields (including through deref) of the name we originally wanted. In this case, I would love to see the following output: <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
I'll work on this. claim
I was just about to open a PR when I saw that you claimed the issue. It's my fault for not claiming this issue myself obviously, so if you've already been investing time into this the issue its still yours, but if you haven't can I open a PR for this?
I've done nothing yet as I planned to work on this tomorrow morning, so this is yours :)
release-assignment
if you're still interested in contributing, it seems to me that might be similar in scope and section of the codebase you could work in.
Thank you.


Question: // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. <ins> let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque; </ins> if approx_env_bounds.is_empty() && trait_bounds.is_empty() <del> && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque) </del> <ins> && (alias_ty.needs_infer() || is_opaque) </ins> { debug!("no declared bounds"); <del> self.substs_must_outlive(alias_ty.substs, origin, region); </del> <ins> let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id)); self.substs_must_outlive(alias_ty.substs, origin, region, opt_variances); </ins> return; }

Another regresssion of with a different failure path: It should be fixed by ignoring non-captured lifetimes in: cc label regression-from-stable-to-stable C-bug T-compiler T-types A-impl-trait
Note that fixing this issue is necessary for , but might not be sufficient. I'll investigate more...
WG-prioritization assigning priority (). label -I-prioritize +P-high


Question: // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. <ins> let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque; </ins> if approx_env_bounds.is_empty() && trait_bounds.is_empty() <del> && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque) </del> <ins> && (alias_ty.needs_infer() || is_opaque) </ins> { debug!("no declared bounds"); <del> self.substs_must_outlive(alias_ty.substs, origin, region); </del> <ins> let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id)); self.substs_must_outlive(alias_ty.substs, origin, region, opt_variances); </ins> return; }

Some regressions of that I previously reported in , but they were missed: I guess the way to fix this is to ignore non-captured lifetimes of opaque types here cc label C-bug regression-from-stable-to-stable T-types T-compiler A-impl-trait
WG-prioritization assigning priority (). label -I-prioritize +P-high


Question: [stackoverflow]: http://stackoverflow.com/questions/tagged/rust This installer also installs a copy of the documentation locally, so we can <del> read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. On Windows, it's in a `share/doc` directory, inside the directory to which Rust was installed. </del> <ins> read it offline. It's only a `rustup doc` away! </ins> # Hello, world!

Specifically at , and recommend for Windows too, right? We've , but in the meantime, the old book should recommend the new recommended toolchain :) If it's too soon to do this because isn't stable enough yet, consider this a reminder issue to make this change once it is :)
wants to wait a bit, and we'd need to then make sure to update the website in sync (see )
Maybe the big red warning "this is beta software" should be removed from the website?
This will be fixed by


Question: .emit(); } let key = BindingKey::new(target, ns); <del> let mut resolution = this.resolution(parent, key).borrow_mut(); resolution.single_imports.remove(&Interned::new_unchecked(import)); </del> <ins> this.update_resolution(parent, key, |_, resolution| { resolution.single_imports.remove(&Interned::new_unchecked(import)); }); </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. --With the latest nightly, the bytemuck crate fails to compile. This was compiling yesterday and the issue seems to be traits are not imported with super::*. Please see the issue in the bytemuck repository: <!-- 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. --: </p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Regression in searched nightlies: from nightly-2023-06-10 to nightly-2023-06-20 regressed nightly: nightly-2023-06-20 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.6</summaryHost triple: x86_64-unknown-linux-gnu Reproduce with: cc
<details<summaryi made a mistake making the example, see below </summaryThis should error in coherence, but instead errors with It looks like if there is a derive macro and trait with the same name, glob imports don't resolve the trait anymore. Note that works correctly </details
Maybe the reduced it incorrect? I found that it also throw an error for 1.70?
hm, maybe your change simply exposed an existing bug in more cases
I will check it later claim
ah no, I made a stupid mistake, i should have used :D, my example only got from the prelude which only contains the macro.
This is resolved, of course. Only tagging this with Nilstrieb's estimated priority for historical analysis later.
Now that this fix is merged, what time tonight should we expect a new nightly release?
0:00 according to a server somewhere. In practice, usually UTC 0:00. So it should be being cut sometime soon. Or 24 hours from now. Either one.


Question: <ins> - // MIR for `call` before Inline + // MIR for `call` after Inline fn call(_1: &T) -> TypeId { debug s => _1; let mut _0: std::any::TypeId; let mut _2: &T; bb0: { StorageLive(_2); _2 = &(*_1); _0 = <T as Any>::type_id(move _2) -> [return: bb1, unwind unreachable]; } bb1: { StorageDead(_2); return; } } </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 this code: I expected to see this happen: The three printed TypeIds should be identical, as with the behavior in Rust <=1.70 Instead, this happened: switch between rust versions. I could not find reference in the that could explain such behavioral changes.
if my bisection is correct, this surfaced in commit cc (makes sense?)
I do not believe that is the correct PR to point at. Bisecting anything related to MIR opts can be tricky because you need to stabilize the MIR opt pipeline against changes like in that PR which don't actually implement any new behavior, they just change the meaning of MIR opt levels. Try bisecting with ? The above PR just changes the opt level 3 inliner behavior to be the default.
Reproduces since before with
This has to do with the fact that this impl: ... applies even when . Therefore in a polymorphic function like , we're eagerly inlining from that impl even though during monomorphization we'd prefer the built-in candidate instead. This seems problematic.
WG-prioritization assigning priority (). label -I-prioritize +P-high


Question: debug!(?closure_sig); <del> // (1) Feels icky to skip the binder here, but OTOH we know // that the self-type is an unboxed closure type and hence is </del> <ins> // NOTE: The self-type is an unboxed closure type and hence is </ins> // in fact unparameterized (or at least does not reference any <del> // regions bound in the obligation). Still probably some // refactoring could make this nicer. </del> <ins> // regions bound in the obligation). let self_ty = obligation .predicate .self_ty() .no_bound_vars() .expect("unboxed closure type should not capture bound vars from the predicate"); </ins> closure_trait_ref_and_return_type( self.tcx(), obligation.predicate.def_id(), <del> obligation.predicate.skip_binder().self_ty(), // (1) </del> <ins> self_ty, </ins> closure_sig, util::TupleArgumentsFlag::No, )

An there actually does panic for the test. I only moved this code between the files, the same comment and code pattern exists as well for normal closures: Originally posted by in
I couldn't repro this failure, maybe was doing instead of ? The ordering is important here.
I believe I did, yes.


Question: <ins> #![feature(doc_cfg)] #![feature(no_core)] #![crate_name = "foo"] #![no_core] // @has 'foo/index.html' // @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'foobar' // @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'bar' #[doc(cfg(feature = "foobar"))] mod imp_priv { // @has 'foo/struct.BarPriv.html' // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]'  //    'Available on crate feature foobar only.' pub struct BarPriv {} impl BarPriv { pub fn test() {} } } #[doc(cfg(feature = "foobar"))] pub use crate::imp_priv::*; pub mod bar { // @has 'foo/bar/struct.Bar.html' // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]'  //    'Available on crate feature bar only.' #[doc(cfg(feature = "bar"))] pub struct Bar; } #[doc(cfg(feature = "bar"))] pub use bar::Bar; </ins>

From Given the following Rust code with in-line annotations of the expected behaviour: On: does not seem to be able to generate feature requirement labels on types in private modules () that are publicly reexported (). The labels do not show up on the module overview nor page, but do propagate into items like functions for the given type. This renders the type without any feature requirement, neither in the module overview: ! Nor on the page: ! Note that the label is propagated onto (does not have an explicit ), at least understood that! It is supposed to render the feature requirement for like , both in the module overview above as on the page: ! It seems tricky to combine feature requirements on the and reexport. In the case above they are the same, but what if: The type is only publicly available when and are specified. Specifying is fine but makes the contents of unreachable through the current module, specifying only should result in a "module not found" error. CC
This also affects re-exports of entire crates. Unfortunately there the fix is not clear at all, since the "parent" crate is obviously not guaranteed to have the same features as the crate being re-exported.
Within the same crate as well; it's not about the features that are enabled (though it is relevant which are available) but about the combined restrictions that are placed on the definition and reexport. Simplest I can think of is a union of all features (but gets complicated quick when inversions and vs is used) and later perhaps simplifying based on feature relations (if implies there is no need to display as requirement, if either definition or reexport requires ). That's necessary to cleanly solve crate reexports, since you effectively want to ensure that the top-level crate feature implies feature and hide it. If the whole resolver is made smart enough (perhaps this already exists, I'm not too familiar with Cargo) it could even throw warnings when there exist feature combinations that would lead to a compiler error (ie. explicitly reexporting a symbol that is not available for a certain set of features).
I wonder if this is just an ordering issue of the passes: The private modules have disappeared by the point where we pass all the data down so we don't see them.


Question: <ins> #![feature(doc_cfg)] #![feature(no_core)] #![crate_name = "foo"] #![no_core] // @has 'foo/index.html' // @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'foobar' // @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'bar' #[doc(cfg(feature = "foobar"))] mod imp_priv { // @has 'foo/struct.BarPriv.html' // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]'  //    'Available on crate feature foobar only.' pub struct BarPriv {} impl BarPriv { pub fn test() {} } } #[doc(cfg(feature = "foobar"))] pub use crate::imp_priv::*; pub mod bar { // @has 'foo/bar/struct.Bar.html' // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]'  //    'Available on crate feature bar only.' #[doc(cfg(feature = "bar"))] pub struct Bar; } #[doc(cfg(feature = "bar"))] pub use bar::Bar; </ins>

Thanks for the suggestion - I moved before and (I've never built rustc/rustdoc from source, pleasantly surprised that only took just under 7min on a ThreadRipper :partyingface:) but it doesn't change anything to the generated output unfortunately :(
I observe this on public items as well: Does not show the badge at re-exports.
So from the following code: is stripped and then inlined. The stripped version contains all the correct information but the inlined one doesn't. Checking what's the best course here: either cloning the stripped item or propagating when inlining.


Question: <ins> #![feature(return_position_impl_trait_in_trait)] trait Extend { fn extend(_: &str) -> (impl Sized + '_, &'static str); } impl Extend for () { fn extend(s: &str) -> (Option<&'static &'_ ()>, &'static str) { //~^ ERROR in type `&'static &()`, reference has a longer lifetime than the data it references (None, s) } } // This indirection is not necessary for reproduction, // but it makes this test future-proof against #114936. fn extend<T: Extend>(s: &str) -> &'static str { <T as Extend>::extend(s).1 } fn main() { let use_after_free = extend::<()>(&String::from("temporary")); println!("{}", use_after_free); } </ins>

This is a use-after-free that compiles with 1.74.0-nightly (2023-09-13 ): cc


Question: setTimeout(() => { window.location.replace("#" + item.id); }, 0); <ins> return true; </ins> } }, ); <del> } </del> <ins> }); </ins> } } }

I spotted this in : the result links to ' which is not a valid link. Cc
cc -- I think these are supposed to be autoredirected in JS?
Okay... This happens because there's more than one and the one we want is currently named . The URL escaping is fine; the -35 is the problem.


Question: <ins> error[E0308]: mismatched types --> $DIR/str-as-char-non-lit.rs:6:19 | LL |     let _: &str = ('a'); |            ----   ^^^^^ expected `&str`, found `char` |            | |            expected due to this error[E0308]: mismatched types --> $DIR/str-as-char-non-lit.rs:8:19 | LL |     let _: &str = token(); |            ----   ^^^^^^^ expected `&str`, found `char` |            | |            expected due to this error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. </ins>

<!-- ICE: Rustc '' 'thread 'rustc' panicked at 'assertion failed: bpos.tou32() = () + as u32'', 'thread 'rustc' panicked at 'assertion failed: bpos.tou32() = () + as u32'' File: --snippet: 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: [typeck] type-checking [analysis] running analysis passes on this crate --
cc


Question: <ins> //! Normalizes MIR in RevealAll mode. use crate::MirPass; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; pub struct RevealAll; impl<'tcx> MirPass<'tcx> for RevealAll { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // This pass must run before inlining, since we insert callee bodies in RevealAll mode. // Do not apply this transformation to generators. if (tcx.sess.mir_opt_level() >= 3 || !super::inline::is_enabled(tcx)) && body.generator.is_none() { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); RevealAllVisitor { tcx, param_env }.visit_body(body); } } } struct RevealAllVisitor<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, } impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } #[inline] fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { *ty = self.tcx.normalize_erasing_regions(self.param_env, ty); } #[inline] fn process_projection_elem( &mut self, elem: PlaceElem<'tcx>, _: Location, ) -> Option<PlaceElem<'tcx>> { match elem { PlaceElem::Field(field, ty) => { let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty); if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None } } // None of those contain a Ty. PlaceElem::Index(..) | PlaceElem::Deref | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } | PlaceElem::Downcast(..) => None, } } } </ins>

Previously: Now: <!-- 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
Inlining exposes a use of unnormalized local in a call terminator (not sure if this is more of an issue with inlining or a validator): Note: revision annotation doesn't work in an auxiliary file (so it isn't tested on CI with mir-opt-level=2). modify labels: +A-mir-opt-inlining
This ICEs again because the fix was reverted Can someone reopen please?
Due to this new requires to trigger. <details<summaryICE:</summary</details
(FWIW can also trigger this: )
fixes this for and , but it still ICEs with on its own or with mir-opt-level 1/2 cc


Question: <ins> //@ check-pass #![deny(rustdoc::redundant_explicit_links)] mod bar { /// [`Rc`](std::rc::Rc) pub enum Baz {} } pub use bar::*; use std::rc::Rc; /// [`Rc::allocator`] [foo](std::rc::Rc) pub fn winit_runner() {} </ins>

We've recently begun testing Bevy against the beta toolchain, where it has incorrectly raised an lint against . is not imported in this file, yet rustdoc believes that it is. (See the imports .) As a temporary workaround, I've created to ignore the error. Here is that first failed. In case it expires, here's . Look at . I can reproduce it on using by running the following command: The is optional, but it makes the command finish quicker. I'll continue testing to see if I can create a minimum reproducible example. :
I've created a minimal reproduction in my -repro branch of my fork. Go to the  folder and run . I've managed to squish it down to this:
I've created a reproduction that removes the dependency on Bevy . I've simplified it down to this:
I bisected it, and this bug appears to first be introduced in . I could not reproduce it in .


Question: impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); let impl_ty_value = tcx.type_of(impl_ty.def_id); <del> // Map the predicate from the trait to the corresponding one for the impl. // For example: </del> <ins> let param_env = tcx.param_env(impl_ty.def_id); // When checking something like </ins> // <del> // trait X<A> { type Y<'a>: PartialEq<A> } impl X for T { type Y<'a> = &'a S; } // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; } </del> <ins> // trait X { type Y: PartialEq<<Self as X>::Y> } // impl X for T { default type Y = S; } </ins> // <del> // For the `for<'a> <<Self as X<A>>::Y<'a>: PartialEq<A>` bound, this // function would translate and partially normalize // `[<Self as X<A>>::Y<'a>, A]` to `[&'a u32, &'x u32]`. let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| { tcx.mk_substs( iter::once(impl_ty_value.into()) .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))), ) </del> <ins> // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case // we want <T as X>::Y to normalize to S. This is valid because we are // checking the default value specifically here. Add this equality to the // ParamEnv for normalization specifically. let normalize_param_env = { let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>(); predicates.push( ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { item_def_id: trait_ty.def_id, substs: rebased_substs, }, ty: impl_ty_value, }) .to_predicate(tcx), ); ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None) </ins> }; tcx.infer_ctxt().enter(move |infcx| {

So I had a trait system in my (nightly) code for a while now that utilized specialization, but it no longer seems to be working after a recent update: Now, I haven't been following the development of the specialization feature too closely, so it is possible that this is somehow actually intended and I am missing something. However, given that this previously compiled and ran just fine a couple weeks ago and given that the specialization incomplete warning was only recently, I am inclined to think that it is probably a regression of some sort. compiler version:
Another MVCE (): Regressed in , looks like
cc as far as I can tell this wasn't an intended outcome of the change?
It wasn't really, it was just slightly more complex to have this still work after that PR.
Would you mind describing at a high level what needs to be done?
It looks like the problem stems from the bound predicate not being fully normalized when checking the defaulted associated type. From my reproducer above: which should instead be . I'm not certain yet how this ought to be implemented. Perhaps a pass after normalization that looks for occurrences of the defaulted type ( in this case) and replaces it with the defaulted type. Seems simple enough, in theory :) But maybe there are cases I'm not thinking of.


Question: TypeLimits, MissingDoc, MissingDebugImplementations, <ins> ExternCrate, </ins> ); add_lint_group!(sess,

We need to add an epoch lint for It will lint , suggesting removal in root mods, and replacement with in non-root mods. This is blocked on the ability to elide extern crate in the first place.
It is also blocked on a feature to force linkage of a crate, see this comment and the discussion afterwards:
cc
I think the lint should be by default off in cases with , such as: This is because of the ergonomics problems with macros and the new macro import system, expressed here: It's bewildering for the migrating users if a lint tells them not to use the syntax, but then finding out that many of the macros out there have downright bad ergonomics with the import syntax. (For clarification: I think this is an undesirable state of affairs, and we should be linting against all , but if we do that, the ergonomics problem with the macro import should be fixed somehow.)
I don't think we want at all, really. If we want to import macros, we should have another means of doing it. Otherwise we have an inconsistency. So yes, I think I agree with your last paragraph above all,
I've discussed this a bit in the tracking issue for the macros import system:
Thanks, you expressed the exact concern I had in a concise way.
Another thing this needs to lint is unlisted crates that are included in that clash with existing modules. I'm not quite sure on what the story needs to be here cc
Does it? I've thought one of the things the path clarity RFC was about was to have separate namespaces for top level modules and extern crates.
The current plan has changed a bit so I'm not sure if that is still true. (If stuff does change it will probably be RFCd again, there's a bit of experimentation going on)
Sigh I hope we won't discuss all of this crap all over again... I don't enjoy that but it is not me who wants to change things.
I've hidden your last comment, which I found hostile and unconstructive.
IDK what has been hearing, but for me, this is the latest state of consensus on that issue, and it seems to have separate namespaces: is that the case? You seem unresponsive on IRC that's why I'm using github.
That's mostly the latest state of consensus, yeah. Some tweaks have been made iirc. Everything has been implemented.


Question: sess.abort_if_errors() } } <del> a.add_file(&bc, false); </del> <ins> a.add_file(&bc_deflated, false); remove(sess, &bc_deflated); </ins> if !sess.opts.cg.save_temps && !sess.opts.output_types.contains(&OutputTypeBitcode) { remove(sess, &bc);

Passing rustc the flag and passing may produce different files (that is, outputs). This is true of rust-core (see below), though was not the case for a simpler ("Hello, world!") test file. Test script: Diff output indicates binary files differ. Tested with , rust-core on . rustc compiled from master on Arch Linux. If this is, in fact, expected behavior- sorry for the trouble, unexpected to me.
Can you provide a diff between the outputs? This is likely a known issue, but I would like to be sure.
.bc is a binary format, so just gives "Binary files and differ" as its output. On my machine, is 19K and is 62K. I'm not familiar enough with the format to extract much more data.
I note the difference persists when the second line is (two separate flags), though both produce both artifacts.
Can you pass and diff those outputs?
With emit flags as and respectively, there is no difference in and (according to diff.)
It seems that every bytecode is invalid only when a rlib is produced. It stopped working between rust-git-0.9.1301 and 1362 (shortly before 2014-02-23 15:37:05 -0800). Going back thorugh the log, I found I believe that creates deflated bytecode. Perhaps should be stored with extension or .


Question: /// assert_eq!(&l_ptr[..2], "0x"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] <ins> #[rustc_diagnostic_item = "pointer_trait"] </ins> pub trait Pointer { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] <ins> #[rustc_diagnostic_item = "pointer_trait_fmt"] </ins> fn fmt(&self, f: &mut Formatter<'_>) -> Result; }

I tried this code: I expected to see this happen: The compilation succeed or guide me to (1) cast the to with . (2) borrow the : . But in this case the addresses printed are the same (what?). Instead, this happened*: Cryptic error message: There is : . It took me minutes before I found the workaround. But it still surprised me. : <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
This creates a reference-to-function-pointer (type ), a double indirection. So it is not what you want. The error could possibly be improved, and the entire situation documented better, but I think getting an error is expected here. is not a function pointer, it is an anonymous ) (of size 0) indicating exactly the function it was created from. This type coerces to a function pointer, but cannot know what type to coerce it to. Printing function pointers is easy (well, if they are not polymorphic via ), but printing these function singleton ZSTs is hard.
It might also be worth linting against .
helps with the docs. But to close this issue, it would probably make sense to write a lint against where is the name of a function. That should be a matter of adding a new in which checks all expressions for being . That path we can pass to to get a . Now we just need to check if that refers to a function: pass the to . At least I hope that makes sense, someone stop me if this is all wrong. ;)
I'd like to help write this lint. The default level for the lint should be right? claim
Yeah, feels like a reasonable start.
Nominated for lang team discussion. It seems we usually ask for lints to be approved before shipping them, so let's get that process started. sorry for this, I wasn't aware of this part of the process. You can still go ahead and implement this if you want, but depending on what the lang team decides, we should submit this lint to clippy instead of the compiler itself. That might require minor adjustments, but the main work you are putting in and the testcases will be useful either way.


Question: /// assert_eq!(&l_ptr[..2], "0x"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] <ins> #[rustc_diagnostic_item = "pointer_trait"] </ins> pub trait Pointer { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] <ins> #[rustc_diagnostic_item = "pointer_trait_fmt"] </ins> fn fmt(&self, f: &mut Formatter<'_>) -> Result; }

:)
As a point of interest, this would have been extremely useful in helping debug a segfault in The original code used , not .
Without the cast, this should not compile as transmute checks that the sizes match. I assume what you describe happens when using , i.e., not just remove the but also add a .
Unfortunately I never committed the broken code so I'm not sure what I had originally ... the closest thing is which doesn't compile. Sorry for the noise.
no worries. I already have the lint implemented, but in that case I'll wait until they discuss to write the tests
I think should compile. That's no noise, it seems very relevant. :)
poll T-lang Should we add a lint for taking a reference to a fn?
Team member has asked teams: T-lang, for consensus on: [x] [x] [x] [ ] [x] [ ]
I think I agree here, but to confirm: this isn't actually about linting the taking of a reference to a place of type, but just about using on the voldemort-typed function name constants, right?
Yes.
Discussed in a (rather small) meeting today: Those present felt a lint would make sense. If somebody wanted to go ahead and try to author one, please feel free and nominate the resulting PR for discussion.
all right, so if you want to open a PR, everything is settled for that. :)


Question: <ins> // Issue #117720 #![feature(let_chains)] fn main() { if let () = () && let () = (); //~ERROR && let () = () { } } fn foo() { if let () = () && () == (); //~ERROR && 1 < 0 { } } fn bar() { if let () = () && () == (); //~ERROR && let () = () { } } </ins>

This is a common typo I make when hoisting an inconditional let binding into the let chain to merge two let-chains that could be one. The parser only needs to do look-ahead 1 and 2 to detect the case and recover. No response No response <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
claim


Question: } fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) { <ins> use middle::ty::TypeVariants::{TyEnum, TyStruct}; // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar` self.tcx.tables.borrow().item_substs.get(id) .and_then(|substs| substs.substs.self_ty()) .map(|ty| match ty.sty { TyEnum(tyid, _) | TyStruct(tyid, _) => self.check_def_id(tyid.did), _ => (), }); </ins> self.tcx.def_map.borrow().get(id).map(|def| { match def.full_def() { def::DefConst(_) | def::DefAssociatedConst(..) => {

Warning:
By the way, the warning goes away if you explicitly specify the trait who's static method you are calling, like so:


Question: // Finally we construct the actual value of the associated type. let term = match assoc_def.item.kind { ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), <del> ty::AssocKind::Const => bug!("associated const projection is not supported yet"), </del> <ins> ty::AssocKind::Const => { if tcx.features().associated_const_equality { bug!("associated const projection is not supported yet") } else { ty::EarlyBinder::bind( ty::Const::new_error_with_message( tcx, tcx.type_of(assoc_def.item.def_id).instantiate_identity(), DUMMY_SP, "associated const projection is not supported yet", ) .into(), ) } } </ins> ty::AssocKind::Fn => unreachable!("we should never project to a fn"), };

<!-- 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


Question: that warns about any item named `lintme`. ```rust,ignore (requires-stage-2) <del> #![feature(box_syntax, rustc_private)] </del> <ins> #![feature(rustc_private)] </ins> extern crate rustc_ast;

There is no such thing as boxsyntax anymore :D <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
does the same.
It probably makes sense to search across the repository (including submodules) any references to this removed feature and remove them
claim


Question: } } <ins> fn foreign_item_scope_tag(item: &hir::ForeignItem<'_>) -> &'static str { match item.kind { hir::ForeignItemKind::Fn(..) => "method body", hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => "associated item", } } </ins> fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option<Span>) { let lo = tcx.sess.source_map().lookup_char_pos(span.lo()); (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))

Repro: As of current nightly: This is the unreachable line: The same crash reproduces back to 1.47.0. Older stable compilers do not crash:
Bisect: searched nightlies: from nightly-2020-07-10 to nightly-2020-08-27 regressed nightly: nightly-2020-07-22 searched commits: from to regressed commit: () Mentioning because appears the most relevant.
Assigning .


Question: .map(|r| VerifyBound::OutlivedBy(r)); // see the extensive comment in projection_must_outlive <del> let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); let recursive_bound = self.recursive_bound(ty.into(), visited); </del> <ins> let recursive_bound = { let mut components = smallvec![]; let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); compute_components_recursive(self.tcx, ty.into(), &mut components, visited); self.bound_from_components(&components, visited) }; </ins> VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound) } <del> fn recursive_bound( </del> <ins> fn bound_from_components( </ins> &self, <del> parent: GenericArg<'tcx>, </del> <ins> components: &[Component<'tcx>], </ins> visited: &mut SsoHashSet<GenericArg<'tcx>>, ) -> VerifyBound<'tcx> { <del> let mut bounds = parent .walk_shallow(visited) .filter_map(|child| match child.unpack() { GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), GenericArgKind::Lifetime(lt) => { // Ignore late-bound regions. if !lt.is_late_bound() { Some(VerifyBound::OutlivedBy(lt)) } else { None } } GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)), }) </del> <ins> let mut bounds = components .iter() .map(|component| self.bound_from_single_component(component, visited)) </ins> .filter(|bound| { // Remove bounds that must hold, since they are not interesting. !bound.must_hold()

<!-- 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: Both asserts don't pass. Adding bound on makes it compile. We are requiring all the for closures and generators to outlive here: This is wrong and inconsistent with the logic in <!-- 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. --Build using the Nightly version: 1.63.0-nightly (2022-05-24 ) <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summaryBacktrace</summary<p</p</details label T-compiler A-lifetimes A-closures A-generators claim <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Error: Parsing assign command in failed: ...'bot assign' ''... Please let know if you're having trouble with this bot.


Question: <ins> error[E0277]: `<impl Foo as Foo>::Bar` cannot be sent between threads safely --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:14:20 | LL |     assert_is_send(&bar); |                    ^^^^ `<impl Foo as Foo>::Bar` cannot be sent between threads safely ... LL | fn assert_is_send<T: Send>(_: &T) {} |                      ---- required by this bound in `assert_is_send` | = help: the trait `Send` is not implemented for `<impl Foo as Foo>::Bar` help: introduce a type parameter with a trait bound instead of using `impl Trait` | LL | async fn run<F: Foo>(_: &(), foo: F) -> std::io::Result<()> where <F as Foo>::Bar: Send { |             ^^^^^^^^              ^                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `<impl Foo as Foo>::Bar` cannot be sent between threads safely --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:24:20 | LL |     assert_is_send(&bar); |                    ^^^^ `<impl Foo as Foo>::Bar` cannot be sent between threads safely ... LL | fn assert_is_send<T: Send>(_: &T) {} |                      ---- required by this bound in `assert_is_send` | = help: the trait `Send` is not implemented for `<impl Foo as Foo>::Bar` help: introduce a type parameter with a trait bound instead of using `impl Trait` | LL | async fn run2<F: Foo>(_: &(), foo: F) -> std::io::Result<()> where <F as Foo>::Bar: Send { |              ^^^^^^^^              ^                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. </ins>

(Edit: Actually, being an inherent fn doesn't matter. It happens with top-level fns too.) This prints the diagnostic: The suggestion in the last line is not valid syntax (). It also emits malformed syntax if the first parameter is a or parameter. The diagnostic becomes well-formed if any of the following is done: The first parameter is changed to instead ofThe fn is not an async fn. In either case, the diagnostic correctly says: Happens on both nightly: ... and stable:
This should hopefully be a fairly straightforward patch to the diagnostics code that generates the suggestion.