-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lifetime bounds in Copy impls are ignored #29149
Comments
Nominating. |
triage: P-high |
Correct behavior here is not entirely obvious, given that we erase lifetimes at trans. Possibly we should be treating this affine, or possibly the impl should be an error? Have to mull this over. cc @rust-lang/lang |
Nominating for discussion at the lang meeting. |
So my feeling is that the |
(I assume this means e.g. that |
So now that I've thought about this I agree with @pnkfelix. We should use the dropck code to enforce this constraint. |
There is a catch -- we can't use the precise dropck check. We don't want all instances of a type to be impl<T:Copy> Copy for Option<T> { } Probably we want a "lifetime dispatch" predicate exactly like the one that @aturon was experimenting with for specialization -- basically we want to know the same property here. That is, we want to know that the Copy-ness is not decided by the lifetimes, because we view those as outputs of trait selection, not inputs. |
And, in fact, the problem runs deeper -- just as with specialization, the All this makes me wonder: maybe we are taking the wrong approach. Maybe we should run borrowck and find all values that are used more than once and then add a requirement then that they be Not sure just what would be affected. I know that MIR construction uses "is this Copy?" to avoid creating needless drops, but that's really just a heuristic. I'd have to go look where-else this comes up. |
This can get messier with associated types, as they can introduce lifetime bounds on their own: trait Foo { type Out; }
#[derive(Clone)]
struct S<T: Foo>(T::Out);
impl<T: Foo> Copy for S where T::Out: Copy {}
impl<'a> Foo for (&'a u32, &'a u32) {
type Out = u32;
} |
But then the new lifetime bounds can affect (lifetime) inference. |
@arielb1 Yes, that's true. The other place that I've found where a complication arises is in closure inference, which uses copy-vs-move to decide how to handle upvars in some cases. |
OK, so, I see two viable candidates as of now:
The first seems obviously superior in that it doesn't require explaining to people why a move occurred when they expected a copy. |
So I did some investigation here and I believe I have a simple proposal that would solve this problem. We can restrict |
Will associated types not be a problem? |
Maybe, but I don't quite see how yet. Can you give an example of where you think a problem would arise? Earlier, you wrote this, but I don't quite understand what you were getting at: trait Foo { type Out; }
#[derive(Clone)]
struct S<T: Foo>(T::Out);
impl<T: Foo> Copy for S where T::Out: Copy {}
impl<'a> Foo for (&'a u32, &'a u32) {
type Out = u32;
} In particular here, it doesn't seem like there are any lifetime bounds that are not already guaranteed by WF, right? |
Maybe they are not actually an issue, because |
Is anyone interested in spearheading this issue? I'm assigned, but I'm pretty overloaded. An RFC would probably be nice. I think we could just write one, but it'd be even better if we could implement the proposed solution so we can measure the impact with a crater run. I prefer this fix. Logical candidates to do this work: |
Hey @nikomatsakis thanks for the heads up, yeah if you want I'd be happy to tackle this one :) |
That's basically it, but instead of |
If we can ever get rid of MC/EUV, then maybe |
@eddyb I think we will wind up needing something like MC/EUV, because it's needed for upvar inference, but I suspect we can redesign it to be radically better and simpler. |
cc @spastorino -- all the pieces are in place to fix this now, I think. We should use this example: #![feature(nll)]
#[derive(Clone)] struct Foo<'a>(&'a u32);
impl Copy for Foo<'static> {}
fn main() {
let s = 2;
let a = Foo(&s);
drop(a);
drop(a);
} we basically want to change this existing code: rust/src/librustc_mir/borrow_check/nll/type_check/mod.rs Lines 376 to 384 in 5c41fce
so that it invokes rust/src/librustc_mir/borrow_check/nll/type_check/mod.rs Lines 1486 to 1493 in 5c41fce
In other words, rather than testing that |
Fixed (with NLL) in #47877 |
… r=nikomatsakis Do not ignore lifetime bounds in Copy impls cc rust-lang#29149 r? @nikomatsakis
… r=nikomatsakis Do not ignore lifetime bounds in Copy impls cc rust-lang#29149 r? @nikomatsakis
… r=nikomatsakis Do not ignore lifetime bounds in Copy impls cc rust-lang#29149 r? @nikomatsakis
nll requires these annotations, I believe because of rust-lang#29149
nll requires these annotations, I believe because of rust-lang#29149
nll requires these annotations, I believe because of rust-lang#29149
…reemap-annotations, r=gankro add outlives annotations to `BTreeMap` NLL requires these annotations, I believe because of <rust-lang#29149>. Fixes rust-lang#48224 r? @gankro cc @lqd
…reemap-annotations, r=gankro add outlives annotations to `BTreeMap` NLL requires these annotations, I believe because of <rust-lang#29149>. Fixes rust-lang#48224 r? @gankro cc @lqd
…reemap-annotations, r=gankro add outlives annotations to `BTreeMap` NLL requires these annotations, I believe because of <rust-lang#29149>. Fixes rust-lang#48224 r? @gankro cc @lqd
UPDATE: Mentoring instructions below.
Affected Versions
rustc 1.3.0 - 1.5.0
STR
Expected Result
Foo<'a>
is notCopy
, so this should cause a borrowck error.Actual Result
The code compiles :-).
cc @nikomatsakis
The text was updated successfully, but these errors were encountered: