forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#110480 - whtahy:105107/known-bug-tests-for-…
…unsound-issues, r=jackh726 Add `known-bug` tests for 11 unsound issues r? `@jackh726` Should tests for other issues be in separate PRs? Thanks. Edit: Partially addresses rust-lang#105107. This PR adds `known-bug` tests for 11 unsound issues: - rust-lang#25860 - rust-lang#49206 - rust-lang#57893 - rust-lang#84366 - rust-lang#84533 - rust-lang#84591 - rust-lang#85099 - rust-lang#98117 - rust-lang#100041 - rust-lang#100051 - rust-lang#104005
- Loading branch information
Showing
11 changed files
with
348 additions
and
0 deletions.
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
tests/ui/closures/static-closures-with-nonstatic-return.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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: 'static>(_: T) {} | ||
|
||
fn main() {} |
25 changes: 25 additions & 0 deletions
25
tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<U> { | ||
type Output; | ||
} | ||
|
||
impl<T: ?Sized, U> Object<U> for T { | ||
type Output = U; | ||
} | ||
|
||
fn foo<T: ?Sized, U>(x: <T as Object<U>>::Output) -> U { | ||
x | ||
} | ||
|
||
#[allow(dead_code)] | ||
fn transmute<T, U>(x: T) -> U { | ||
foo::<dyn Object<U, Output = T>, U>(x) | ||
} | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T> Sync for Wrapper<'_, T> where T: Sync {} | ||
unsafe impl<'a> std::marker::Sync for Foo where Wrapper<'a, *const ()>: Sync {} | ||
fn _assert_sync<T: 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::<Foo>(); // uncomment this line causes compile error | ||
// "`*const ()` cannot be shared between threads safely" | ||
|
||
let handle = std::thread::spawn(inspect); | ||
inspect(); | ||
handle.join().unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T> 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); | ||
} |
16 changes: 16 additions & 0 deletions
16
tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() {} |
39 changes: 39 additions & 0 deletions
39
tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T>: Supertrait {} | ||
trait Supertrait { | ||
fn action(self); | ||
} | ||
|
||
fn subs_to_soup<T, U>(x: T) | ||
where | ||
T: Subtrait<U>, | ||
{ | ||
soup(x) | ||
} | ||
|
||
fn soup<T: Supertrait>(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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// check-pass | ||
// known-bug: #85099 | ||
|
||
// Should fail. Can coerce `Pin<T>` into `Pin<U>` where | ||
// `T: Deref<Target: Unpin>` and `U: Deref<Target: !Unpin>`, 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<Fut>); | ||
|
||
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<Output = ()>> 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<Output = ()>> 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: Future<Output = ()>>( | ||
fut: Fut, | ||
callback: impl FnOnce(Pin<&mut Fut>), | ||
) -> Fut { | ||
let cell = RefCell::new(fut); | ||
let s: &SomeLocalStruct<'_, Fut> = &SomeLocalStruct(&cell); | ||
let p: Pin<Pin<&SomeLocalStruct<'_, Fut>>> = Pin::new(Pin::new(s)); | ||
let mut p: Pin<Pin<&dyn SomeTrait<'_, Fut>>> = 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() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<dyn Display>; | ||
} | ||
|
||
impl<T: Display> Displayable for (T, Option<&'static T>) { | ||
fn display(self) -> Box<dyn Display> { | ||
Box::new(self.0) | ||
} | ||
} | ||
|
||
fn extend_lt<T, U>(val: T) -> Box<dyn Display> | ||
where | ||
(T, Option<U>): 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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T> Static for &'static T {} | ||
|
||
fn foo<S: Display>(x: S) -> Box<dyn Display> | ||
where | ||
&'static S: Static, | ||
{ | ||
Box::new(x) | ||
} | ||
|
||
fn main() { | ||
let s = foo(&String::from("blah blah blah")); | ||
println!("{}", s); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T: ?Sized> WellUnformed for T { | ||
type RequestNormalize = (); | ||
} | ||
|
||
const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); | ||
const _: <Vec<str> as WellUnformed>::RequestNormalize = (); | ||
|
||
fn main() {} |