From 196b8c40f90d97f0a81356602069d8d5f09d3206 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 6 Jul 2022 16:36:52 +0100 Subject: [PATCH 01/21] Use `rtabort!` instead of `process::abort` --- library/std/src/sys/windows/handle.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index ef9a8bd690031..6f38e4e828a9f 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -252,10 +252,7 @@ impl Handle { // If the operation has not completed then abort the process. // Doing otherwise means that the buffer and stack may be written to // after this function returns. - c::STATUS_PENDING => { - eprintln!("I/O error: operation failed to complete synchronously"); - crate::process::abort(); - } + c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"), // Return `Ok(0)` when there's nothing more to read. c::STATUS_END_OF_FILE => Ok(0), @@ -298,9 +295,7 @@ impl Handle { // If the operation has not completed then abort the process. // Doing otherwise means that the buffer may be read and the stack // written to after this function returns. - c::STATUS_PENDING => { - rtabort!("I/O error: operation failed to complete synchronously"); - } + c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"), // Success! status if c::nt_success(status) => Ok(io_status.Information), From e59e58064c9ed33abd8b740c928a82b0eba4bde5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 6 Jul 2022 16:38:35 +0100 Subject: [PATCH 02/21] Windows: Fallback for overlapped I/O Try waiting on the file handle once. If that fails then give up. --- library/std/src/sys/windows/c.rs | 14 +++++++++++++- library/std/src/sys/windows/handle.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 5f14edaf067c0..b92aa420177f3 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -325,7 +325,9 @@ union IO_STATUS_BLOCK_union { } impl Default for IO_STATUS_BLOCK_union { fn default() -> Self { - Self { Pointer: ptr::null_mut() } + let mut this = Self { Pointer: ptr::null_mut() }; + this.Status = STATUS_PENDING; + this } } #[repr(C)] @@ -334,6 +336,16 @@ pub struct IO_STATUS_BLOCK { u: IO_STATUS_BLOCK_union, pub Information: usize, } +impl IO_STATUS_BLOCK { + pub fn status(&self) -> NTSTATUS { + // SAFETY: If `self.u.Status` was set then this is obviously safe. + // If `self.u.Pointer` was set then this is the equivalent to converting + // the pointer to an integer, which is also safe. + // Currently the only safe way to construct `IO_STATUS_BLOCK` outside of + // this module is to call the `default` method, which sets the `Status`. + unsafe { self.u.Status } + } +} pub type LPOVERLAPPED_COMPLETION_ROUTINE = unsafe extern "system" fn( dwErrorCode: DWORD, diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 6f38e4e828a9f..dd84d505cb322 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -248,6 +248,13 @@ impl Handle { offset.map(|n| n as _).as_ref(), None, ); + + let status = if status == c::STATUS_PENDING { + c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE); + io_status.status() + } else { + status + }; match status { // If the operation has not completed then abort the process. // Doing otherwise means that the buffer and stack may be written to @@ -291,6 +298,12 @@ impl Handle { None, ) }; + let status = if status == c::STATUS_PENDING { + unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) }; + io_status.status() + } else { + status + }; match status { // If the operation has not completed then abort the process. // Doing otherwise means that the buffer may be read and the stack From af3cc8e79c0d0e9731a5cf12f18e2dc709a24f89 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 6 Jul 2022 16:39:06 +0100 Subject: [PATCH 03/21] Tests for unsound Windows file methods --- library/std/src/sys/windows/handle.rs | 3 + library/std/src/sys/windows/handle/tests.rs | 22 ++++++ .../issues-81357-unsound-file-methods.rs | 76 +++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 library/std/src/sys/windows/handle/tests.rs create mode 100644 src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index dd84d505cb322..6398c4456331c 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -1,5 +1,8 @@ #![unstable(issue = "none", feature = "windows_handle")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf}; use crate::mem; diff --git a/library/std/src/sys/windows/handle/tests.rs b/library/std/src/sys/windows/handle/tests.rs new file mode 100644 index 0000000000000..d836dae4c305b --- /dev/null +++ b/library/std/src/sys/windows/handle/tests.rs @@ -0,0 +1,22 @@ +use crate::sys::pipe::{anon_pipe, Pipes}; +use crate::{thread, time}; + +/// Test the synchronous fallback for overlapped I/O. +#[test] +fn overlapped_handle_fallback() { + // Create some pipes. `ours` will be asynchronous. + let Pipes { ours, theirs } = anon_pipe(true, false).unwrap(); + + let async_readable = ours.into_handle(); + let sync_writeable = theirs.into_handle(); + + thread::scope(|_| { + thread::sleep(time::Duration::from_millis(100)); + sync_writeable.write(b"hello world!").unwrap(); + }); + + // The pipe buffer starts empty so reading won't complete synchronously unless + // our fallback path works. + let mut buffer = [0u8; 1024]; + async_readable.read(&mut buffer).unwrap(); +} diff --git a/src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs b/src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs new file mode 100644 index 0000000000000..94b5798a0e7d2 --- /dev/null +++ b/src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs @@ -0,0 +1,76 @@ +// run-fail +// only-windows + +fn main() { + use std::fs; + use std::io::prelude::*; + use std::os::windows::prelude::*; + use std::ptr; + use std::sync::Arc; + use std::thread; + use std::time::Duration; + + const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; + + fn create_pipe_server(path: &str) -> fs::File { + let mut path0 = path.as_bytes().to_owned(); + path0.push(0); + extern "system" { + fn CreateNamedPipeA( + lpName: *const u8, + dwOpenMode: u32, + dwPipeMode: u32, + nMaxInstances: u32, + nOutBufferSize: u32, + nInBufferSize: u32, + nDefaultTimeOut: u32, + lpSecurityAttributes: *mut u8, + ) -> RawHandle; + } + + unsafe { + let h = CreateNamedPipeA(path0.as_ptr(), 3, 0, 1, 0, 0, 0, ptr::null_mut()); + assert_ne!(h as isize, -1); + fs::File::from_raw_handle(h) + } + } + + let path = "\\\\.\\pipe\\repro"; + let mut server = create_pipe_server(path); + + let client = Arc::new( + fs::OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).read(true).open(path).unwrap(), + ); + + let spawn_read = |is_first: bool| { + thread::spawn({ + let f = client.clone(); + move || { + let mut buf = [0xcc; 1]; + let mut f = f.as_ref(); + f.read(&mut buf).unwrap(); + if is_first { + assert_ne!(buf[0], 0xcc); + } else { + let b = buf[0]; // capture buf[0] + thread::sleep(Duration::from_millis(200)); + + // In this test, success is indicated by failing. + if buf[0] == b { + panic!("Success!"); + } + } + } + }) + }; + + let t1 = spawn_read(true); + thread::sleep(Duration::from_millis(20)); + let t2 = spawn_read(false); + thread::sleep(Duration::from_millis(100)); + let _ = server.write(b"x"); + thread::sleep(Duration::from_millis(100)); + let _ = server.write(b"y"); + let _ = t1.join(); + let _ = t2.join(); +} From f5edcc2256bfa25a8fd5ae45a2f5243b07c4572e Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 6 Jul 2022 18:47:44 +0100 Subject: [PATCH 04/21] Fix ui-fulldep test --- ...s.rs => issue-81357-unsound-file-methods.rs} | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) rename src/test/ui-fulldeps/{issues-81357-unsound-file-methods.rs => issue-81357-unsound-file-methods.rs} (83%) diff --git a/src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs b/src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs similarity index 83% rename from src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs rename to src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs index 94b5798a0e7d2..fdf1150f8d25a 100644 --- a/src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs +++ b/src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs @@ -55,10 +55,9 @@ fn main() { let b = buf[0]; // capture buf[0] thread::sleep(Duration::from_millis(200)); - // In this test, success is indicated by failing. - if buf[0] == b { - panic!("Success!"); - } + // Check the buffer hasn't been written to after read. + dbg!(buf[0], b); + assert_eq!(buf[0], b); } } }) @@ -71,6 +70,12 @@ fn main() { let _ = server.write(b"x"); thread::sleep(Duration::from_millis(100)); let _ = server.write(b"y"); - let _ = t1.join(); - let _ = t2.join(); + + // This is run fail because we need to test for the `abort`. + // That failing to run is the success case. + if t1.join().is_err() || t2.join().is_err() { + return; + } else { + panic!("success"); + } } From d8d064e7a863ac5b5af3397e82e801f091b51a4b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Jun 2022 14:25:44 +0000 Subject: [PATCH 05/21] pessimistically treat all function items as containing an opaque type --- compiler/rustc_middle/src/ty/flags.rs | 5 +++++ .../issue-53398-cyclic-types.rs | 2 +- .../issue-53398-cyclic-types.stderr | 4 +--- .../ui/type-alias-impl-trait/issue-98604.rs | 13 +++++++++++++ .../type-alias-impl-trait/issue-98604.stderr | 18 ++++++++++++++++++ .../ui/type-alias-impl-trait/issue-98608.rs | 9 +++++++++ .../type-alias-impl-trait/issue-98608.stderr | 16 ++++++++++++++++ 7 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/issue-98604.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-98604.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-98608.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-98608.stderr diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 7a3d615862cba..63b1352e66b80 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -207,6 +207,11 @@ impl FlagComputation { &ty::FnDef(_, substs) => { self.add_substs(substs); + // HACK(#98608, oli-obk): Function items with opaque types in their signature will + // end up not having the HAS_TY_OPAQUE flag set, causing `evaluate_obligation` to + // optimistically assume the function item matches any signature. See documentation + // on `HAS_FREE_LOCAL_NAMES` for details. + self.add_flags(TypeFlags::HAS_TY_OPAQUE); } &ty::FnPtr(fn_sig) => self.bound_computation(fn_sig, |computation, fn_sig| { diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs index 6c838f410036a..4bc0f9d920087 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs +++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs @@ -3,7 +3,7 @@ type Foo = impl Fn() -> Foo; fn foo() -> Foo { - foo //~ ERROR: overflow evaluating the requirement `fn() -> Foo {foo}: Sized` + foo //~ ERROR: overflow evaluating the requirement ` Foo {foo} as FnOnce<()>>::Output == fn() -> Foo {foo}` } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr index a9c2c18630c01..f69514b7808f5 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr @@ -1,10 +1,8 @@ -error[E0275]: overflow evaluating the requirement `fn() -> Foo {foo}: Sized` +error[E0275]: overflow evaluating the requirement ` Foo {foo} as FnOnce<()>>::Output == fn() -> Foo {foo}` --> $DIR/issue-53398-cyclic-types.rs:6:5 | LL | foo | ^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`) error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.rs b/src/test/ui/type-alias-impl-trait/issue-98604.rs new file mode 100644 index 0000000000000..a4fd8a82a04fd --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-98604.rs @@ -0,0 +1,13 @@ +// edition:2018 + +type AsyncFnPtr = Box< + dyn Fn() -> std::pin::Pin>>, +>; + +async fn test() {} + +#[allow(unused_must_use)] +fn main() { + Box::new(test) as AsyncFnPtr; + //~^ ERROR type mismatch +} diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.stderr b/src/test/ui/type-alias-impl-trait/issue-98604.stderr new file mode 100644 index 0000000000000..f04d1b4d7877e --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-98604.stderr @@ -0,0 +1,18 @@ +error[E0271]: type mismatch resolving ` impl Future {test} as FnOnce<()>>::Output == Pin + 'static)>>` + --> $DIR/issue-98604.rs:11:5 + | +LL | Box::new(test) as AsyncFnPtr; + | ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type + | +note: while checking the return type of the `async fn` + --> $DIR/issue-98604.rs:7:17 + | +LL | async fn test() {} + | ^ checked the `Output` of this `async fn`, found opaque type + = note: expected struct `Pin + 'static)>>` + found opaque type `impl Future` + = note: required for the cast from `fn() -> impl Future {test}` to the object type `dyn Fn() -> Pin + 'static)>>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.rs b/src/test/ui/type-alias-impl-trait/issue-98608.rs new file mode 100644 index 0000000000000..d75762a8b62f0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-98608.rs @@ -0,0 +1,9 @@ +fn hi() -> impl Sized { std::ptr::null::() } + +fn main() { + let b: Box Box> = Box::new(hi); + //~^ ERROR type mismatch resolving ` impl Sized {hi} as FnOnce<()>>::Output == Box` + let boxed = b(); + let null = *boxed; + println!("{null:?}"); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.stderr b/src/test/ui/type-alias-impl-trait/issue-98608.stderr new file mode 100644 index 0000000000000..8f3ec7d9d1616 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-98608.stderr @@ -0,0 +1,16 @@ +error[E0271]: type mismatch resolving ` impl Sized {hi} as FnOnce<()>>::Output == Box` + --> $DIR/issue-98608.rs:4:39 + | +LL | fn hi() -> impl Sized { std::ptr::null::() } + | ---------- the found opaque type +... +LL | let b: Box Box> = Box::new(hi); + | ^^^^^^^^^^^^ expected struct `Box`, found opaque type + | + = note: expected struct `Box` + found opaque type `impl Sized` + = note: required for the cast from `fn() -> impl Sized {hi}` to the object type `dyn Fn() -> Box` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. From 34a200304c2bf1cc75e6bc1d986827bf7eb18cf3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 30 Jun 2022 13:24:35 +0000 Subject: [PATCH 06/21] use a method instead of manually doing what its body does --- compiler/rustc_infer/src/traits/project.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index b84ed3dc68937..18469208731c8 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -203,7 +203,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { Some(&ProjectionCacheEntry::NormalizedTy { ref ty, complete: _ }) => { info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); let mut ty = ty.clone(); - if result == EvaluationResult::EvaluatedToOk { + if result.must_apply_considering_regions() { ty.obligations = vec![]; } map.insert(key, ProjectionCacheEntry::NormalizedTy { ty, complete: Some(result) }); From 7e543bb165fe5c8f0f34d70aace232d6e9856321 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 30 Jun 2022 14:23:31 +0000 Subject: [PATCH 07/21] Make `evaluate_obligation` not succeed unconditionally if it registered new hidden types for opaque types --- compiler/rustc_infer/src/infer/mod.rs | 4 ++++ compiler/rustc_infer/src/infer/undo_log.rs | 4 ++++ compiler/rustc_middle/src/traits/select.rs | 18 ++++++++++++++---- compiler/rustc_middle/src/ty/flags.rs | 5 ----- .../src/traits/error_reporting/suggestions.rs | 1 + .../src/traits/select/mod.rs | 4 ++++ .../issue-53398-cyclic-types.rs | 2 +- .../issue-53398-cyclic-types.stderr | 4 +++- 8 files changed, 31 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c9121f7d348ce..989cc551a82f7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -929,6 +929,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .region_constraints_added_in_snapshot(&snapshot.undo_snapshot) } + pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool { + self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot) + } + pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup); } diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 1b696f21cbcf4..74a26ebc39f81 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -185,6 +185,10 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> { }) } + pub(crate) fn opaque_types_in_snapshot(&self, s: &Snapshot<'tcx>) -> bool { + self.logs[s.undo_len..].iter().any(|log| matches!(log, UndoLog::OpaqueTypes(..))) + } + pub(crate) fn region_constraints( &self, ) -> impl Iterator> + Clone { diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index ffa70cddbd59c..025059fcbcfb8 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -174,6 +174,10 @@ pub enum SelectionCandidate<'tcx> { pub enum EvaluationResult { /// Evaluation successful. EvaluatedToOk, + /// Evaluation successful, but need to rerun because opaque types got + /// hidden types assigned without it being known whether the opaque types + /// are within their defining scope + EvaluatedToOkModuloOpaqueTypes, /// Evaluation successful, but there were unevaluated region obligations. EvaluatedToOkModuloRegions, /// Evaluation is known to be ambiguous -- it *might* hold for some @@ -252,9 +256,11 @@ impl EvaluationResult { pub fn may_apply(self) -> bool { match self { - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { - true - } + EvaluatedToOkModuloOpaqueTypes + | EvaluatedToOk + | EvaluatedToOkModuloRegions + | EvaluatedToAmbig + | EvaluatedToUnknown => true, EvaluatedToErr | EvaluatedToRecur => false, } @@ -264,7 +270,11 @@ impl EvaluationResult { match self { EvaluatedToUnknown | EvaluatedToRecur => true, - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, + EvaluatedToOkModuloOpaqueTypes + | EvaluatedToOk + | EvaluatedToOkModuloRegions + | EvaluatedToAmbig + | EvaluatedToErr => false, } } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 63b1352e66b80..7a3d615862cba 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -207,11 +207,6 @@ impl FlagComputation { &ty::FnDef(_, substs) => { self.add_substs(substs); - // HACK(#98608, oli-obk): Function items with opaque types in their signature will - // end up not having the HAS_TY_OPAQUE flag set, causing `evaluate_obligation` to - // optimistically assume the function item matches any signature. See documentation - // on `HAS_FREE_LOCAL_NAMES` for details. - self.add_flags(TypeFlags::HAS_TY_OPAQUE); } &ty::FnPtr(fn_sig) => self.bound_computation(fn_sig, |computation, fn_sig| { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index d20ba99ebc9b5..60cb5914dada8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -761,6 +761,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { Ok( EvaluationResult::EvaluatedToOk | EvaluationResult::EvaluatedToOkModuloRegions + | EvaluationResult::EvaluatedToOkModuloOpaqueTypes | EvaluationResult::EvaluatedToAmbig, ) => {} _ => return false, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 1c9f83f8f3408..ed4877638bff6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -388,6 +388,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(_) => return Ok(EvaluatedToErr), } + if self.infcx.opaque_types_added_in_snapshot(snapshot) { + return Ok(result.max(EvaluatedToOkModuloOpaqueTypes)); + } + match self.infcx.region_constraints_added_in_snapshot(snapshot) { None => Ok(result), Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs index 4bc0f9d920087..6c838f410036a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs +++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs @@ -3,7 +3,7 @@ type Foo = impl Fn() -> Foo; fn foo() -> Foo { - foo //~ ERROR: overflow evaluating the requirement ` Foo {foo} as FnOnce<()>>::Output == fn() -> Foo {foo}` + foo //~ ERROR: overflow evaluating the requirement `fn() -> Foo {foo}: Sized` } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr index f69514b7808f5..a9c2c18630c01 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr @@ -1,8 +1,10 @@ -error[E0275]: overflow evaluating the requirement ` Foo {foo} as FnOnce<()>>::Output == fn() -> Foo {foo}` +error[E0275]: overflow evaluating the requirement `fn() -> Foo {foo}: Sized` --> $DIR/issue-53398-cyclic-types.rs:6:5 | LL | foo | ^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`) error: aborting due to previous error From 838f779c7559f9cbe5841b5eb1a71ce305db1243 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 1 Jul 2022 13:19:27 +0000 Subject: [PATCH 08/21] Remove type flag based opaque type workaround --- compiler/rustc_type_ir/src/lib.rs | 8 -- src/test/ui/impl-trait/auto-trait-leak.rs | 1 - src/test/ui/impl-trait/auto-trait-leak.stderr | 112 +++--------------- .../auto-trait-leakage3.rs | 1 - .../auto-trait-leakage3.stderr | 27 +---- .../type-alias-impl-trait/inference-cycle.rs | 1 - .../inference-cycle.stderr | 27 +---- .../ui/type-alias-impl-trait/reveal_local.rs | 1 - .../type-alias-impl-trait/reveal_local.stderr | 33 +----- 9 files changed, 30 insertions(+), 181 deletions(-) diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index c63e9c31d535c..a46729f229e23 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -61,14 +61,6 @@ bitflags! { | TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits - // The `evaluate_obligation` query does not return further - // obligations. If it evaluates an obligation with an opaque - // type, that opaque type may get compared to another type, - // constraining it. We would lose this information. - // FIXME: differentiate between crate-local opaque types - // and opaque types from other crates, as only opaque types - // from the local crate can possibly be a local name - | TypeFlags::HAS_TY_OPAQUE.bits // We consider 'freshened' types and constants // to depend on a particular fn. // The freshening process throws away information, diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index d2452abab0254..c2fbbf94fd666 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -11,7 +11,6 @@ fn main() { // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { //~^ ERROR cycle detected - //~| ERROR cycle detected send(cycle2().clone()); Rc::new(Cell::new(5)) diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 14db864f1c28a..634ff14869eb4 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -30,129 +30,47 @@ note: ...which requires building MIR for `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires computing type of `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:20:16 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^ -note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/auto-trait-leak.rs:1:1 - | -LL | / use std::cell::Cell; -LL | | use std::rc::Rc; -LL | | -LL | | fn send(_: T) {} -... | -LL | | Rc::new(String::from("foo")) -LL | | } - | |_^ - -error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` - --> $DIR/auto-trait-leak.rs:12:16 + --> $DIR/auto-trait-leak.rs:14:5 | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - | -note: ...which requires borrow-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | send(cycle2().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... note: ...which requires computing type of `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:20:16 + --> $DIR/auto-trait-leak.rs:19:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:20:5 | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | send(cycle1().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 @@ -166,6 +84,6 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs index b456b1445e784..5fb7a9473d3df 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs @@ -6,7 +6,6 @@ mod m { type Foo = impl std::fmt::Debug; //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] - //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] pub fn foo() -> Foo { 22_u32 diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr index 4c44875b4a548..1e9a45aac79e9 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr @@ -5,10 +5,11 @@ LL | type Foo = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ | note: ...which requires type-checking `m::bar`... - --> $DIR/auto-trait-leakage3.rs:15:5 + --> $DIR/auto-trait-leakage3.rs:15:9 | -LL | pub fn bar() { - | ^^^^^^^^^^^^ +LL | is_send(foo()); + | ^^^^^^^ + = note: ...which requires evaluating trait selection obligation `m::Foo: core::marker::Send`... = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in module `m` --> $DIR/auto-trait-leakage3.rs:6:1 @@ -16,24 +17,6 @@ note: cycle used when checking item types in module `m` LL | mod m { | ^^^^^ -error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` - --> $DIR/auto-trait-leakage3.rs:7:16 - | -LL | type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `m::bar`... - --> $DIR/auto-trait-leakage3.rs:15:5 - | -LL | pub fn bar() { - | ^^^^^^^^^^^^ - = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle -note: cycle used when checking item types in module `m` - --> $DIR/auto-trait-leakage3.rs:6:1 - | -LL | mod m { - | ^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.rs b/src/test/ui/type-alias-impl-trait/inference-cycle.rs index 608572978a351..79caddf791320 100644 --- a/src/test/ui/type-alias-impl-trait/inference-cycle.rs +++ b/src/test/ui/type-alias-impl-trait/inference-cycle.rs @@ -4,7 +4,6 @@ mod m { type Foo = impl std::fmt::Debug; //~^ ERROR cycle detected - //~| ERROR cycle detected // Cycle: error today, but it'd be nice if it eventually worked diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr index 3ed86fae8a18d..b9d646b927a6f 100644 --- a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr +++ b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr @@ -5,10 +5,11 @@ LL | type Foo = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ | note: ...which requires type-checking `m::bar`... - --> $DIR/inference-cycle.rs:15:5 + --> $DIR/inference-cycle.rs:15:9 | -LL | pub fn bar() { - | ^^^^^^^^^^^^ +LL | is_send(foo()); // Today: error + | ^^^^^^^ + = note: ...which requires evaluating trait selection obligation `m::Foo: core::marker::Send`... = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in module `m` --> $DIR/inference-cycle.rs:4:1 @@ -16,24 +17,6 @@ note: cycle used when checking item types in module `m` LL | mod m { | ^^^^^ -error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` - --> $DIR/inference-cycle.rs:5:16 - | -LL | type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `m::bar`... - --> $DIR/inference-cycle.rs:15:5 - | -LL | pub fn bar() { - | ^^^^^^^^^^^^ - = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle -note: cycle used when checking item types in module `m` - --> $DIR/inference-cycle.rs:4:1 - | -LL | mod m { - | ^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/reveal_local.rs b/src/test/ui/type-alias-impl-trait/reveal_local.rs index 145186baa1faa..7ecb553530106 100644 --- a/src/test/ui/type-alias-impl-trait/reveal_local.rs +++ b/src/test/ui/type-alias-impl-trait/reveal_local.rs @@ -4,7 +4,6 @@ use std::fmt::Debug; type Foo = impl Debug; //~^ ERROR cycle detected -//~| ERROR cycle detected fn is_send() { } diff --git a/src/test/ui/type-alias-impl-trait/reveal_local.stderr b/src/test/ui/type-alias-impl-trait/reveal_local.stderr index 5d48dd5b2bf73..27fded3332921 100644 --- a/src/test/ui/type-alias-impl-trait/reveal_local.stderr +++ b/src/test/ui/type-alias-impl-trait/reveal_local.stderr @@ -5,10 +5,11 @@ LL | type Foo = impl Debug; | ^^^^^^^^^^ | note: ...which requires type-checking `not_good`... - --> $DIR/reveal_local.rs:11:1 + --> $DIR/reveal_local.rs:13:5 | -LL | fn not_good() { - | ^^^^^^^^^^^^^ +LL | is_send::(); + | ^^^^^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Send`... = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/reveal_local.rs:1:1 @@ -22,30 +23,6 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when computing type of `Foo::{opaque#0}` - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `not_gooder`... - --> $DIR/reveal_local.rs:17:1 - | -LL | fn not_gooder() { - | ^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/reveal_local.rs:1:1 - | -LL | / #![feature(type_alias_impl_trait)] -LL | | -LL | | use std::fmt::Debug; -LL | | -... | -LL | | -LL | | fn main() {} - | |____________^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. From 7371ad990d0b62a2a073cc49291a223cd199fa41 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:10:50 +0000 Subject: [PATCH 09/21] not knowing about opaque types is worse than not knowing about regions, make sure we don't accidentally mark something as ok-modulo-regions if there are opaque types involved --- compiler/rustc_middle/src/traits/select.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 025059fcbcfb8..854dd215a37c0 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -174,12 +174,12 @@ pub enum SelectionCandidate<'tcx> { pub enum EvaluationResult { /// Evaluation successful. EvaluatedToOk, + /// Evaluation successful, but there were unevaluated region obligations. + EvaluatedToOkModuloRegions, /// Evaluation successful, but need to rerun because opaque types got /// hidden types assigned without it being known whether the opaque types /// are within their defining scope EvaluatedToOkModuloOpaqueTypes, - /// Evaluation successful, but there were unevaluated region obligations. - EvaluatedToOkModuloRegions, /// Evaluation is known to be ambiguous -- it *might* hold for some /// assignment of inference variables, but it might not. /// From 781cbf6b708c2fc2129e0c173941f557d5b840d8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 13:59:44 +0000 Subject: [PATCH 10/21] Only register hidden types for opaque types from the current crate, nothing else would work anyway. --- compiler/rustc_infer/src/infer/opaque_types.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 92c0ed84057a6..3b9b6f7a2af99 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let (a, b) = if a_is_expected { (a, b) } else { (b, a) }; let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { - ty::Opaque(def_id, substs) => { + ty::Opaque(def_id, substs) if def_id.is_local() => { let origin = if self.defining_use_anchor.is_some() { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1c552591b117c..a254979162e83 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1065,6 +1065,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { Lift )] pub struct OpaqueTypeKey<'tcx> { + // FIXME(oli-obk): make this a LocalDefId pub def_id: DefId, pub substs: SubstsRef<'tcx>, } From f3b0cb5c5d851d423409cf040cad21624ce55908 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Tue, 29 Mar 2022 15:31:42 +0200 Subject: [PATCH 11/21] Unify copying data from enclave to userspace --- library/std/src/sys/sgx/abi/usercalls/alloc.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 3792a3820a534..9a64b7e4b150c 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -225,13 +225,9 @@ where /// Copies `val` into freshly allocated space in user memory. pub fn new_from_enclave(val: &T) -> Self { unsafe { - let ret = Self::new_uninit_bytes(mem::size_of_val(val)); - ptr::copy( - val as *const T as *const u8, - ret.0.as_ptr() as *mut u8, - mem::size_of_val(val), - ); - ret + let mut user = Self::new_uninit_bytes(mem::size_of_val(val)); + user.copy_from_enclave(val); + user } } From b5d842f65c74a475a0490cc0888a57033c648572 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Mon, 28 Mar 2022 14:34:16 +0200 Subject: [PATCH 12/21] Mitigate MMIO stale data vulnerabilities Intel Security Advisory: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html --- .../std/src/sys/sgx/abi/usercalls/alloc.rs | 100 +++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 9a64b7e4b150c..b37e9b257edb4 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -1,13 +1,15 @@ #![allow(unused)] +use crate::arch::asm; use crate::cell::UnsafeCell; +use crate::convert::TryInto; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; use crate::ptr::{self, NonNull}; use crate::slice; use crate::slice::SliceIndex; -use super::super::mem::is_user_range; +use super::super::mem::{is_enclave_range, is_user_range}; use fortanix_sgx_abi::*; /// A type that can be safely read from or written to userspace. @@ -300,6 +302,100 @@ where } } +/// Copies `len` bytes of data from enclave pointer `src` to userspace `dst` +/// +/// This function mitigates stale data vulnerabilities +/// https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html +/// +/// # Panics +/// This function panics if: +/// +/// * The `src` pointer is null +/// * The `dst` pointer is null +/// * The `src` memory range is not in enclave memory +/// * The `dst` memory range is not in user memory +unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe fn copy_bytewise_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe { + let seg_sel: u16 = 0; + for off in 0..len { + asm!(" + mov %ds, ({seg_sel}) + verw ({seg_sel}) + movb {val}, ({dst}) + mfence + lfence + ", + val = in(reg_byte) *src.offset(off as isize), + dst = in(reg) dst.offset(off as isize), + seg_sel = in(reg) &seg_sel, + options(nostack, att_syntax) + ); + } + } + } + + unsafe fn copy_aligned_quadwords_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe { + asm!( + "rep movsq (%rsi), (%rdi)", + inout("rcx") len / 8 => _, + inout("rdi") dst => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); + } + } + assert!(!src.is_null()); + assert!(!dst.is_null()); + assert!(is_enclave_range(src, len)); + assert!(is_user_range(dst, len)); + assert!(len < isize::MAX as usize); + assert!(!(src as usize).overflowing_add(len).1); + assert!(!(dst as usize).overflowing_add(len).1); + + if len < 8 { + // Can't align on 8 byte boundary: copy safely byte per byte + unsafe { + copy_bytewise_to_userspace(src, dst, len); + } + } else if len % 8 == 0 && dst as usize % 8 == 0 { + // Copying 8-byte aligned quadwords: copy quad word per quad word + unsafe { + copy_aligned_quadwords_to_userspace(src, dst, len); + } + } else { + // Split copies into three parts: + // +--------+ + // | small0 | Chunk smaller than 8 bytes + // +--------+ + // | big | Chunk 8-byte aligned, and size a multiple of 8 bytes + // +--------+ + // | small1 | Chunk smaller than 8 bytes + // +--------+ + + unsafe { + // Copy small0 + let small0_size = (8 - dst as usize % 8) as u8; + let small0_src = src; + let small0_dst = dst; + copy_bytewise_to_userspace(small0_src as _, small0_dst, small0_size as _); + + // Copy big + let small1_size = ((len - small0_size as usize) % 8) as u8; + let big_size = len - small0_size as usize - small1_size as usize; + let big_src = src.offset(small0_size as _); + let big_dst = dst.offset(small0_size as _); + copy_aligned_quadwords_to_userspace(big_src as _, big_dst, big_size); + + // Copy small1 + let small1_src = src.offset(big_size as isize + small0_size as isize); + let small1_dst = dst.offset(big_size as isize + small0_size as isize); + copy_bytewise_to_userspace(small1_src, small1_dst, small1_size as _); + } + } +} + #[unstable(feature = "sgx_platform", issue = "56975")] impl UserRef where @@ -348,7 +444,7 @@ where pub fn copy_from_enclave(&mut self, val: &T) { unsafe { assert_eq!(mem::size_of_val(val), mem::size_of_val(&*self.0.get())); - ptr::copy( + copy_to_userspace( val as *const T as *const u8, self.0.get() as *mut T as *mut u8, mem::size_of_val(val), From 36e6ca7d110267d98d82aca6648acf45fdafbaf2 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Wed, 23 Mar 2022 10:03:00 +0100 Subject: [PATCH 13/21] Ensure userspace allocation is 8-byte aligned --- library/std/src/sys/sgx/abi/usercalls/alloc.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index b37e9b257edb4..4c1f279857f9c 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -2,6 +2,7 @@ use crate::arch::asm; use crate::cell::UnsafeCell; +use crate::cmp; use crate::convert::TryInto; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; @@ -212,7 +213,9 @@ where unsafe { // Mustn't call alloc with size 0. let ptr = if size > 0 { - rtunwrap!(Ok, super::alloc(size, T::align_of())) as _ + // `copy_to_userspace` is more efficient when data is 8-byte aligned + let alignment = cmp::max(T::align_of(), 8); + rtunwrap!(Ok, super::alloc(size, alignment)) as _ } else { T::align_of() as _ // dangling pointer ok for size 0 }; From c1e8e4dbb4a7542f7617b5442179269ec843405e Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Tue, 22 Mar 2022 17:34:44 +0100 Subject: [PATCH 14/21] Test `copy_to_userspace` function --- .../std/src/sys/sgx/abi/usercalls/alloc.rs | 2 +- library/std/src/sys/sgx/abi/usercalls/mod.rs | 2 ++ .../std/src/sys/sgx/abi/usercalls/tests.rs | 30 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 library/std/src/sys/sgx/abi/usercalls/tests.rs diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 4c1f279857f9c..4ac27e85f8ba8 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -317,7 +317,7 @@ where /// * The `dst` pointer is null /// * The `src` memory range is not in enclave memory /// * The `dst` memory range is not in user memory -unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) { +pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) { unsafe fn copy_bytewise_to_userspace(src: *const u8, dst: *mut u8, len: usize) { unsafe { let seg_sel: u16 = 0; diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs index 2f99abba77667..79d1db5e1c50d 100644 --- a/library/std/src/sys/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs @@ -6,6 +6,8 @@ use crate::time::{Duration, Instant}; pub(crate) mod alloc; #[macro_use] pub(crate) mod raw; +#[cfg(test)] +mod tests; use self::raw::*; diff --git a/library/std/src/sys/sgx/abi/usercalls/tests.rs b/library/std/src/sys/sgx/abi/usercalls/tests.rs new file mode 100644 index 0000000000000..cbf7d7d54f7a2 --- /dev/null +++ b/library/std/src/sys/sgx/abi/usercalls/tests.rs @@ -0,0 +1,30 @@ +use super::alloc::copy_to_userspace; +use super::alloc::User; + +#[test] +fn test_copy_function() { + let mut src = [0u8; 100]; + let mut dst = User::<[u8]>::uninitialized(100); + + for i in 0..src.len() { + src[i] = i as _; + } + + for size in 0..48 { + // For all possible alignment + for offset in 0..8 { + // overwrite complete dst + dst.copy_from_enclave(&[0u8; 100]); + + // Copy src[0..size] to dst + offset + unsafe { copy_to_userspace(src.as_ptr(), dst.as_mut_ptr().offset(offset), size) }; + + // Verify copy + for byte in 0..size { + unsafe { + assert_eq!(*dst.as_ptr().offset(offset + byte as isize), src[byte as usize]); + } + } + } + } +} From f835f9cfda1f30bb3ccb104a26f8ed6354effc43 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Wed, 22 Jun 2022 13:47:32 +0200 Subject: [PATCH 15/21] Address reviewer comments --- library/std/src/sys/sgx/abi/usercalls/alloc.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 4ac27e85f8ba8..ea24fedd0eb3d 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -307,8 +307,9 @@ where /// Copies `len` bytes of data from enclave pointer `src` to userspace `dst` /// -/// This function mitigates stale data vulnerabilities -/// https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html +/// This function mitigates stale data vulnerabilities by ensuring all writes to untrusted memory are either: +/// - preceded by the VERW instruction and followed by the MFENCE; LFENCE instruction sequence +/// - or are in multiples of 8 bytes, aligned to an 8-byte boundary /// /// # Panics /// This function panics if: @@ -317,10 +318,14 @@ where /// * The `dst` pointer is null /// * The `src` memory range is not in enclave memory /// * The `dst` memory range is not in user memory +/// +/// # References +/// - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html +/// - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html#inpage-nav-3-2-2 pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) { unsafe fn copy_bytewise_to_userspace(src: *const u8, dst: *mut u8, len: usize) { unsafe { - let seg_sel: u16 = 0; + let mut seg_sel: u16 = 0; for off in 0..len { asm!(" mov %ds, ({seg_sel}) @@ -328,10 +333,10 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) movb {val}, ({dst}) mfence lfence - ", + ", val = in(reg_byte) *src.offset(off as isize), dst = in(reg) dst.offset(off as isize), - seg_sel = in(reg) &seg_sel, + seg_sel = in(reg) &mut seg_sel, options(nostack, att_syntax) ); } From d8c7a157e677cae4af99132e5ef039ef5d50a330 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 5 Jul 2022 21:54:38 +0200 Subject: [PATCH 16/21] Return a FxIndexSet in is_late_bound query. This return value is iterated upon by borrowck, hence the need to preserve a deterministic iteration order. --- compiler/rustc_middle/src/arena.rs | 1 + compiler/rustc_middle/src/middle/resolve_lifetime.rs | 4 ++-- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/query.rs | 2 +- compiler/rustc_resolve/src/late/lifetimes.rs | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 7c90cbb9092b8..c1ec5d68a7b6b 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -85,6 +85,7 @@ macro_rules! arena_types { [] attribute: rustc_ast::Attribute, [] name_set: rustc_data_structures::fx::FxHashSet, [] hir_id_set: rustc_hir::HirIdSet, + [] late_bound_lifetimes: rustc_data_structures::fx::FxIndexSet, // Interned types [] tys: rustc_data_structures::intern::WithStableHash>, diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 70586cefaeee1..11ce6313147d4 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -2,7 +2,7 @@ use crate::ty; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::ItemLocalId; use rustc_macros::HashStable; @@ -64,7 +64,7 @@ pub struct ResolveLifetimes { /// Set of lifetime def ids that are late-bound; a region can /// be late-bound if (a) it does NOT appear in a where-clause and /// (b) it DOES appear in the arguments. - pub late_bound: FxHashMap>, + pub late_bound: FxHashMap>, pub late_bound_vars: FxHashMap>>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6d7ec247d0452..a23ff302a40aa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1537,7 +1537,7 @@ rustc_queries! { Option<&'tcx FxHashMap> { desc { "looking up a named region" } } - query is_late_bound_map(_: LocalDefId) -> Option<(LocalDefId, &'tcx FxHashSet)> { + query is_late_bound_map(_: LocalDefId) -> Option<(LocalDefId, &'tcx FxIndexSet)> { desc { "testing if a region is late bound" } } /// For a given item (like a struct), gets the default lifetimes to be used diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index fb937ded65af1..1bb49a59ba47b 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -36,7 +36,7 @@ use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, T use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index ff75e4eae3568..7f7c8ec53aa1b 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -8,7 +8,7 @@ use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc_ast::walk_list; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::{struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -540,7 +540,7 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId { fn is_late_bound_map<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> Option<(LocalDefId, &'tcx FxHashSet)> { +) -> Option<(LocalDefId, &'tcx FxIndexSet)> { match tcx.def_kind(def_id) { DefKind::AnonConst | DefKind::InlineConst => { let mut def_id = tcx.local_parent(def_id); From 5a4723abe4077e70c47dc788979f7bb2876679fd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 6 Jul 2022 10:56:35 +0200 Subject: [PATCH 17/21] Add regression test. --- src/test/incremental/async-lifetimes.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/incremental/async-lifetimes.rs diff --git a/src/test/incremental/async-lifetimes.rs b/src/test/incremental/async-lifetimes.rs new file mode 100644 index 0000000000000..b97725d3b6a7d --- /dev/null +++ b/src/test/incremental/async-lifetimes.rs @@ -0,0 +1,17 @@ +// revisions: rpass1 rpass2 +// edition:2021 + +#![allow(unused)] + +struct Foo; + +impl Foo { + async fn f(&self, _: &&()) -> &() { + &() + } +} + +#[cfg(rpass2)] +enum Bar {} + +fn main() {} From f1aa6522abfdd9d39f5a86f48fce2d89e7dd6325 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 6 Jul 2022 11:32:55 +0200 Subject: [PATCH 18/21] Add link to issue for src/test/incremental/async-lifetimes.rs --- src/test/incremental/async-lifetimes.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/incremental/async-lifetimes.rs b/src/test/incremental/async-lifetimes.rs index b97725d3b6a7d..90a0b93b99a13 100644 --- a/src/test/incremental/async-lifetimes.rs +++ b/src/test/incremental/async-lifetimes.rs @@ -1,6 +1,8 @@ // revisions: rpass1 rpass2 // edition:2021 +// See https://github.com/rust-lang/rust/issues/98890 + #![allow(unused)] struct Foo; From 94ed9c9790de180c67c7e3fadef39975b7fda632 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 00:32:01 +0200 Subject: [PATCH 19/21] Sort query output. --- compiler/rustc_resolve/src/late/lifetimes.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 7f7c8ec53aa1b..9b4184840bd27 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -482,6 +482,11 @@ fn convert_named_region_map(tcx: TyCtxt<'_>, named_region_map: NamedRegionMap) - let def_id = tcx.hir().local_def_id(hir_id); map.insert(def_id); } + for (_, late_bound) in &mut rl.late_bound { + late_bound.sort_by(|&a, &b| { + tcx.def_path_hash(a.to_def_id()).cmp(&tcx.def_path_hash(b.to_def_id())) + }); + } for (hir_id, v) in named_region_map.late_bound_vars { let map = rl.late_bound_vars.entry(hir_id.owner).or_default(); map.insert(hir_id.local_id, v); From 650421c07156415e270b6456b0194c9094edd639 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 15 Jul 2022 17:51:06 -0400 Subject: [PATCH 20/21] Release 1.62.1 --- RELEASES.md | 18 ++++++++++++++++++ src/version | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 3d88891ad215c..fa82077e65bb3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,21 @@ +Version 1.62.1 (2022-07-19) +========================== + +Rust 1.62.1 addresses a few recent regressions in the compiler and standard +library, and also mitigates a CPU vulnerability on Intel SGX. + +* [The compiler fixed unsound function coercions involving `impl Trait` return types.][98608] +* [The compiler fixed an incremental compilation bug with `async fn` lifetimes.][98890] +* [Windows added a fallback for overlapped I/O in synchronous reads and writes.][98950] +* [The `x86_64-fortanix-unknown-sgx` target added a mitigation for the + MMIO stale data vulnerability][98126], advisory [INTEL-SA-00615]. + +[98608]: https://github.com/rust-lang/rust/issues/98608 +[98890]: https://github.com/rust-lang/rust/issues/98890 +[98950]: https://github.com/rust-lang/rust/pull/98950 +[98126]: https://github.com/rust-lang/rust/pull/98126 +[INTEL-SA-00615]: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html + Version 1.62.0 (2022-06-30) ========================== diff --git a/src/version b/src/version index 76d0536205683..b77a81dcb12a8 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.62.0 +1.62.1 From 647922f9d8a6f1fa639ab206e60a76d43cc9d3dd Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 9 Jul 2022 18:16:53 -0400 Subject: [PATCH 21/21] Fix tests after beta backport --- src/test/ui/type-alias-impl-trait/issue-98604.stderr | 2 +- src/test/ui/type-alias-impl-trait/issue-98608.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.stderr b/src/test/ui/type-alias-impl-trait/issue-98604.stderr index f04d1b4d7877e..ad3982760c39c 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98604.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-98604.stderr @@ -11,7 +11,7 @@ LL | async fn test() {} | ^ checked the `Output` of this `async fn`, found opaque type = note: expected struct `Pin + 'static)>>` found opaque type `impl Future` - = note: required for the cast from `fn() -> impl Future {test}` to the object type `dyn Fn() -> Pin + 'static)>>` + = note: required for the cast to the object type `dyn Fn() -> Pin + 'static)>>` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.stderr b/src/test/ui/type-alias-impl-trait/issue-98608.stderr index 8f3ec7d9d1616..6773b01112d87 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98608.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-98608.stderr @@ -9,7 +9,7 @@ LL | let b: Box Box> = Box::new(hi); | = note: expected struct `Box` found opaque type `impl Sized` - = note: required for the cast from `fn() -> impl Sized {hi}` to the object type `dyn Fn() -> Box` + = note: required for the cast to the object type `dyn Fn() -> Box` error: aborting due to previous error