diff options
Diffstat (limited to 'tests/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs')
-rw-r--r-- | tests/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/tests/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs b/tests/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs new file mode 100644 index 000000000..c177655c5 --- /dev/null +++ b/tests/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs @@ -0,0 +1,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); +} |