jiebi/CodeConvo huggingface dataset:
Code change:
error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | <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 |         println!("{}", &x); <del> |                        ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> <ins> |                        ^^ value borrowed here after move </ins> error: aborting due to 5 previous errors

Related discussion:
text: (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).
Code change:
error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | <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 |         println!("{}", &x); <del> |                        ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> <ins> |                        ^^ value borrowed here after move </ins> error: aborting due to 5 previous errors

Related discussion:
text: 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.
Code change:
error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | <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 |         println!("{}", &x); <del> |                        ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> <ins> |                        ^^ value borrowed here after move </ins> error: aborting due to 5 previous errors

Related discussion:
text: 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.
Code change:
error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | <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 |         println!("{}", &x); <del> |                        ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> <ins> |                        ^^ value borrowed here after move </ins> error: aborting due to 5 previous errors

Related discussion:
text: 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?
Code change:
error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | <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 |         println!("{}", &x); <del> |                        ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> <ins> |                        ^^ value borrowed here after move </ins> error: aborting due to 5 previous errors

Related discussion:
text: 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.
Code change:
error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | <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 |         println!("{}", &x); <del> |                        ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> <ins> |                        ^^ value borrowed here after move </ins> error: aborting due to 5 previous errors

Related discussion:
text: 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).
Code change:
error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | <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 |         println!("{}", &x); <del> |                        ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait </del> <ins> |                        ^^ value borrowed here after move </ins> error: aborting due to 5 previous errors

Related discussion:
text: 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:
Code change:
<ins> #![feature(fn_delegation)] #![allow(incomplete_features)] mod to_reuse {} trait Trait { reuse to_reuse::foo { foo } //~^ ERROR cannot find function `foo` in module `to_reuse` //~| ERROR cannot find value `foo` in this scope } fn main() {} </ins>

Related discussion:
text: <!-- [31mICE[0m: Rustc '' 'thread 'rustc' panicked at 'no entry found for key'', 'thread 'rustc' panicked at 'no entry found for key'' 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: [resolverforlowering_raw] getting the resolver for lowering --
this probably crashes since but I haven't verified that yet
smaller
even smaller
Code change:
tt @ &TtSequence(..) => { check_matcher(cx, Some(tt).into_iter(), &Eof); }, <del> _ => cx.span_bug(sp, "wrong-structured lhs for follow check (didn't find  a TtDelimited or TtSequence)") </del> <ins> _ => cx.span_err(sp, "Invalid macro matcher; matchers must be contained  in balanced delimiters or a repetition indicator") </ins> }, _ => cx.span_bug(sp, "wrong-structured lhs for follow check (didn't find a  MatchedNonterminal)")

Related discussion:
text: A simple malformed macro makes the compiler crash. Code: Playpen error: Playpen:
Another case: Playpen:
I had a crash in a bad macro which hits the same bug as Note that his/her error has the following which is a different stack trace: I'm on the latest beta; not nightly.
I think you and I are getting a different panic from this bug. I've opened since the panic is in a different location in the code.
Code change:
<ins> // Regression test for #92111. // // The issue was that we normalize trait bounds before caching // results of selection. Checking that `impl NoDrop for S` requires // checking `S: !Drop` because it cannot overlap with the blanket // impl. Then we save the (unsatisfied) result from checking `S: Drop`. // Then the call to `a` checks whether `S: ~const Drop` but we normalize // it to `S: Drop` which the cache claims to be unsatisfied. // // check-pass #![feature(const_trait_impl)] #![feature(const_fn_trait_bound)] pub trait Tr {} #[allow(drop_bounds)] impl<T: Drop> Tr for T {} #[derive(Debug)] pub struct S(i32); impl Tr for S {} const fn a<T: ~const Drop>(t: T) {} fn main() { a(S(0)); } </ins>

Related discussion:
text: <!-- Thank you for filing a regression report! A regression is something that changed between versions of Rust but was not supposed to. Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. --I tried this code: I expected to see this happen: print (from Debug impl) Instead, this happened: E0277, trait impl not found This was found by CI in the Ruffle Project: The issue is caused by the effective anti-bound of Drop, introduced by the manual impl of the trait, as well as the PR which introduced bounds for a number of functions in . It most recently worked on: rustc 1.59.0-nightly ( 2021-12-18) : modify labels: +regression-from-stable-to-nightly -regression-untriaged
cc
Code change:
<ins> // Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. macro_rules! items { () => { type A = (); fn a() {} } } trait Foo { type A; fn a(); } impl Foo for () { items!(); } fn main() { } </ins>

Related discussion:
text: Mm, we have "method macros" but now there are other things that can go in a trait.
Seems to be fixed by , but I don't see tests for it specifically, so I guess this needs tests.
Code change:
<ins> // Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. macro_rules! items { () => { type A = (); fn a() {} } } trait Foo { type A; fn a(); } impl Foo for () { items!(); } fn main() { } </ins>

Related discussion:
text: Rust Version: rustc 1.0.0-nightly ( 2015-02-12 00:38:24 +0000) Description: When compiling the following code with rustc the output is: ERROR:rbml::reader: failed to find block with tag 7 error: internal compiler error: unexpected panic note: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: note: run with for a backtrace thread 'rustc' panicked at 'explicit panic', C:botslavenightly-dist-rustc-win-64buildsrclibrbml stack backtrace: 1: 0x69bfbbeb - sys::backtrace::write::h57b621d79849130fitB 2: 0x69c13974 - rt::unwind::register::h686925f8fa692ab9GSJ 3: 0x69b836ef - rt::unwind::beginunwindinner::hc2a974b1bdaa4639YPJ 4: 0x302da8 - reader::maybegetdoc::h2547f886a15a227erHa 5: 0x301d2f - reader::getdoc::hc198b8918d0de179nLa 6: 0x1138635 - metadata::decoder::itemtype::h7f6e008c4a79af18mck 7: 0x11480d9 - metadata::decoder::gettype::h9620389d7a7d23c0Xok 8: 0x10fb7a8 - metadata::csearch::gettype::h3af5a6a2534b2d8bCkn 9: 0x6d605059 - collect::CollectCtxt<'a, 'tcx.AstConv<'tcx::getitemtypescheme::he174d5be00f2627cMFw 10: 0x6d5f49ab - rscope::ShiftedRscope<'r.RegionScope::anonregions::h0a5ed4a2d46d3aeeqlu 11: 0x6d5f64ef - rscope::ShiftedRscope<'r.