From d5357c1b399410b2559d32b2fbd4afa92c57d7fa Mon Sep 17 00:00:00 2001 From: Kisaragi Marine Date: Thu, 13 Apr 2023 22:24:33 +0900 Subject: [PATCH 01/21] stdarch: update submodule --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index b655243782c18..1044810de54ea 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit b655243782c18d3419439daa523782e0818ecf26 +Subproject commit 1044810de54ea6f4026951e5d54211503ea0bd9e From d9256f94a987a008484caab5acf5a6e06c24ecd3 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Mon, 26 Dec 2022 00:52:58 -0800 Subject: [PATCH 02/21] Add Lazy{Cell,Lock}::into_inner Signed-off-by: Alex Saveau --- library/core/src/cell/lazy.rs | 28 +++++++++++++++++++++++ library/std/src/sync/lazy_lock.rs | 38 ++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 44adcfa1a9463..1b213f6a2941b 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -63,6 +63,34 @@ impl T> LazyCell { LazyCell { state: UnsafeCell::new(State::Uninit(f)) } } + /// Consumes this `LazyCell` returning the stored value. + /// + /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(lazy_cell)] + /// #![feature(lazy_cell_consume)] + /// + /// use std::cell::LazyCell; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = LazyCell::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); + /// ``` + #[unstable(feature = "lazy_cell_consume", issue = "109736")] + pub fn into_inner(this: Self) -> Result { + match this.state.into_inner() { + State::Init(data) => Ok(data), + State::Uninit(f) => Err(f), + State::Poisoned => panic!("LazyCell instance has previously been poisoned"), + } + } + /// Forces the evaluation of this lazy value and returns a reference to /// the result. /// diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 8e9ea293ce4e9..a6bc468b09281 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -1,9 +1,9 @@ use crate::cell::UnsafeCell; -use crate::fmt; use crate::mem::ManuallyDrop; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::Once; +use crate::{fmt, ptr}; use super::once::ExclusiveState; @@ -69,6 +69,42 @@ impl T> LazyLock { LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } } + /// Consumes this `LazyLock` returning the stored value. + /// + /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(lazy_cell)] + /// #![feature(lazy_cell_consume)] + /// + /// use std::sync::LazyLock; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = LazyLock::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); + /// ``` + #[unstable(feature = "lazy_cell_consume", issue = "109736")] + pub fn into_inner(mut this: Self) -> Result { + let state = this.once.state(); + match state { + ExclusiveState::Poisoned => panic!("LazyLock instance has previously been poisoned"), + state => { + let this = ManuallyDrop::new(this); + let data = unsafe { ptr::read(&this.data) }.into_inner(); + match state { + ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })), + ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })), + ExclusiveState::Poisoned => unreachable!(), + } + } + } + } + /// Forces the evaluation of this lazy value and /// returns a reference to result. This is equivalent /// to the `Deref` impl, but is explicit. From 41e3cc4c963450111eea9132c97258d9644e3f1e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 20 Apr 2023 09:35:04 +0000 Subject: [PATCH 03/21] Add some tests around (lack of) object safety of associated types and consts --- tests/ui/object-safety/assoc_const_bounds.rs | 13 ++++++++++++ .../object-safety/assoc_const_bounds.stderr | 15 +++++++++++++ .../object-safety/assoc_const_bounds_sized.rs | 9 ++++++++ .../assoc_const_bounds_sized.stderr | 15 +++++++++++++ tests/ui/object-safety/assoc_type_bounds.rs | 13 ++++++++++++ .../ui/object-safety/assoc_type_bounds.stderr | 21 +++++++++++++++++++ tests/ui/object-safety/assoc_type_bounds2.rs | 13 ++++++++++++ .../object-safety/assoc_type_bounds2.stderr | 21 +++++++++++++++++++ .../object-safety/assoc_type_bounds_sized.rs | 9 ++++++++ .../assoc_type_bounds_sized.stderr | 12 +++++++++++ 10 files changed, 141 insertions(+) create mode 100644 tests/ui/object-safety/assoc_const_bounds.rs create mode 100644 tests/ui/object-safety/assoc_const_bounds.stderr create mode 100644 tests/ui/object-safety/assoc_const_bounds_sized.rs create mode 100644 tests/ui/object-safety/assoc_const_bounds_sized.stderr create mode 100644 tests/ui/object-safety/assoc_type_bounds.rs create mode 100644 tests/ui/object-safety/assoc_type_bounds.stderr create mode 100644 tests/ui/object-safety/assoc_type_bounds2.rs create mode 100644 tests/ui/object-safety/assoc_type_bounds2.stderr create mode 100644 tests/ui/object-safety/assoc_type_bounds_sized.rs create mode 100644 tests/ui/object-safety/assoc_type_bounds_sized.stderr diff --git a/tests/ui/object-safety/assoc_const_bounds.rs b/tests/ui/object-safety/assoc_const_bounds.rs new file mode 100644 index 0000000000000..94b1f63165ba2 --- /dev/null +++ b/tests/ui/object-safety/assoc_const_bounds.rs @@ -0,0 +1,13 @@ +trait Foo { + const BAR: bool + where //~ ERROR: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where` + Self: Sized; +} + +trait Cake {} +impl Cake for () {} + +fn foo(_: &dyn Foo<()>) {} +fn bar(_: &dyn Foo) {} + +fn main() {} diff --git a/tests/ui/object-safety/assoc_const_bounds.stderr b/tests/ui/object-safety/assoc_const_bounds.stderr new file mode 100644 index 0000000000000..09bc11e178a45 --- /dev/null +++ b/tests/ui/object-safety/assoc_const_bounds.stderr @@ -0,0 +1,15 @@ +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where` + --> $DIR/assoc_const_bounds.rs:3:9 + | +LL | trait Foo { + | - while parsing this item list starting here +LL | const BAR: bool + | - expected one of 7 possible tokens +LL | where + | ^^^^^ unexpected token +LL | Self: Sized; +LL | } + | - the item list ends here + +error: aborting due to previous error + diff --git a/tests/ui/object-safety/assoc_const_bounds_sized.rs b/tests/ui/object-safety/assoc_const_bounds_sized.rs new file mode 100644 index 0000000000000..2a76e5dce2b49 --- /dev/null +++ b/tests/ui/object-safety/assoc_const_bounds_sized.rs @@ -0,0 +1,9 @@ +trait Foo { + const BAR: bool + where //~ ERROR: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where` + Self: Sized; +} + +fn foo(_: &dyn Foo) {} + +fn main() {} diff --git a/tests/ui/object-safety/assoc_const_bounds_sized.stderr b/tests/ui/object-safety/assoc_const_bounds_sized.stderr new file mode 100644 index 0000000000000..e1f57f677956b --- /dev/null +++ b/tests/ui/object-safety/assoc_const_bounds_sized.stderr @@ -0,0 +1,15 @@ +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where` + --> $DIR/assoc_const_bounds_sized.rs:3:9 + | +LL | trait Foo { + | - while parsing this item list starting here +LL | const BAR: bool + | - expected one of 7 possible tokens +LL | where + | ^^^^^ unexpected token +LL | Self: Sized; +LL | } + | - the item list ends here + +error: aborting due to previous error + diff --git a/tests/ui/object-safety/assoc_type_bounds.rs b/tests/ui/object-safety/assoc_type_bounds.rs new file mode 100644 index 0000000000000..9abf7939c4302 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds.rs @@ -0,0 +1,13 @@ +trait Foo { + type Bar + where + T: Cake; +} + +trait Cake {} +impl Cake for () {} + +fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` (from trait `Foo`) must be specified +fn bar(_: &dyn Foo) {} //~ ERROR: the value of the associated type `Bar` (from trait `Foo`) must be specified + +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds.stderr b/tests/ui/object-safety/assoc_type_bounds.stderr new file mode 100644 index 0000000000000..a1396dc3ad40e --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds.stderr @@ -0,0 +1,21 @@ +error[E0191]: the value of the associated type `Bar` (from trait `Foo`) must be specified + --> $DIR/assoc_type_bounds.rs:10:16 + | +LL | type Bar + | -------- `Bar` defined here +... +LL | fn foo(_: &dyn Foo<()>) {} + | ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>` + +error[E0191]: the value of the associated type `Bar` (from trait `Foo`) must be specified + --> $DIR/assoc_type_bounds.rs:11:16 + | +LL | type Bar + | -------- `Bar` defined here +... +LL | fn bar(_: &dyn Foo) {} + | ^^^^^^^^ help: specify the associated type: `Foo` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0191`. diff --git a/tests/ui/object-safety/assoc_type_bounds2.rs b/tests/ui/object-safety/assoc_type_bounds2.rs new file mode 100644 index 0000000000000..0112123fd42cd --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds2.rs @@ -0,0 +1,13 @@ +trait Foo { + type Bar + where + Self: Foo<()>; +} + +trait Cake {} +impl Cake for () {} + +fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` (from trait `Foo`) must be specified +fn bar(_: &dyn Foo) {} //~ ERROR: the value of the associated type `Bar` (from trait `Foo`) must be specified + +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds2.stderr b/tests/ui/object-safety/assoc_type_bounds2.stderr new file mode 100644 index 0000000000000..7a3c0e02d485d --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds2.stderr @@ -0,0 +1,21 @@ +error[E0191]: the value of the associated type `Bar` (from trait `Foo`) must be specified + --> $DIR/assoc_type_bounds2.rs:10:16 + | +LL | type Bar + | -------- `Bar` defined here +... +LL | fn foo(_: &dyn Foo<()>) {} + | ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>` + +error[E0191]: the value of the associated type `Bar` (from trait `Foo`) must be specified + --> $DIR/assoc_type_bounds2.rs:11:16 + | +LL | type Bar + | -------- `Bar` defined here +... +LL | fn bar(_: &dyn Foo) {} + | ^^^^^^^^ help: specify the associated type: `Foo` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0191`. diff --git a/tests/ui/object-safety/assoc_type_bounds_sized.rs b/tests/ui/object-safety/assoc_type_bounds_sized.rs new file mode 100644 index 0000000000000..61ad3cf9dc6dc --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_sized.rs @@ -0,0 +1,9 @@ +trait Foo { + type Bar + where + Self: Sized; +} + +fn foo(_: &dyn Foo) {} //~ ERROR: the value of the associated type `Bar` (from trait `Foo`) must be specified + +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_sized.stderr new file mode 100644 index 0000000000000..49d624f9b1d26 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_sized.stderr @@ -0,0 +1,12 @@ +error[E0191]: the value of the associated type `Bar` (from trait `Foo`) must be specified + --> $DIR/assoc_type_bounds_sized.rs:7:16 + | +LL | type Bar + | -------- `Bar` defined here +... +LL | fn foo(_: &dyn Foo) {} + | ^^^ help: specify the associated type: `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0191`. From adb5ded7a71911f66e20dd3a85dd39fb236c476d Mon Sep 17 00:00:00 2001 From: whtahy Date: Tue, 18 Apr 2023 00:29:01 -0400 Subject: [PATCH 04/21] 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 05/21] 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 06/21] 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 07/21] 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 08/21] 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 09/21] 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 10/21] 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 0e68cbd45dc169e807b470687f4e8f270ac97039 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 15 Apr 2023 16:03:36 +0000 Subject: [PATCH 11/21] Remove useless special case. --- .../src/dataflow_const_prop.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index a56c5cc5c12f9..809a0a386e339 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -520,21 +520,6 @@ impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> { _ => (), } } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - match rvalue { - Rvalue::Discriminant(place) => { - match self.state.get_discr(place.as_ref(), self.visitor.map) { - FlatSet::Top => (), - FlatSet::Elem(value) => { - self.visitor.before_effect.insert((location, *place), value); - } - FlatSet::Bottom => (), - } - } - _ => self.super_rvalue(rvalue, location), - } - } } struct DummyMachine; From 629cdb42d364a7de2845d24204c7018e1f9cd406 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 15 Apr 2023 16:04:20 +0000 Subject: [PATCH 12/21] Move eval_discriminant. --- .../src/dataflow_const_prop.rs | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 809a0a386e339..2f1e93664522e 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -70,22 +70,6 @@ struct ConstAnalysis<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, } -impl<'tcx> ConstAnalysis<'_, 'tcx> { - fn eval_discriminant( - &self, - enum_ty: Ty<'tcx>, - variant_index: VariantIdx, - ) -> Option> { - if !enum_ty.is_enum() { - return None; - } - let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?; - let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?; - let discr_value = Scalar::try_from_uint(discr.val, discr_layout.size)?; - Some(ScalarTy(discr_value, discr.ty)) - } -} - impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { type Value = FlatSet>; @@ -377,6 +361,20 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } + fn eval_discriminant( + &self, + enum_ty: Ty<'tcx>, + variant_index: VariantIdx, + ) -> Option> { + if !enum_ty.is_enum() { + return None; + } + let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?; + let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?; + let discr_value = Scalar::try_from_uint(discr.val, discr_layout.size)?; + Some(ScalarTy(discr_value, discr.ty)) + } + fn wrap_scalar(&self, scalar: Scalar, ty: Ty<'tcx>) -> FlatSet> { FlatSet::Elem(ScalarTy(scalar, ty)) } From dd452ae70ecee1d3e07ca9fc10ce8220b2821578 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 15 Apr 2023 16:05:19 +0000 Subject: [PATCH 13/21] Simplify logic. --- compiler/rustc_mir_transform/src/dataflow_const_prop.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 2f1e93664522e..3fdf556e15ea2 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -157,12 +157,10 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { // Flood everything now, so we can use `insert_value_idx` directly later. state.flood(target.as_ref(), self.map()); - let target = self.map().find(target.as_ref()); + let Some(target) = self.map().find(target.as_ref()) else { return }; - let value_target = target - .and_then(|target| self.map().apply(target, TrackElem::Field(0_u32.into()))); - let overflow_target = target - .and_then(|target| self.map().apply(target, TrackElem::Field(1_u32.into()))); + let value_target = self.map().apply(target, TrackElem::Field(0_u32.into())); + let overflow_target = self.map().apply(target, TrackElem::Field(1_u32.into())); if value_target.is_some() || overflow_target.is_some() { let (val, overflow) = self.binary_op(state, *op, left, right); From dd78b997b59b298a8e869db0def714c0630dcf94 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 15 Apr 2023 16:27:55 +0000 Subject: [PATCH 14/21] Reduce rightward drift. --- .../src/dataflow_const_prop.rs | 72 +++++++++---------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 3fdf556e15ea2..d0823a8597da9 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -110,48 +110,46 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { // we must make sure that all `target as Variant#i` are `Top`. state.flood(target.as_ref(), self.map()); - if let Some(target_idx) = self.map().find(target.as_ref()) { - let (variant_target, variant_index) = match **kind { - AggregateKind::Tuple | AggregateKind::Closure(..) => { - (Some(target_idx), None) - } - AggregateKind::Adt(def_id, variant_index, ..) => { - match self.tcx.def_kind(def_id) { - DefKind::Struct => (Some(target_idx), None), - DefKind::Enum => ( - self.map.apply(target_idx, TrackElem::Variant(variant_index)), - Some(variant_index), - ), - _ => (None, None), - } - } - _ => (None, None), - }; - if let Some(variant_target_idx) = variant_target { - for (field_index, operand) in operands.iter().enumerate() { - if let Some(field) = self.map().apply( - variant_target_idx, - TrackElem::Field(FieldIdx::from_usize(field_index)), - ) { - let result = self.handle_operand(operand, state); - state.insert_idx(field, result, self.map()); - } + let Some(target_idx) = self.map().find(target.as_ref()) else { return }; + + let (variant_target, variant_index) = match **kind { + AggregateKind::Tuple | AggregateKind::Closure(..) => (Some(target_idx), None), + AggregateKind::Adt(def_id, variant_index, ..) => { + match self.tcx.def_kind(def_id) { + DefKind::Struct => (Some(target_idx), None), + DefKind::Enum => ( + self.map.apply(target_idx, TrackElem::Variant(variant_index)), + Some(variant_index), + ), + _ => return, } } - if let Some(variant_index) = variant_index - && let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant) - { - // We are assigning the discriminant as part of an aggregate. - // This discriminant can only alias a variant field's value if the operand - // had an invalid value for that type. - // Using invalid values is UB, so we are allowed to perform the assignment - // without extra flooding. - let enum_ty = target.ty(self.local_decls, self.tcx).ty; - if let Some(discr_val) = self.eval_discriminant(enum_ty, variant_index) { - state.insert_value_idx(discr_idx, FlatSet::Elem(discr_val), &self.map); + _ => return, + }; + if let Some(variant_target_idx) = variant_target { + for (field_index, operand) in operands.iter().enumerate() { + if let Some(field) = self.map().apply( + variant_target_idx, + TrackElem::Field(FieldIdx::from_usize(field_index)), + ) { + let result = self.handle_operand(operand, state); + state.insert_idx(field, result, self.map()); } } } + if let Some(variant_index) = variant_index + && let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant) + { + // We are assigning the discriminant as part of an aggregate. + // This discriminant can only alias a variant field's value if the operand + // had an invalid value for that type. + // Using invalid values is UB, so we are allowed to perform the assignment + // without extra flooding. + let enum_ty = target.ty(self.local_decls, self.tcx).ty; + if let Some(discr_val) = self.eval_discriminant(enum_ty, variant_index) { + state.insert_value_idx(discr_idx, FlatSet::Elem(discr_val), &self.map); + } + } } Rvalue::CheckedBinaryOp(op, box (left, right)) => { // Flood everything now, so we can use `insert_value_idx` directly later. From 314126257d3d20e3e788325f3b88b7e635bd6bb8 Mon Sep 17 00:00:00 2001 From: whtahy Date: Sat, 22 Apr 2023 13:31:00 -0400 Subject: [PATCH 15/21] 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 16/21] 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 17/21] 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 18/21] 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); +} From 741096061c5a3dd65677058e4ad00b50a600bf91 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 23 Apr 2023 15:24:34 +0200 Subject: [PATCH 19/21] format panic message only once --- library/std/src/panicking.rs | 26 ++++++++++++------------ tests/ui/panics/fmt-only-once.rs | 21 +++++++++++++++++++ tests/ui/panics/fmt-only-once.run.stderr | 3 +++ 3 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 tests/ui/panics/fmt-only-once.rs create mode 100644 tests/ui/panics/fmt-only-once.run.stderr diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index ca4cf68ad54e2..b51f513f46eeb 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -249,20 +249,20 @@ fn default_hook(info: &PanicInfo<'_>) { let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); let write = |err: &mut dyn crate::io::Write| { - // Use the panic message directly if available, otherwise take it from - // the payload. - if let Some(msg) = info.message() { - let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}"); + // The std panic runtime always sets a `&str` or `String` payload for `panic!` and related + // macros with the formatted message. + // We try using the payload first to avoid formatting the message twice. + let msg: &dyn fmt::Display = if let Some(s) = info.payload().downcast_ref::<&'static str>() + { + s + } else if let Some(s) = info.payload().downcast_ref::() { + s + } else if let Some(msg) = info.message() { + msg } else { - let msg = if let Some(s) = info.payload().downcast_ref::<&'static str>() { - *s - } else if let Some(s) = info.payload().downcast_ref::() { - &s[..] - } else { - "Box" - }; - let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}"); - } + &"Box" + }; + let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}"); static FIRST_PANIC: AtomicBool = AtomicBool::new(true); diff --git a/tests/ui/panics/fmt-only-once.rs b/tests/ui/panics/fmt-only-once.rs new file mode 100644 index 0000000000000..6211bf961b3bc --- /dev/null +++ b/tests/ui/panics/fmt-only-once.rs @@ -0,0 +1,21 @@ +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=0 + +// Test that we format the panic message only once. +// Regression test for https://github.com/rust-lang/rust/issues/110717 + +use std::fmt; + +struct PrintOnFmt; + +impl fmt::Display for PrintOnFmt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + eprintln!("fmt"); + f.write_str("PrintOnFmt") + } +} + +fn main() { + panic!("{}", PrintOnFmt) +} diff --git a/tests/ui/panics/fmt-only-once.run.stderr b/tests/ui/panics/fmt-only-once.run.stderr new file mode 100644 index 0000000000000..39bd06881ad05 --- /dev/null +++ b/tests/ui/panics/fmt-only-once.run.stderr @@ -0,0 +1,3 @@ +fmt +thread 'main' panicked at 'PrintOnFmt', $DIR/fmt-only-once.rs:20:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 49413bb619e3ed8d589e7cf7f2d81127b7f6ce36 Mon Sep 17 00:00:00 2001 From: Kisaragi Marine Date: Mon, 24 Apr 2023 05:36:49 +0900 Subject: [PATCH 20/21] stdarch: update submodule, take 2 --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 1044810de54ea..24c2188ab75db 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 1044810de54ea6f4026951e5d54211503ea0bd9e +Subproject commit 24c2188ab75dbb15c9822e99f712a3a7ad390a8c From f5e535cb3e5fd99d7aeb21b92896dba72908af92 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sun, 23 Apr 2023 23:31:09 +0100 Subject: [PATCH 21/21] bootstrap: update paths cargo-credential crate This should be done in #110653 but forgot. --- src/bootstrap/tool.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index f8da6df0c7ccd..f4c7bdd445a1e 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -588,18 +588,18 @@ impl Step for Cargo { if self.target.contains("windows") { build_cred( "cargo-credential-wincred", - "src/tools/cargo/crates/credential/cargo-credential-wincred", + "src/tools/cargo/credential/cargo-credential-wincred", ); } if self.target.contains("apple-darwin") { build_cred( "cargo-credential-macos-keychain", - "src/tools/cargo/crates/credential/cargo-credential-macos-keychain", + "src/tools/cargo/credential/cargo-credential-macos-keychain", ); } build_cred( "cargo-credential-1password", - "src/tools/cargo/crates/credential/cargo-credential-1password", + "src/tools/cargo/credential/cargo-credential-1password", ); cargo_bin_path }