Skip to content

Commit

Permalink
Rollup merge of #93732 - lcnr:hrlt-backcompa, r=Mark-Simulacrum
Browse files Browse the repository at this point in the history
add fut/back compat tests for implied trait bounds

the `guard` test was tested to cause a segfault with `-Zchalk`, very nice

cc ``@nikomatsakis`` #44491 #25860
  • Loading branch information
matthiaskrgr authored Feb 8, 2022
2 parents 9cb39a6 + af9e30a commit e881d65
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// A test exploiting the bug behind #25860 except with
// implied trait bounds which currently don't exist without `-Zchalk`.
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 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);
}
12 changes: 12 additions & 0 deletions src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0623]: lifetime mismatch
--> $DIR/hrlt-implied-trait-bounds-guard.rs:29:29
|
LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
| ^^^^^^^^^^^^^^^^^^ -------
| |
| this parameter and the return type are declared with different lifetimes...
| ...but data from `x` is returned here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0623`.
35 changes: 35 additions & 0 deletions src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// check-pass
struct Foo<'a>(&'a ())
where
(): Trait<'a>;

trait Trait<'a> {
fn id<T>(value: &'a T) -> &'static T;
}

impl Trait<'static> for () {
fn id<T>(value: &'static T) -> &'static T {
value
}
}

fn could_use_implied_bounds<'a, T>(_: Foo<'a>, x: &'a T) -> &'static T
where
(): Trait<'a>, // This could be an implied bound
{
<()>::id(x)
}

fn main() {
let bar: for<'a, 'b> fn(Foo<'a>, &'b ()) = |_, _| {};

// If `could_use_implied_bounds` were to use implied bounds,
// keeping 'a late-bound, then we could assign that function
// to this variable.
let bar: for<'a> fn(Foo<'a>, &'a ()) = bar;

// In this case, the subtyping relation here would be unsound,
// allowing us to transmute lifetimes. This currently compiles
// because we incorrectly deal with implied bounds inside of binders.
let _bar: for<'a, 'b> fn(Foo<'a>, &'b ()) = bar;
}

0 comments on commit e881d65

Please sign in to comment.