62 lines
1.9 KiB
Rust
62 lines
1.9 KiB
Rust
// A test exploiting the bug behind #25860 except with
|
|
// implied trait bounds which currently don't exist.
|
|
use std::marker::PhantomData;
|
|
struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
|
|
where
|
|
T: Convert<'a, 'b>;
|
|
|
|
trait Convert<'a, 'b>: Sized {
|
|
fn cast(&'a self) -> &'b Self;
|
|
}
|
|
impl<'long: 'short, 'short, T> Convert<'long, 'short> for T {
|
|
fn cast(&'long self) -> &'short T {
|
|
self
|
|
}
|
|
}
|
|
|
|
// This function will compile once we add implied trait bounds.
|
|
//
|
|
// If we're not careful with our impl, the transformations
|
|
// in `bad` would succeed, which is unsound ✨
|
|
//
|
|
// FIXME: the error is pretty bad, this should say
|
|
//
|
|
// `T: Convert<'in_, 'out>` is not implemented
|
|
//
|
|
// help: needed by `Foo<'in_, 'out, T>`
|
|
//
|
|
// Please ping @lcnr if your changes end up causing `badboi` to compile.
|
|
fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
|
|
//~^ ERROR lifetime mismatch
|
|
sadness.cast()
|
|
}
|
|
|
|
fn badboi2<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) {
|
|
//~^ ERROR lifetime mismatch
|
|
let _: &'out T = sadness.cast();
|
|
}
|
|
|
|
fn badboi3<'in_, 'out, T>(a: Foo<'in_, 'out, (&'in_ T, &'out T)>, sadness: &'in_ T) {
|
|
//~^ ERROR lifetime mismatch
|
|
let _: &'out T = sadness.cast();
|
|
}
|
|
|
|
fn bad<'short, T>(value: &'short T) -> &'static T {
|
|
let x: for<'in_, 'out> fn(Foo<'in_, 'out, T>, &'in_ T) -> &'out T = badboi;
|
|
let x: for<'out> fn(Foo<'short, 'out, T>, &'short T) -> &'out T = x;
|
|
let x: for<'out> fn(Foo<'static, 'out, T>, &'short T) -> &'out T = x;
|
|
let x: fn(Foo<'static, 'static, T>, &'short T) -> &'static T = x;
|
|
x(Foo(PhantomData), value)
|
|
}
|
|
|
|
// Use `bad` to cause a segfault.
|
|
fn main() {
|
|
let mut outer: Option<&'static u32> = Some(&3);
|
|
let static_ref: &'static &'static u32 = match outer {
|
|
Some(ref reference) => bad(reference),
|
|
None => unreachable!(),
|
|
};
|
|
outer = None;
|
|
println!("{}", static_ref);
|
|
}
|