Skip to content

Commit e881d65

Browse files
authored
Rollup merge of #93732 - lcnr:hrlt-backcompa, r=Mark-Simulacrum
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
2 parents 9cb39a6 + af9e30a commit e881d65

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// A test exploiting the bug behind #25860 except with
2+
// implied trait bounds which currently don't exist without `-Zchalk`.
3+
use std::marker::PhantomData;
4+
struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
5+
where
6+
T: Convert<'a, 'b>;
7+
8+
trait Convert<'a, 'b>: Sized {
9+
fn cast(&'a self) -> &'b Self;
10+
}
11+
impl<'long: 'short, 'short, T> Convert<'long, 'short> for T {
12+
fn cast(&'long self) -> &'short T {
13+
self
14+
}
15+
}
16+
17+
// This function will compile once we add implied trait bounds.
18+
//
19+
// If we're not careful with our impl, the transformations
20+
// in `bad` would succeed, which is unsound ✨
21+
//
22+
// FIXME: the error is pretty bad, this should say
23+
//
24+
// `T: Convert<'in_, 'out>` is not implemented
25+
//
26+
// help: needed by `Foo<'in_, 'out, T>`
27+
//
28+
// Please ping @lcnr if your changes end up causing `badboi` to compile.
29+
fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
30+
//~^ ERROR lifetime mismatch
31+
sadness.cast()
32+
}
33+
34+
fn bad<'short, T>(value: &'short T) -> &'static T {
35+
let x: for<'in_, 'out> fn(Foo<'in_, 'out, T>, &'in_ T) -> &'out T = badboi;
36+
let x: for<'out> fn(Foo<'short, 'out, T>, &'short T) -> &'out T = x;
37+
let x: for<'out> fn(Foo<'static, 'out, T>, &'short T) -> &'out T = x;
38+
let x: fn(Foo<'static, 'static, T>, &'short T) -> &'static T = x;
39+
x(Foo(PhantomData), value)
40+
}
41+
42+
// Use `bad` to cause a segfault.
43+
fn main() {
44+
let mut outer: Option<&'static u32> = Some(&3);
45+
let static_ref: &'static &'static u32 = match outer {
46+
Some(ref reference) => bad(reference),
47+
None => unreachable!(),
48+
};
49+
outer = None;
50+
println!("{}", static_ref);
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0623]: lifetime mismatch
2+
--> $DIR/hrlt-implied-trait-bounds-guard.rs:29:29
3+
|
4+
LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
5+
| ^^^^^^^^^^^^^^^^^^ -------
6+
| |
7+
| this parameter and the return type are declared with different lifetimes...
8+
| ...but data from `x` is returned here
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0623`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// check-pass
2+
struct Foo<'a>(&'a ())
3+
where
4+
(): Trait<'a>;
5+
6+
trait Trait<'a> {
7+
fn id<T>(value: &'a T) -> &'static T;
8+
}
9+
10+
impl Trait<'static> for () {
11+
fn id<T>(value: &'static T) -> &'static T {
12+
value
13+
}
14+
}
15+
16+
fn could_use_implied_bounds<'a, T>(_: Foo<'a>, x: &'a T) -> &'static T
17+
where
18+
(): Trait<'a>, // This could be an implied bound
19+
{
20+
<()>::id(x)
21+
}
22+
23+
fn main() {
24+
let bar: for<'a, 'b> fn(Foo<'a>, &'b ()) = |_, _| {};
25+
26+
// If `could_use_implied_bounds` were to use implied bounds,
27+
// keeping 'a late-bound, then we could assign that function
28+
// to this variable.
29+
let bar: for<'a> fn(Foo<'a>, &'a ()) = bar;
30+
31+
// In this case, the subtyping relation here would be unsound,
32+
// allowing us to transmute lifetimes. This currently compiles
33+
// because we incorrectly deal with implied bounds inside of binders.
34+
let _bar: for<'a, 'b> fn(Foo<'a>, &'b ()) = bar;
35+
}

0 commit comments

Comments
 (0)