From adb5ded7a71911f66e20dd3a85dd39fb236c476d Mon Sep 17 00:00:00 2001 From: whtahy Date: Tue, 18 Apr 2023 00:29:01 -0400 Subject: [PATCH 01/11] add known-bug test for unsound issue 25860 --- ...-bounds-on-nested-references-plus-variance.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs new file mode 100644 index 0000000000000..1f5562497c12e --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs @@ -0,0 +1,16 @@ +// check-pass +// known-bug: #25860 + +// Should fail. The combination of variance and implied bounds for nested +// references allows us to infer a longer lifetime than we can prove. + +static UNIT: &'static &'static () = &&(); + +fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v } + +fn bad<'a, T>(x: &'a T) -> &'static T { + let f: fn(_, &'a T) -> &'static T = foo; + f(UNIT, x) +} + +fn main() {} From 2fb20985a000a8f1cd891ef484f7265a55c1612f Mon Sep 17 00:00:00 2001 From: whtahy Date: Tue, 18 Apr 2023 19:42:48 -0400 Subject: [PATCH 02/11] add known-bug test for unsound issue 49206 --- .../ui/consts/non-sync-references-in-const.rs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/ui/consts/non-sync-references-in-const.rs diff --git a/tests/ui/consts/non-sync-references-in-const.rs b/tests/ui/consts/non-sync-references-in-const.rs new file mode 100644 index 0000000000000..0f668b8d46903 --- /dev/null +++ b/tests/ui/consts/non-sync-references-in-const.rs @@ -0,0 +1,38 @@ +// check-pass +// known-bug: #49206 + +// Should fail. Compiles and prints 2 identical addresses, which shows 2 threads +// with the same `'static` reference to non-`Sync` struct. The problem is that +// promotion to static does not check if the type is `Sync`. + +#[allow(dead_code)] +#[derive(Debug)] +struct Foo { + value: u32, +} + +// stable negative impl trick from https://crates.io/crates/negative-impl +// see https://github.com/taiki-e/pin-project/issues/102#issuecomment-540472282 +// for details. +struct Wrapper<'a, T>(::std::marker::PhantomData<&'a ()>, T); +unsafe impl Sync for Wrapper<'_, T> where T: Sync {} +unsafe impl<'a> std::marker::Sync for Foo where Wrapper<'a, *const ()>: Sync {} +fn _assert_sync() {} + +fn inspect() { + let foo: &'static Foo = &Foo { value: 1 }; + println!( + "I am in thread {:?}, address: {:p}", + std::thread::current().id(), + foo as *const Foo, + ); +} + +fn main() { + // _assert_sync::(); // uncomment this line causes compile error + // "`*const ()` cannot be shared between threads safely" + + let handle = std::thread::spawn(inspect); + inspect(); + handle.join().unwrap(); +} From 232d685e6149227abb28c8fef05b00c4f50bbd28 Mon Sep 17 00:00:00 2001 From: whtahy Date: Tue, 18 Apr 2023 21:30:21 -0400 Subject: [PATCH 03/11] add known-bug test for unsound issue 57893 --- .../indirect-impl-for-trait-obj-coherence.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs new file mode 100644 index 0000000000000..bb46498f90eba --- /dev/null +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs @@ -0,0 +1,25 @@ +// check-pass +// known-bug: #57893 + +// Should fail. Because we see an impl that uses a certain associated type, we +// type-check assuming that impl is used. However, this conflicts with the +// "implicit impl" that we get for trait objects, violating coherence. + +trait Object { + type Output; +} + +impl Object for T { + type Output = U; +} + +fn foo(x: >::Output) -> U { + x +} + +#[allow(dead_code)] +fn transmute(x: T) -> U { + foo::, U>(x) +} + +fn main() {} From fbfb620de8afdabddfa819e698cdbfc7a7b10797 Mon Sep 17 00:00:00 2001 From: whtahy Date: Tue, 18 Apr 2023 23:11:43 -0400 Subject: [PATCH 04/11] add known-bug test for unsound issue 84366 --- .../static-closures-with-nonstatic-return.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/ui/closures/static-closures-with-nonstatic-return.rs diff --git a/tests/ui/closures/static-closures-with-nonstatic-return.rs b/tests/ui/closures/static-closures-with-nonstatic-return.rs new file mode 100644 index 0000000000000..b5f0684bae92b --- /dev/null +++ b/tests/ui/closures/static-closures-with-nonstatic-return.rs @@ -0,0 +1,15 @@ +// check-pass +// known-bug: #84366 + +// Should fail. Associated types of 'static types should be `'static`, but +// argument-free closures can be `'static` and return non-`'static` types. + +#[allow(dead_code)] +fn foo<'a>() { + let closure = || -> &'a str { "" }; + assert_static(closure); +} + +fn assert_static(_: T) {} + +fn main() {} From cac62ab2dde20adca6e1a9070211afbc784c1d64 Mon Sep 17 00:00:00 2001 From: whtahy Date: Tue, 18 Apr 2023 23:55:20 -0400 Subject: [PATCH 05/11] add known-bug test for unsound issue 84533 --- tests/ui/fn/fn-item-lifetime-bounds.rs | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/ui/fn/fn-item-lifetime-bounds.rs diff --git a/tests/ui/fn/fn-item-lifetime-bounds.rs b/tests/ui/fn/fn-item-lifetime-bounds.rs new file mode 100644 index 0000000000000..68a1d0ce9b0b2 --- /dev/null +++ b/tests/ui/fn/fn-item-lifetime-bounds.rs @@ -0,0 +1,37 @@ +// check-pass +// known-bug: #84533 + +// Should fail. Lifetimes are checked correctly when `foo` is called, but NOT +// when only the lifetime parameters are instantiated. + +use std::marker::PhantomData; + +#[allow(dead_code)] +fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> { + PhantomData +} + +#[allow(dead_code)] +#[allow(path_statements)] +fn caller<'b, 'a>() { + foo::<'b, 'a>; +} + +// In contrast to above, below code correctly does NOT compile. +// fn caller<'b, 'a>() { +// foo::<'b, 'a>(); +// } + +// error: lifetime may not live long enough +// --> src/main.rs:22:5 +// | +// 21 | fn caller<'b, 'a>() { +// | -- -- lifetime `'a` defined here +// | | +// | lifetime `'b` defined here +// 22 | foo::<'b, 'a>(); +// | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` +// | +// = help: consider adding the following bound: `'a: 'b` + +fn main() {} From be68c69e7123fbe513c1f5689f61018e3f94220e Mon Sep 17 00:00:00 2001 From: whtahy Date: Wed, 19 Apr 2023 00:44:07 -0400 Subject: [PATCH 06/11] add known-bug test for unsound issue 84591 --- .../implied-bounds-on-trait-hierarchy.rs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy.rs diff --git a/tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy.rs b/tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy.rs new file mode 100644 index 0000000000000..9c26cd59d100a --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy.rs @@ -0,0 +1,39 @@ +// check-pass +// known-bug: #84591 + +// Should fail. Subtrait can incorrectly extend supertrait lifetimes even when +// supertrait has weaker implied bounds than subtrait. Strongly related to +// issue #25860. + +trait Subtrait: Supertrait {} +trait Supertrait { + fn action(self); +} + +fn subs_to_soup(x: T) +where + T: Subtrait, +{ + soup(x) +} + +fn soup(x: T) { + x.action(); +} + +impl<'a, 'b: 'a> Supertrait for (&'b str, &mut &'a str) { + fn action(self) { + *self.1 = self.0; + } +} + +impl<'a, 'b> Subtrait<&'a &'b str> for (&'b str, &mut &'a str) {} + +fn main() { + let mut d = "hi"; + { + let x = "Hello World".to_string(); + subs_to_soup((x.as_str(), &mut d)); + } + println!("{}", d); +} From 3c5de9a2e85e4490fad8c30a8078ac7117a01836 Mon Sep 17 00:00:00 2001 From: whtahy Date: Thu, 20 Apr 2023 01:16:21 -0400 Subject: [PATCH 07/11] add known-bug test for unsound issue 85099 --- .../pin-unsound-issue-85099-derefmut.rs | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs new file mode 100644 index 0000000000000..03602144e5001 --- /dev/null +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs @@ -0,0 +1,68 @@ +// check-pass +// known-bug: #85099 + +// Should fail. Can coerce `Pin` into `Pin` where +// `T: Deref` and `U: Deref`, using the +// `CoerceUnsized` impl on `Pin` and an unorthodox `DerefMut` impl for +// `Pin<&_>`. + +// This should not be allowed, since one can unpin `T::Target` (since it is +// `Unpin`) to gain unpinned access to the previously pinned `U::Target` (which +// is `!Unpin`) and then move it. + +use std::{ + cell::{RefCell, RefMut}, + future::Future, + ops::DerefMut, + pin::Pin, +}; + +struct SomeLocalStruct<'a, Fut>(&'a RefCell); + +trait SomeTrait<'a, Fut> { + #[allow(clippy::mut_from_ref)] + fn deref_helper(&self) -> &mut (dyn SomeTrait<'a, Fut> + 'a) { + unimplemented!() + } + fn downcast(self: Pin<&mut Self>) -> Pin<&mut Fut> { + unimplemented!() + } +} + +impl<'a, Fut: Future> SomeTrait<'a, Fut> for SomeLocalStruct<'a, Fut> { + fn deref_helper(&self) -> &mut (dyn SomeTrait<'a, Fut> + 'a) { + let x = Box::new(self.0.borrow_mut()); + let x: &'a mut RefMut<'a, Fut> = Box::leak(x); + &mut **x + } +} +impl<'a, Fut: Future> SomeTrait<'a, Fut> for Fut { + fn downcast(self: Pin<&mut Self>) -> Pin<&mut Fut> { + self + } +} + +impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { + fn deref_mut<'c>( + self: &'c mut Pin<&'b dyn SomeTrait<'a, Fut>>, + ) -> &'c mut (dyn SomeTrait<'a, Fut> + 'b) { + self.deref_helper() + } +} + +// obviously a "working" function with this signature is problematic +pub fn unsound_pin>( + fut: Fut, + callback: impl FnOnce(Pin<&mut Fut>), +) -> Fut { + let cell = RefCell::new(fut); + let s: &SomeLocalStruct<'_, Fut> = &SomeLocalStruct(&cell); + let p: Pin>> = Pin::new(Pin::new(s)); + let mut p: Pin>> = p; + let r: Pin<&mut dyn SomeTrait<'_, Fut>> = p.as_mut(); + let f: Pin<&mut Fut> = r.downcast(); + callback(f); + cell.into_inner() +} + +fn main() {} From 314126257d3d20e3e788325f3b88b7e635bd6bb8 Mon Sep 17 00:00:00 2001 From: whtahy Date: Sat, 22 Apr 2023 13:31:00 -0400 Subject: [PATCH 08/11] add known-bug test for unsound issue 98117 --- tests/ui/wf/wf-in-where-clause-static.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/ui/wf/wf-in-where-clause-static.rs diff --git a/tests/ui/wf/wf-in-where-clause-static.rs b/tests/ui/wf/wf-in-where-clause-static.rs new file mode 100644 index 0000000000000..86722afdf9fdd --- /dev/null +++ b/tests/ui/wf/wf-in-where-clause-static.rs @@ -0,0 +1,23 @@ +// check-pass +// known-bug: #98117 + +// Should fail. Functions are responsible for checking the well-formedness of +// their own where clauses, so this should fail and require an explicit bound +// `T: 'static`. + +use std::fmt::Display; + +trait Static: 'static {} +impl Static for &'static T {} + +fn foo(x: S) -> Box +where + &'static S: Static, +{ + Box::new(x) +} + +fn main() { + let s = foo(&String::from("blah blah blah")); + println!("{}", s); +} From cff6c0e0c8d33efe4b64b08751008ac353c9b232 Mon Sep 17 00:00:00 2001 From: whtahy Date: Sat, 22 Apr 2023 13:37:13 -0400 Subject: [PATCH 09/11] add known-bug test for unsound issue 100041 --- tests/ui/wf/wf-normalization-sized.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/ui/wf/wf-normalization-sized.rs diff --git a/tests/ui/wf/wf-normalization-sized.rs b/tests/ui/wf/wf-normalization-sized.rs new file mode 100644 index 0000000000000..473fc79a8a39d --- /dev/null +++ b/tests/ui/wf/wf-normalization-sized.rs @@ -0,0 +1,19 @@ +// check-pass +// known-bug: #100041 + +// Should fail. Normalization can bypass well-formedness checking. +// `[[[[[[u8]]]]]]` is not a well-formed type since size of type `[u8]` cannot +// be known at compile time (since `Sized` is not implemented for `[u8]`). + +trait WellUnformed { + type RequestNormalize; +} + +impl WellUnformed for T { + type RequestNormalize = (); +} + +const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); +const _: as WellUnformed>::RequestNormalize = (); + +fn main() {} From 6f6550f156eb6ea18e90db1712b30460613ad4a8 Mon Sep 17 00:00:00 2001 From: whtahy Date: Sat, 22 Apr 2023 13:41:53 -0400 Subject: [PATCH 10/11] add known-bug test for unsound issue 100051 --- .../implied-bounds-impl-header-projections.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/ui/fn/implied-bounds-impl-header-projections.rs diff --git a/tests/ui/fn/implied-bounds-impl-header-projections.rs b/tests/ui/fn/implied-bounds-impl-header-projections.rs new file mode 100644 index 0000000000000..28cec8050327f --- /dev/null +++ b/tests/ui/fn/implied-bounds-impl-header-projections.rs @@ -0,0 +1,31 @@ +// check-pass +// known-bug: #100051 + +// Should fail. Implied bounds from projections in impl headers can create +// improper lifetimes. Variant of issue #98543 which was fixed by #99217. + +trait Trait { + type Type; +} + +impl Trait for T { + type Type = (); +} + +trait Extend<'a, 'b> { + fn extend(self, s: &'a str) -> &'b str; +} + +impl<'a, 'b> Extend<'a, 'b> for <&'b &'a () as Trait>::Type +where + for<'what, 'ever> &'what &'ever (): Trait, +{ + fn extend(self, s: &'a str) -> &'b str { + s + } +} + +fn main() { + let y = <() as Extend<'_, '_>>::extend((), &String::from("Hello World")); + println!("{}", y); +} From ebe61cefc4fa30f0a719892d544abcaee25da44c Mon Sep 17 00:00:00 2001 From: whtahy Date: Sat, 22 Apr 2023 13:57:34 -0400 Subject: [PATCH 11/11] add known-bug test for unsound issue 104005 --- tests/ui/wf/wf-in-fn-type-implicit.rs | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/ui/wf/wf-in-fn-type-implicit.rs diff --git a/tests/ui/wf/wf-in-fn-type-implicit.rs b/tests/ui/wf/wf-in-fn-type-implicit.rs new file mode 100644 index 0000000000000..c5ff92c88754a --- /dev/null +++ b/tests/ui/wf/wf-in-fn-type-implicit.rs @@ -0,0 +1,37 @@ +// check-pass +// known-bug: #104005 + +// Should fail. Function type parameters with implicit type annotations are not +// checked for well-formedness, which allows incorrect borrowing. + +// In contrast, user annotations are always checked for well-formedness, and the +// commented code below is correctly rejected by the borrow checker. + +use std::fmt::Display; + +trait Displayable { + fn display(self) -> Box; +} + +impl Displayable for (T, Option<&'static T>) { + fn display(self) -> Box { + Box::new(self.0) + } +} + +fn extend_lt(val: T) -> Box +where + (T, Option): Displayable, +{ + Displayable::display((val, None)) +} + +fn main() { + // *incorrectly* compiles + let val = extend_lt(&String::from("blah blah blah")); + println!("{}", val); + + // *correctly* fails to compile + // let val = extend_lt::<_, &_>(&String::from("blah blah blah")); + // println!("{}", val); +}