Skip to content
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

add fut/back compat tests for implied trait bounds #93732

Merged
merged 2 commits into from
Feb 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}