-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Closures in methods can return pointers with short lifetimes #18899
Comments
And look at this: fn main() {
println!("{}", vec![1i8,2,3].iter().max_by(|n| n + 0).map(|&e|e))
} Gives:
??? This compiles and runs fine: fn main() {
println!("{}", vec![1i8,2,3].iter().max_by(|n|**n + 0).map(|&e|e))
} And your example:
Works fine like that. Hmm... |
Yes, that is expected because |
Trying to narrow it down reveals something strange. I created a trait // Defining max_by as a function appears not to work because it refuses the `|n|n` closure due to some lifetime issue
trait MaxBye<A> {
fn max_bye<B: Ord + std::fmt::Show>(&mut self, f: |&A| -> B) -> Option<A>;
}
impl <A: std::fmt::Show, T: Iterator<A>> MaxBye<A> for T {
fn max_bye<B: Ord + std::fmt::Show>(&mut self, f: |&A| -> B) -> Option<A> {
self.fold(None, |max: Option<(A, B)>, x| {
for &(_,ref b) in max.iter() { println!("Current: {}, previous: {}",&x, b); }
let x_val = f(&x);
match max {
None => Some((x, x_val)),
Some((y, y_val)) => {
if x_val > y_val {
Some((x, x_val))
} else {
Some((y, y_val))
}
}
}
}
).map(|(x, _)| x)
}
}
fn main() {
let v = vec!(1u8 , 2 , 3);
println!("{}" , v.iter().max_bye(|n|n).map(|&e|e));
} The above code will print
Which is very strange, because I would expect
When I change the match to:
It indeed reveals that |
Oops, I didn't follow the discussion carefully. Let me retract my old comment here. |
This is not the case, This looks like it may be a misoptimisation (similar to #18786). |
Ah, it's not a misoptimisation: it's rustc being bad. @Thiez correctly picked it out with:
and
The lifetime issue is real, and it is entirely invalid to write I've edited the issue & title to reflect the above. |
A minimal code for reproducing the bug. struct S;
impl S {
fn f<B: std::fmt::Show>(&self, g: |&i32| -> B) {
let h = |x| { g(&x) };
let r = h(10);
/*
let r = g(&10_i32);
*/
println!("r == {}", r); // r == 32767 ???
}
}
fn main() {
let s = S;
s.f(|p| {
println!("p == {}", p);
p
})
} The above code shouln't pass the lifetime check, but it does; that is the bug.
Also note that |
It looks very much alike but my original example is wrong for all optimization levels (at least on the playpen), so are we observing the same bug? |
@Thiez I think so. I updated my previous comment because my wording was misleading. |
The bug here is the compiler letting this through at all; the consequences can manifest in different ways but they're all just (unfortunate) flow-on from the original problem of methods apparently not being checked. Since this is all undefined behaviour, the specific details of what will go wrong at runtime are hard to predict and aren't really that "interesting" (it's undefined behaviour, so it could be anything). |
P-backcompat-lang, 1.0. |
So the key problem is this closure:
which should not type check, as far as I can tell. The pointer |
I'll investigate a bit while the HRTB builds go. |
I think the problem is that we don't do call |
fix: Fix another issue with fixup reversing
function
and the two methods are basically identical, except onlyfunction
correctly gets an error (there's no lifetime connection between the returnedB
and the reference passed to the closure so it should be illegal to return that reference directly).Old report:
Iterator.max_by does strange things.
Example:
I would really expect this asertion to fail, because the answer should be
Some(3)
.The text was updated successfully, but these errors were encountered: