summaryrefslogtreecommitdiffstats
path: root/src/test/ui/implied-bounds
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/implied-bounds')
-rw-r--r--src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs51
-rw-r--r--src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr12
-rw-r--r--src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs35
3 files changed, 98 insertions, 0 deletions
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
new file mode 100644
index 000000000..d9de73a38
--- /dev/null
+++ b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
@@ -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);
+}
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr
new file mode 100644
index 000000000..b020ea64b
--- /dev/null
+++ b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr
@@ -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`.
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs
new file mode 100644
index 000000000..69847d6a8
--- /dev/null
+++ b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs
@@ -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;
+}