]> git.lizzy.rs Git - rust.git/commitdiff
add fut/back compat tests for implied trait bounds
authorlcnr <rust@lcnr.de>
Mon, 7 Feb 2022 08:17:44 +0000 (09:17 +0100)
committerlcnr <rust@lcnr.de>
Mon, 7 Feb 2022 08:33:22 +0000 (09:33 +0100)
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs [new file with mode: 0644]
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr [new file with mode: 0644]
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs [new file with mode: 0644]

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 (file)
index 0000000..d79f63d
--- /dev/null
@@ -0,0 +1,51 @@
+// A test exploiting the bug behind #25860 except with
+// implied trait bounds which currently don't exist,
+//
+// please ping @lcnr if your changes end up causing `badboi` to compile.
+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>`
+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 (file)
index 0000000..b020ea6
--- /dev/null
@@ -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 (file)
index 0000000..69847d6
--- /dev/null
@@ -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;
+}