summaryrefslogtreecommitdiffstats
path: root/tests/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
blob: c177655c5acf549cae437f52356d139ba452c7c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// A test exploiting the bug behind #25860 except with
// implied trait bounds which currently don't exist without `-Ztrait-solver=chalk`.
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);
}