about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-02-08 16:40:50 +0100
committerGitHub <noreply@github.com>2022-02-08 16:40:50 +0100
commite881d655c4ea13649d60013a0d62ec2ec59d3797 (patch)
tree3d274af2efac552935d153843e3d9e23c0c54108
parent9cb39a6083c34f2266ec4f2235deda7bdab60b06 (diff)
parentaf9e30a326b56bca01ef3a7694ab8a117d791885 (diff)
downloadrust-e881d655c4ea13649d60013a0d62ec2ec59d3797.tar.gz
rust-e881d655c4ea13649d60013a0d62ec2ec59d3797.zip
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
-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 00000000000..d9de73a38ef
--- /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 00000000000..b020ea64bf4
--- /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 00000000000..69847d6a8bb
--- /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;
+}