From 8f397bc8a0d8f2569d9aec7ad787b484c4b147e4 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 31 May 2021 14:51:31 +0200 Subject: [PATCH 01/17] Simplify box_region macros --- .../rustc_data_structures/src/box_region.rs | 43 ++++++++----------- compiler/rustc_interface/src/passes.rs | 3 +- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_data_structures/src/box_region.rs b/compiler/rustc_data_structures/src/box_region.rs index eb6f4e8213ec7..2f212b03e08e5 100644 --- a/compiler/rustc_data_structures/src/box_region.rs +++ b/compiler/rustc_data_structures/src/box_region.rs @@ -82,37 +82,35 @@ pub enum YieldType { #[macro_export] #[allow_internal_unstable(fn_traits)] macro_rules! declare_box_region_type { - (impl $v:vis - $name: ident, - $yield_type:ty, - for($($lifetimes:tt)*), - ($($args:ty),*) -> ($reti:ty, $retc:ty) - ) => { + ($v:vis $name: ident, ($($args:ty),*) -> ($reti:ty, $retc:ty)) => { $v struct $name($crate::box_region::PinnedGenerator< $reti, - for<$($lifetimes)*> fn(($($args,)*)), + fn(($($args,)*)), $retc >); impl $name { - fn new + 'static>( - generator: T - ) -> ($reti, Self) { + fn new(generator: T) -> ($reti, Self) + where T: ::std::ops::Generator< + $crate::box_region::Action, + Yield = $crate::box_region::YieldType<$reti, fn(($($args,)*))>, + Return = $retc, + > + 'static { let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator); (initial, $name(pinned)) } - $v fn access FnOnce($($args,)*) -> R, R>(&mut self, f: F) -> R { + $v fn access R, R>(&mut self, f: F) -> R { // Turn the FnOnce closure into *mut dyn FnMut() // so we can pass it in to the generator let mut r = None; let mut f = Some(f); - let mut_f: &mut dyn for<$($lifetimes)*> FnMut(($($args,)*)) = + let mut_f: &mut dyn FnMut(($($args,)*)) = &mut |args| { let f = f.take().unwrap(); r = Some(FnOnce::call_once(f, args)); }; - let mut_f = mut_f as *mut dyn for<$($lifetimes)*> FnMut(($($args,)*)); + let mut_f = mut_f as *mut dyn FnMut(($($args,)*)); // Get the generator to call our closure unsafe { @@ -127,36 +125,29 @@ macro_rules! declare_box_region_type { self.0.complete() } - fn initial_yield(value: $reti) -> $yield_type { + fn initial_yield( + value: $reti, + ) -> $crate::box_region::YieldType<$reti, fn(($($args,)*))> { $crate::box_region::YieldType::Initial(value) } } }; - - ($v:vis $name: ident, for($($lifetimes:tt)*), ($($args:ty),*) -> ($reti:ty, $retc:ty)) => { - declare_box_region_type!( - impl $v $name, - $crate::box_region::YieldType<$reti, for<$($lifetimes)*> fn(($($args,)*))>, - for($($lifetimes)*), - ($($args),*) -> ($reti, $retc) - ); - }; } #[macro_export] #[allow_internal_unstable(fn_traits)] macro_rules! box_region_allow_access { - (for($($lifetimes:tt)*), ($($args:ty),*), ($($exprs:expr),*), $action:ident) => { + (($($args:ty),*), ($($exprs:expr),*), $action:ident) => { loop { match $action { $crate::box_region::Action::Access(accessor) => { - let accessor: &mut dyn for<$($lifetimes)*> FnMut($($args),*) = unsafe { + let accessor: &mut dyn FnMut($($args),*) = unsafe { ::std::mem::transmute(accessor.get()) }; (*accessor)(($($exprs),*)); unsafe { let marker = $crate::box_region::Marker::< - for<$($lifetimes)*> fn(($($args,)*)) + fn(($($args,)*)) >::new(); $action = yield $crate::box_region::YieldType::Accessor(marker); }; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index aa7af609fb54f..478b2ef4d8f43 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -87,7 +87,6 @@ fn count_nodes(krate: &ast::Crate) -> usize { declare_box_region_type!( pub BoxedResolver, - for(), (&mut Resolver<'_>) -> (Result, ResolverOutputs) ); @@ -133,7 +132,7 @@ pub fn configure_and_expand( resolver } }; - box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver), action); + box_region_allow_access!((&mut Resolver<'_>), (&mut resolver), action); resolver.into_outputs() }); result.map(|k| (k, resolver)) From 86b3ebe2da46081b58a1f6208eb0f9c3ac4f3ec0 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 31 May 2021 15:17:04 +0200 Subject: [PATCH 02/17] Inline box_region macro calls --- .../rustc_data_structures/src/box_region.rs | 80 ------------------ compiler/rustc_interface/src/passes.rs | 82 +++++++++++++++++-- 2 files changed, 77 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_data_structures/src/box_region.rs b/compiler/rustc_data_structures/src/box_region.rs index 2f212b03e08e5..a1a757b705418 100644 --- a/compiler/rustc_data_structures/src/box_region.rs +++ b/compiler/rustc_data_structures/src/box_region.rs @@ -78,83 +78,3 @@ pub enum YieldType { Initial(I), Accessor(Marker), } - -#[macro_export] -#[allow_internal_unstable(fn_traits)] -macro_rules! declare_box_region_type { - ($v:vis $name: ident, ($($args:ty),*) -> ($reti:ty, $retc:ty)) => { - $v struct $name($crate::box_region::PinnedGenerator< - $reti, - fn(($($args,)*)), - $retc - >); - - impl $name { - fn new(generator: T) -> ($reti, Self) - where T: ::std::ops::Generator< - $crate::box_region::Action, - Yield = $crate::box_region::YieldType<$reti, fn(($($args,)*))>, - Return = $retc, - > + 'static { - let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator); - (initial, $name(pinned)) - } - - $v fn access R, R>(&mut self, f: F) -> R { - // Turn the FnOnce closure into *mut dyn FnMut() - // so we can pass it in to the generator - let mut r = None; - let mut f = Some(f); - let mut_f: &mut dyn FnMut(($($args,)*)) = - &mut |args| { - let f = f.take().unwrap(); - r = Some(FnOnce::call_once(f, args)); - }; - let mut_f = mut_f as *mut dyn FnMut(($($args,)*)); - - // Get the generator to call our closure - unsafe { - self.0.access(::std::mem::transmute(mut_f)); - } - - // Unwrap the result - r.unwrap() - } - - $v fn complete(mut self) -> $retc { - self.0.complete() - } - - fn initial_yield( - value: $reti, - ) -> $crate::box_region::YieldType<$reti, fn(($($args,)*))> { - $crate::box_region::YieldType::Initial(value) - } - } - }; -} - -#[macro_export] -#[allow_internal_unstable(fn_traits)] -macro_rules! box_region_allow_access { - (($($args:ty),*), ($($exprs:expr),*), $action:ident) => { - loop { - match $action { - $crate::box_region::Action::Access(accessor) => { - let accessor: &mut dyn FnMut($($args),*) = unsafe { - ::std::mem::transmute(accessor.get()) - }; - (*accessor)(($($exprs),*)); - unsafe { - let marker = $crate::box_region::Marker::< - fn(($($args,)*)) - >::new(); - $action = yield $crate::box_region::YieldType::Accessor(marker); - }; - } - $crate::box_region::Action::Complete => break, - $crate::box_region::Action::Initial => panic!("unexpected box_region action: Initial"), - } - } - } -} diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 478b2ef4d8f43..383917e41b520 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -6,10 +6,10 @@ use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_errors::{ErrorReported, PResult}; use rustc_expand::base::ExtCtxt; use rustc_hir::def_id::LOCAL_CRATE; @@ -85,11 +85,62 @@ fn count_nodes(krate: &ast::Crate) -> usize { counter.count } -declare_box_region_type!( - pub BoxedResolver, - (&mut Resolver<'_>) -> (Result, ResolverOutputs) +pub struct BoxedResolver( + rustc_data_structures::box_region::PinnedGenerator< + Result, + fn(&mut Resolver<'_>), + ResolverOutputs, + >, ); +impl BoxedResolver { + fn new(generator: T) -> (Result, Self) + where + T: ::std::ops::Generator< + rustc_data_structures::box_region::Action, + Yield = rustc_data_structures::box_region::YieldType< + Result, + fn(&mut Resolver<'_>), + >, + Return = ResolverOutputs, + > + 'static, + { + let (initial, pinned) = rustc_data_structures::box_region::PinnedGenerator::new(generator); + (initial, BoxedResolver(pinned)) + } + + pub fn access) -> R, R>(&mut self, f: F) -> R { + // Turn the FnOnce closure into *mut dyn FnMut() + // so we can pass it in to the generator + let mut r = None; + let mut f = Some(f); + let mut_f: &mut dyn FnMut(&mut Resolver<'_>) = &mut |resolver| { + let f = f.take().unwrap(); + r = Some(f(resolver)); + }; + let mut_f = mut_f as *mut dyn FnMut(&mut Resolver<'_>); + + // Get the generator to call our closure + unsafe { + self.0.access(::std::mem::transmute(mut_f)); + } + + // Unwrap the result + r.unwrap() + } + + pub fn complete(mut self) -> ResolverOutputs { + self.0.complete() + } + + fn initial_yield( + value: Result, + ) -> rustc_data_structures::box_region::YieldType, fn(&mut Resolver<'_>)> + { + rustc_data_structures::box_region::YieldType::Initial(value) + } +} + /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins, /// syntax expansion, secondary `cfg` expansion, synthesis of a test /// harness if one is to be provided, injection of a dependency on the @@ -132,7 +183,28 @@ pub fn configure_and_expand( resolver } }; - box_region_allow_access!((&mut Resolver<'_>), (&mut resolver), action); + + loop { + match action { + rustc_data_structures::box_region::Action::Access(accessor) => { + let accessor: &mut dyn FnMut(&mut Resolver<'_>) = + unsafe { ::std::mem::transmute(accessor.get()) }; + (*accessor)(&mut resolver); + unsafe { + let marker = rustc_data_structures::box_region::Marker::< + fn(&mut Resolver<'_>), + >::new(); + action = + yield rustc_data_structures::box_region::YieldType::Accessor(marker); + }; + } + rustc_data_structures::box_region::Action::Complete => break, + rustc_data_structures::box_region::Action::Initial => { + panic!("unexpected box_region action: Initial") + } + } + } + resolver.into_outputs() }); result.map(|k| (k, resolver)) From 99e112d28288566d7b3305e78d010bffd2aec89d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 31 May 2021 15:20:50 +0200 Subject: [PATCH 03/17] Inline the rest of box_region --- .../rustc_data_structures/src/box_region.rs | 80 -------------- compiler/rustc_data_structures/src/lib.rs | 2 - compiler/rustc_interface/src/passes.rs | 101 ++++++++++++++---- 3 files changed, 79 insertions(+), 104 deletions(-) delete mode 100644 compiler/rustc_data_structures/src/box_region.rs diff --git a/compiler/rustc_data_structures/src/box_region.rs b/compiler/rustc_data_structures/src/box_region.rs deleted file mode 100644 index a1a757b705418..0000000000000 --- a/compiler/rustc_data_structures/src/box_region.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! This module provides a way to deal with self-referential data. -//! -//! The main idea is to allocate such data in a generator frame and then -//! give access to it by executing user-provided closures inside that generator. -//! The module provides a safe abstraction for the latter task. -//! -//! The interface consists of two exported macros meant to be used together: -//! * `declare_box_region_type` wraps a generator inside a struct with `access` -//! method which accepts closures. -//! * `box_region_allow_access` is a helper which should be called inside -//! a generator to actually execute those closures. - -use std::marker::PhantomData; -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -#[derive(Copy, Clone)] -pub struct AccessAction(*mut dyn FnMut()); - -impl AccessAction { - pub fn get(self) -> *mut dyn FnMut() { - self.0 - } -} - -#[derive(Copy, Clone)] -pub enum Action { - Initial, - Access(AccessAction), - Complete, -} - -pub struct PinnedGenerator { - generator: Pin, Return = R>>>, -} - -impl PinnedGenerator { - pub fn new, Return = R> + 'static>( - generator: T, - ) -> (I, Self) { - let mut result = PinnedGenerator { generator: Box::pin(generator) }; - - // Run it to the first yield to set it up - let init = match Pin::new(&mut result.generator).resume(Action::Initial) { - GeneratorState::Yielded(YieldType::Initial(y)) => y, - _ => panic!(), - }; - - (init, result) - } - - pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { - // Call the generator, which in turn will call the closure - if let GeneratorState::Complete(_) = - Pin::new(&mut self.generator).resume(Action::Access(AccessAction(closure))) - { - panic!() - } - } - - pub fn complete(&mut self) -> R { - // Tell the generator we want it to complete, consuming it and yielding a result - let result = Pin::new(&mut self.generator).resume(Action::Complete); - if let GeneratorState::Complete(r) = result { r } else { panic!() } - } -} - -#[derive(PartialEq)] -pub struct Marker(PhantomData); - -impl Marker { - pub unsafe fn new() -> Self { - Marker(PhantomData) - } -} - -pub enum YieldType { - Initial(I), - Accessor(Marker), -} diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index a8b9f479f1e9e..d55e471810cd3 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,7 +10,6 @@ #![feature(array_windows)] #![feature(control_flow_enum)] #![feature(in_band_lifetimes)] -#![feature(generator_trait)] #![feature(min_specialization)] #![feature(auto_traits)] #![feature(nll)] @@ -63,7 +62,6 @@ macro_rules! unlikely { pub mod base_n; pub mod binary_search_util; -pub mod box_region; pub mod captures; pub mod flock; pub mod functor; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 383917e41b520..a93079c85a8c0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -47,7 +47,10 @@ use std::cell::RefCell; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; use std::lazy::SyncLazy; +use std::marker::PhantomData; +use std::ops::{Generator, GeneratorState}; use std::path::PathBuf; +use std::pin::Pin; use std::rc::Rc; use std::{env, fs, iter}; @@ -85,27 +88,85 @@ fn count_nodes(krate: &ast::Crate) -> usize { counter.count } +#[derive(Copy, Clone)] +pub struct AccessAction(*mut dyn FnMut()); + +impl AccessAction { + pub fn get(self) -> *mut dyn FnMut() { + self.0 + } +} + +#[derive(Copy, Clone)] +pub enum Action { + Initial, + Access(AccessAction), + Complete, +} + +pub struct PinnedGenerator { + generator: Pin, Return = R>>>, +} + +impl PinnedGenerator { + pub fn new, Return = R> + 'static>( + generator: T, + ) -> (I, Self) { + let mut result = PinnedGenerator { generator: Box::pin(generator) }; + + // Run it to the first yield to set it up + let init = match Pin::new(&mut result.generator).resume(Action::Initial) { + GeneratorState::Yielded(YieldType::Initial(y)) => y, + _ => panic!(), + }; + + (init, result) + } + + pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { + // Call the generator, which in turn will call the closure + if let GeneratorState::Complete(_) = + Pin::new(&mut self.generator).resume(Action::Access(AccessAction(closure))) + { + panic!() + } + } + + pub fn complete(&mut self) -> R { + // Tell the generator we want it to complete, consuming it and yielding a result + let result = Pin::new(&mut self.generator).resume(Action::Complete); + if let GeneratorState::Complete(r) = result { r } else { panic!() } + } +} + +#[derive(PartialEq)] +pub struct Marker(PhantomData); + +impl Marker { + pub unsafe fn new() -> Self { + Marker(PhantomData) + } +} + +pub enum YieldType { + Initial(I), + Accessor(Marker), +} + pub struct BoxedResolver( - rustc_data_structures::box_region::PinnedGenerator< - Result, - fn(&mut Resolver<'_>), - ResolverOutputs, - >, + PinnedGenerator, fn(&mut Resolver<'_>), ResolverOutputs>, ); impl BoxedResolver { fn new(generator: T) -> (Result, Self) where T: ::std::ops::Generator< - rustc_data_structures::box_region::Action, - Yield = rustc_data_structures::box_region::YieldType< - Result, - fn(&mut Resolver<'_>), - >, + Action, + Yield = YieldType, fn(&mut Resolver<'_>)>, Return = ResolverOutputs, > + 'static, { - let (initial, pinned) = rustc_data_structures::box_region::PinnedGenerator::new(generator); + let (initial, pinned) = PinnedGenerator::new(generator); (initial, BoxedResolver(pinned)) } @@ -135,9 +196,8 @@ impl BoxedResolver { fn initial_yield( value: Result, - ) -> rustc_data_structures::box_region::YieldType, fn(&mut Resolver<'_>)> - { - rustc_data_structures::box_region::YieldType::Initial(value) + ) -> YieldType, fn(&mut Resolver<'_>)> { + YieldType::Initial(value) } } @@ -186,20 +246,17 @@ pub fn configure_and_expand( loop { match action { - rustc_data_structures::box_region::Action::Access(accessor) => { + Action::Access(accessor) => { let accessor: &mut dyn FnMut(&mut Resolver<'_>) = unsafe { ::std::mem::transmute(accessor.get()) }; (*accessor)(&mut resolver); unsafe { - let marker = rustc_data_structures::box_region::Marker::< - fn(&mut Resolver<'_>), - >::new(); - action = - yield rustc_data_structures::box_region::YieldType::Accessor(marker); + let marker = Marker::)>::new(); + action = yield YieldType::Accessor(marker); }; } - rustc_data_structures::box_region::Action::Complete => break, - rustc_data_structures::box_region::Action::Initial => { + Action::Complete => break, + Action::Initial => { panic!("unexpected box_region action: Initial") } } From 1b7ec348783f1ebd3c4610c56ec02608dd3dad54 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 31 May 2021 15:28:17 +0200 Subject: [PATCH 04/17] Inline PinnedGenerator --- compiler/rustc_interface/src/passes.rs | 71 +++++++++++--------------- 1 file changed, 29 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a93079c85a8c0..e68d601a98d7d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -104,41 +104,6 @@ pub enum Action { Complete, } -pub struct PinnedGenerator { - generator: Pin, Return = R>>>, -} - -impl PinnedGenerator { - pub fn new, Return = R> + 'static>( - generator: T, - ) -> (I, Self) { - let mut result = PinnedGenerator { generator: Box::pin(generator) }; - - // Run it to the first yield to set it up - let init = match Pin::new(&mut result.generator).resume(Action::Initial) { - GeneratorState::Yielded(YieldType::Initial(y)) => y, - _ => panic!(), - }; - - (init, result) - } - - pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { - // Call the generator, which in turn will call the closure - if let GeneratorState::Complete(_) = - Pin::new(&mut self.generator).resume(Action::Access(AccessAction(closure))) - { - panic!() - } - } - - pub fn complete(&mut self) -> R { - // Tell the generator we want it to complete, consuming it and yielding a result - let result = Pin::new(&mut self.generator).resume(Action::Complete); - if let GeneratorState::Complete(r) = result { r } else { panic!() } - } -} - #[derive(PartialEq)] pub struct Marker(PhantomData); @@ -153,9 +118,17 @@ pub enum YieldType { Accessor(Marker), } -pub struct BoxedResolver( - PinnedGenerator, fn(&mut Resolver<'_>), ResolverOutputs>, -); +pub struct BoxedResolver { + generator: Pin< + Box< + dyn Generator< + Action, + Yield = YieldType, fn(&mut Resolver<'_>)>, + Return = ResolverOutputs, + >, + >, + >, +} impl BoxedResolver { fn new(generator: T) -> (Result, Self) @@ -166,8 +139,15 @@ impl BoxedResolver { Return = ResolverOutputs, > + 'static, { - let (initial, pinned) = PinnedGenerator::new(generator); - (initial, BoxedResolver(pinned)) + let mut generator = Box::pin(generator); + + // Run it to the first yield to set it up + let init = match Pin::new(&mut generator).resume(Action::Initial) { + GeneratorState::Yielded(YieldType::Initial(y)) => y, + _ => panic!(), + }; + + (init, BoxedResolver { generator }) } pub fn access) -> R, R>(&mut self, f: F) -> R { @@ -183,7 +163,12 @@ impl BoxedResolver { // Get the generator to call our closure unsafe { - self.0.access(::std::mem::transmute(mut_f)); + // Call the generator, which in turn will call the closure + if let GeneratorState::Complete(_) = Pin::new(&mut self.generator) + .resume(Action::Access(AccessAction(::std::mem::transmute(mut_f)))) + { + panic!() + } } // Unwrap the result @@ -191,7 +176,9 @@ impl BoxedResolver { } pub fn complete(mut self) -> ResolverOutputs { - self.0.complete() + // Tell the generator we want it to complete, consuming it and yielding a result + let result = Pin::new(&mut self.generator).resume(Action::Complete); + if let GeneratorState::Complete(r) = result { r } else { panic!() } } fn initial_yield( From bddf151deac83ad9306c31806ebacfede93e4b99 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 31 May 2021 16:24:09 +0200 Subject: [PATCH 05/17] Use more accurate lifetimes --- compiler/rustc_interface/src/passes.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e68d601a98d7d..8f6c955056d7e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -88,16 +88,14 @@ fn count_nodes(krate: &ast::Crate) -> usize { counter.count } -#[derive(Copy, Clone)] -pub struct AccessAction(*mut dyn FnMut()); +pub struct AccessAction(*mut dyn for<'a> FnMut(&mut Resolver<'a>)); impl AccessAction { - pub fn get(self) -> *mut dyn FnMut() { + pub fn get(self) -> *mut dyn for<'a> FnMut(&mut Resolver<'a>) { self.0 } } -#[derive(Copy, Clone)] pub enum Action { Initial, Access(AccessAction), @@ -123,7 +121,7 @@ pub struct BoxedResolver { Box< dyn Generator< Action, - Yield = YieldType, fn(&mut Resolver<'_>)>, + Yield = YieldType, for<'a> fn(&mut Resolver<'a>)>, Return = ResolverOutputs, >, >, @@ -150,16 +148,16 @@ impl BoxedResolver { (init, BoxedResolver { generator }) } - pub fn access) -> R, R>(&mut self, f: F) -> R { + pub fn access FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R { // Turn the FnOnce closure into *mut dyn FnMut() // so we can pass it in to the generator let mut r = None; let mut f = Some(f); - let mut_f: &mut dyn FnMut(&mut Resolver<'_>) = &mut |resolver| { + let mut_f: &mut dyn for<'a> FnMut(&mut Resolver<'a>) = &mut |resolver| { let f = f.take().unwrap(); r = Some(f(resolver)); }; - let mut_f = mut_f as *mut dyn FnMut(&mut Resolver<'_>); + let mut_f = mut_f as *mut dyn for<'a> FnMut(&mut Resolver<'a>); // Get the generator to call our closure unsafe { From ecc68e78799968d719e38c0fc5bf80e2d9800953 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 31 May 2021 16:33:09 +0200 Subject: [PATCH 06/17] Replace Pin::new with .as_mut() --- compiler/rustc_interface/src/passes.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8f6c955056d7e..e888af97dc113 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -140,7 +140,7 @@ impl BoxedResolver { let mut generator = Box::pin(generator); // Run it to the first yield to set it up - let init = match Pin::new(&mut generator).resume(Action::Initial) { + let init = match generator.as_mut().resume(Action::Initial) { GeneratorState::Yielded(YieldType::Initial(y)) => y, _ => panic!(), }; @@ -162,7 +162,9 @@ impl BoxedResolver { // Get the generator to call our closure unsafe { // Call the generator, which in turn will call the closure - if let GeneratorState::Complete(_) = Pin::new(&mut self.generator) + if let GeneratorState::Complete(_) = self + .generator + .as_mut() .resume(Action::Access(AccessAction(::std::mem::transmute(mut_f)))) { panic!() @@ -175,7 +177,7 @@ impl BoxedResolver { pub fn complete(mut self) -> ResolverOutputs { // Tell the generator we want it to complete, consuming it and yielding a result - let result = Pin::new(&mut self.generator).resume(Action::Complete); + let result = self.generator.as_mut().resume(Action::Complete); if let GeneratorState::Complete(r) = result { r } else { panic!() } } From db4d8e2cabe646bc5cfa89bb58804c47f8d6d3af Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 31 May 2021 17:36:53 +0200 Subject: [PATCH 07/17] Store boxed metadata loader in CrateLoader --- compiler/rustc_interface/src/passes.rs | 4 ++-- compiler/rustc_metadata/src/creader.rs | 6 +++--- compiler/rustc_resolve/src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e888af97dc113..7c5eac8bbae91 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -218,7 +218,7 @@ pub fn configure_and_expand( krate, &crate_name, &resolver_arenas, - &*metadata_loader, + metadata_loader, ); let mut resolver = match res { Err(v) => { @@ -350,7 +350,7 @@ fn configure_and_expand_inner<'a>( mut krate: ast::Crate, crate_name: &str, resolver_arenas: &'a ResolverArenas<'a>, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box, ) -> Result<(ast::Crate, Resolver<'a>)> { tracing::trace!("configure_and_expand_inner"); pre_expansion_lint(sess, lint_store, &krate, crate_name); diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e9ae22f8cedbc..d73cfe35dc4a1 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -54,7 +54,7 @@ pub struct CStore { pub struct CrateLoader<'a> { // Immutable configuration. sess: &'a Session, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box, local_crate_name: Symbol, // Mutable output. cstore: CStore, @@ -219,7 +219,7 @@ impl CStore { impl<'a> CrateLoader<'a> { pub fn new( sess: &'a Session, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box, local_crate_name: &str, ) -> Self { let local_crate_stable_id = @@ -544,7 +544,7 @@ impl<'a> CrateLoader<'a> { info!("falling back to a load"); let mut locator = CrateLocator::new( self.sess, - self.metadata_loader, + &*self.metadata_loader, name, hash, host_hash, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fd9b897111a98..6d5531d330783 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1198,7 +1198,7 @@ impl<'a> Resolver<'a> { session: &'a Session, krate: &Crate, crate_name: &str, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a> { let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }; From d376f032e65cc02e9a082ab1e919f3798af4b9dd Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 31 May 2021 19:48:47 +0200 Subject: [PATCH 08/17] Let several methods take &Resolver instead of a BoxedResolver wrapper --- compiler/rustc_interface/src/passes.rs | 33 +++++++++++-------------- compiler/rustc_interface/src/queries.rs | 21 ++++++++++------ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7c5eac8bbae91..79b318a4d34df 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -7,7 +7,6 @@ use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; -use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorReported, PResult}; @@ -346,7 +345,7 @@ fn pre_expansion_lint( fn configure_and_expand_inner<'a>( sess: &'a Session, - lint_store: &'a LintStore, + lint_store: &LintStore, mut krate: ast::Crate, crate_name: &str, resolver_arenas: &'a ResolverArenas<'a>, @@ -669,7 +668,7 @@ fn escape_dep_env(symbol: Symbol) -> String { fn write_out_deps( sess: &Session, - boxed_resolver: &Steal>>, + resolver: &Resolver<'_>, outputs: &OutputFilenames, out_filenames: &[PathBuf], ) { @@ -696,20 +695,18 @@ fn write_out_deps( } if sess.binary_dep_depinfo() { - boxed_resolver.borrow().borrow_mut().access(|resolver| { - for cnum in resolver.cstore().crates_untracked() { - let source = resolver.cstore().crate_source_untracked(cnum); - if let Some((path, _)) = source.dylib { - files.push(escape_dep_filename(&path.display().to_string())); - } - if let Some((path, _)) = source.rlib { - files.push(escape_dep_filename(&path.display().to_string())); - } - if let Some((path, _)) = source.rmeta { - files.push(escape_dep_filename(&path.display().to_string())); - } + for cnum in resolver.cstore().crates_untracked() { + let source = resolver.cstore().crate_source_untracked(cnum); + if let Some((path, _)) = source.dylib { + files.push(escape_dep_filename(&path.display().to_string())); } - }); + if let Some((path, _)) = source.rlib { + files.push(escape_dep_filename(&path.display().to_string())); + } + if let Some((path, _)) = source.rmeta { + files.push(escape_dep_filename(&path.display().to_string())); + } + } } let mut file = BufWriter::new(fs::File::create(&deps_filename)?); @@ -765,7 +762,7 @@ pub fn prepare_outputs( sess: &Session, compiler: &Compiler, krate: &ast::Crate, - boxed_resolver: &Steal>>, + resolver: &Resolver<'_>, crate_name: &str, ) -> Result { let _timer = sess.timer("prepare_outputs"); @@ -805,7 +802,7 @@ pub fn prepare_outputs( } } - write_out_deps(sess, boxed_resolver, &outputs, &output_paths); + write_out_deps(sess, resolver, &outputs, &output_paths); let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 2320f0b47d27d..cc9c30986e917 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -246,13 +246,20 @@ impl<'tcx> Queries<'tcx> { let expansion_result = self.expansion()?; let (krate, boxed_resolver, _) = &*expansion_result.peek(); let crate_name = self.crate_name()?.peek(); - passes::prepare_outputs( - self.session(), - self.compiler, - &krate, - &boxed_resolver, - &crate_name, - ) + + // These borrow(), borrow_mut() and access() calls are separate statements to prevent a + // "temporary value dropped while borrowed" error. + let boxed_resolver = boxed_resolver.borrow(); + let mut boxed_resolver = boxed_resolver.borrow_mut(); + boxed_resolver.access(|resolver| { + passes::prepare_outputs( + self.session(), + self.compiler, + &krate, + resolver, + &crate_name, + ) + }) }) } From 9d9ccec3fc416965dabd1851369a10315754a922 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 1 Jun 2021 10:04:13 +0200 Subject: [PATCH 09/17] Inline two more methods --- compiler/rustc_interface/src/passes.rs | 38 ++++++++++---------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 79b318a4d34df..0347b2ccda9af 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -102,15 +102,15 @@ pub enum Action { } #[derive(PartialEq)] -pub struct Marker(PhantomData); +struct Marker(PhantomData); impl Marker { - pub unsafe fn new() -> Self { + unsafe fn new() -> Self { Marker(PhantomData) } } -pub enum YieldType { +enum YieldType { Initial(I), Accessor(Marker), } @@ -174,16 +174,15 @@ impl BoxedResolver { r.unwrap() } - pub fn complete(mut self) -> ResolverOutputs { - // Tell the generator we want it to complete, consuming it and yielding a result - let result = self.generator.as_mut().resume(Action::Complete); - if let GeneratorState::Complete(r) = result { r } else { panic!() } - } - - fn initial_yield( - value: Result, - ) -> YieldType, fn(&mut Resolver<'_>)> { - YieldType::Initial(value) + pub fn to_resolver_outputs(resolver: Rc>) -> ResolverOutputs { + match Rc::try_unwrap(resolver) { + Ok(resolver) => { + // Tell the generator we want it to complete, consuming it and yielding a result + let result = resolver.into_inner().generator.as_mut().resume(Action::Complete); + if let GeneratorState::Complete(r) = result { r } else { panic!() } + } + Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), + } } } @@ -221,11 +220,11 @@ pub fn configure_and_expand( ); let mut resolver = match res { Err(v) => { - yield BoxedResolver::initial_yield(Err(v)); + yield YieldType::Initial(Err(v)); panic!() } Ok((krate, resolver)) => { - action = yield BoxedResolver::initial_yield(Ok(krate)); + action = yield YieldType::Initial(Ok(krate)); resolver } }; @@ -253,15 +252,6 @@ pub fn configure_and_expand( result.map(|k| (k, resolver)) } -impl BoxedResolver { - pub fn to_resolver_outputs(resolver: Rc>) -> ResolverOutputs { - match Rc::try_unwrap(resolver) { - Ok(resolver) => resolver.into_inner().complete(), - Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), - } - } -} - pub fn register_plugins<'a>( sess: &'a Session, metadata_loader: &'a dyn MetadataLoader, From 36bdfdc411c5d1fc6c83498f406f2191273e0833 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 1 Jun 2021 10:15:28 +0200 Subject: [PATCH 10/17] Don't return a BoxedResolver on errors --- compiler/rustc_interface/src/passes.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 0347b2ccda9af..afd553f06ca55 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -128,7 +128,7 @@ pub struct BoxedResolver { } impl BoxedResolver { - fn new(generator: T) -> (Result, Self) + fn new(generator: T) -> Result<(ast::Crate, Self)> where T: ::std::ops::Generator< Action, @@ -144,7 +144,7 @@ impl BoxedResolver { _ => panic!(), }; - (init, BoxedResolver { generator }) + init.map(|init| (init, BoxedResolver { generator })) } pub fn access FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R { @@ -206,7 +206,7 @@ pub fn configure_and_expand( // its contents but the results of name resolution on those contents. Hopefully we'll push // this back at some point. let crate_name = crate_name.to_string(); - let (result, resolver) = BoxedResolver::new(static move |mut action| { + BoxedResolver::new(static move |mut action| { let _ = action; let sess = &*sess; let resolver_arenas = Resolver::arenas(); @@ -248,8 +248,7 @@ pub fn configure_and_expand( } resolver.into_outputs() - }); - result.map(|k| (k, resolver)) + }) } pub fn register_plugins<'a>( From 86c2d1a2a7cb98bf5ff75e8236dea924c7a12638 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 1 Jun 2021 10:47:39 +0200 Subject: [PATCH 11/17] Don't use a generator for BoxedResolver The generator is non-trivial and requires unsafe code anyway. Using regular unsafe code without a generator is much easier to follow. --- compiler/rustc_interface/src/lib.rs | 2 - compiler/rustc_interface/src/passes.rs | 165 +++++++------------------ 2 files changed, 48 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index b5af2bfca3521..c7424b9e2a120 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -2,8 +2,6 @@ #![feature(box_patterns)] #![feature(internal_output_capture)] #![feature(nll)] -#![feature(generator_trait)] -#![feature(generators)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index afd553f06ca55..19fa5043295d3 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -46,8 +46,7 @@ use std::cell::RefCell; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; use std::lazy::SyncLazy; -use std::marker::PhantomData; -use std::ops::{Generator, GeneratorState}; +use std::marker::PhantomPinned; use std::path::PathBuf; use std::pin::Pin; use std::rc::Rc; @@ -87,99 +86,64 @@ fn count_nodes(krate: &ast::Crate) -> usize { counter.count } -pub struct AccessAction(*mut dyn for<'a> FnMut(&mut Resolver<'a>)); - -impl AccessAction { - pub fn get(self) -> *mut dyn for<'a> FnMut(&mut Resolver<'a>) { - self.0 - } -} - -pub enum Action { - Initial, - Access(AccessAction), - Complete, -} - -#[derive(PartialEq)] -struct Marker(PhantomData); - -impl Marker { - unsafe fn new() -> Self { - Marker(PhantomData) - } -} - -enum YieldType { - Initial(I), - Accessor(Marker), -} - -pub struct BoxedResolver { - generator: Pin< - Box< - dyn Generator< - Action, - Yield = YieldType, for<'a> fn(&mut Resolver<'a>)>, - Return = ResolverOutputs, - >, - >, - >, +pub struct BoxedResolver(Pin>); + +// Note: Drop order is important to prevent dangling references. Resolver must be dropped first, +// then resolver_arenas and finally session. +// The drop order is defined to be from top to bottom in RFC1857, so there is no need for +// ManuallyDrop for as long as the fields are not reordered. +struct BoxedResolverInner { + resolver: Option>, + resolver_arenas: ResolverArenas<'static>, + session: Lrc, + _pin: PhantomPinned, } impl BoxedResolver { - fn new(generator: T) -> Result<(ast::Crate, Self)> + fn new(session: Lrc, make_resolver: F) -> Result<(ast::Crate, Self)> where - T: ::std::ops::Generator< - Action, - Yield = YieldType, fn(&mut Resolver<'_>)>, - Return = ResolverOutputs, - > + 'static, + F: for<'a> FnOnce( + &'a Session, + &'a ResolverArenas<'a>, + ) -> Result<(ast::Crate, Resolver<'a>)>, { - let mut generator = Box::pin(generator); - - // Run it to the first yield to set it up - let init = match generator.as_mut().resume(Action::Initial) { - GeneratorState::Yielded(YieldType::Initial(y)) => y, - _ => panic!(), - }; - - init.map(|init| (init, BoxedResolver { generator })) + let mut boxed_resolver = Box::new(BoxedResolverInner { + session, + resolver_arenas: Resolver::arenas(), + resolver: None, + _pin: PhantomPinned, + }); + unsafe { + let (crate_, resolver) = make_resolver( + std::mem::transmute::<&Session, &Session>(&boxed_resolver.session), + std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>( + &boxed_resolver.resolver_arenas, + ), + )?; + boxed_resolver.resolver = + Some(std::mem::transmute::, Resolver<'_>>(resolver)); + Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver)))) + } } pub fn access FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R { - // Turn the FnOnce closure into *mut dyn FnMut() - // so we can pass it in to the generator - let mut r = None; - let mut f = Some(f); - let mut_f: &mut dyn for<'a> FnMut(&mut Resolver<'a>) = &mut |resolver| { - let f = f.take().unwrap(); - r = Some(f(resolver)); + let mut resolver = unsafe { + self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) }; - let mut_f = mut_f as *mut dyn for<'a> FnMut(&mut Resolver<'a>); - - // Get the generator to call our closure - unsafe { - // Call the generator, which in turn will call the closure - if let GeneratorState::Complete(_) = self - .generator - .as_mut() - .resume(Action::Access(AccessAction(::std::mem::transmute(mut_f)))) - { - panic!() - } - } - - // Unwrap the result - r.unwrap() + f((&mut *resolver).as_mut().unwrap()) } pub fn to_resolver_outputs(resolver: Rc>) -> ResolverOutputs { match Rc::try_unwrap(resolver) { Ok(resolver) => { - // Tell the generator we want it to complete, consuming it and yielding a result - let result = resolver.into_inner().generator.as_mut().resume(Action::Complete); - if let GeneratorState::Complete(r) = result { r } else { panic!() } + let mut resolver = resolver.into_inner(); + let mut resolver = unsafe { + resolver + .0 + .as_mut() + .map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) + }; + resolver.take().unwrap().into_outputs() } Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), } @@ -206,48 +170,15 @@ pub fn configure_and_expand( // its contents but the results of name resolution on those contents. Hopefully we'll push // this back at some point. let crate_name = crate_name.to_string(); - BoxedResolver::new(static move |mut action| { - let _ = action; - let sess = &*sess; - let resolver_arenas = Resolver::arenas(); - let res = configure_and_expand_inner( + BoxedResolver::new(sess, move |sess, resolver_arenas| { + configure_and_expand_inner( sess, &lint_store, krate, &crate_name, &resolver_arenas, metadata_loader, - ); - let mut resolver = match res { - Err(v) => { - yield YieldType::Initial(Err(v)); - panic!() - } - Ok((krate, resolver)) => { - action = yield YieldType::Initial(Ok(krate)); - resolver - } - }; - - loop { - match action { - Action::Access(accessor) => { - let accessor: &mut dyn FnMut(&mut Resolver<'_>) = - unsafe { ::std::mem::transmute(accessor.get()) }; - (*accessor)(&mut resolver); - unsafe { - let marker = Marker::)>::new(); - action = yield YieldType::Accessor(marker); - }; - } - Action::Complete => break, - Action::Initial => { - panic!("unexpected box_region action: Initial") - } - } - } - - resolver.into_outputs() + ) }) } From 5e148200d457ef7f6740990d15b7b9c534e3aaeb Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 1 Jun 2021 10:49:42 +0200 Subject: [PATCH 12/17] Use a submodule as safety boundary for BoxedResolver --- compiler/rustc_interface/src/passes.rs | 115 +++++++++++++------------ 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 19fa5043295d3..a6115762a82ec 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -86,66 +86,71 @@ fn count_nodes(krate: &ast::Crate) -> usize { counter.count } -pub struct BoxedResolver(Pin>); - -// Note: Drop order is important to prevent dangling references. Resolver must be dropped first, -// then resolver_arenas and finally session. -// The drop order is defined to be from top to bottom in RFC1857, so there is no need for -// ManuallyDrop for as long as the fields are not reordered. -struct BoxedResolverInner { - resolver: Option>, - resolver_arenas: ResolverArenas<'static>, - session: Lrc, - _pin: PhantomPinned, -} +pub use boxed_resolver::BoxedResolver; +mod boxed_resolver { + use super::*; + + pub struct BoxedResolver(Pin>); + + // Note: Drop order is important to prevent dangling references. Resolver must be dropped first, + // then resolver_arenas and finally session. + // The drop order is defined to be from top to bottom in RFC1857, so there is no need for + // ManuallyDrop for as long as the fields are not reordered. + struct BoxedResolverInner { + resolver: Option>, + resolver_arenas: ResolverArenas<'static>, + session: Lrc, + _pin: PhantomPinned, + } -impl BoxedResolver { - fn new(session: Lrc, make_resolver: F) -> Result<(ast::Crate, Self)> - where - F: for<'a> FnOnce( - &'a Session, - &'a ResolverArenas<'a>, - ) -> Result<(ast::Crate, Resolver<'a>)>, - { - let mut boxed_resolver = Box::new(BoxedResolverInner { - session, - resolver_arenas: Resolver::arenas(), - resolver: None, - _pin: PhantomPinned, - }); - unsafe { - let (crate_, resolver) = make_resolver( - std::mem::transmute::<&Session, &Session>(&boxed_resolver.session), - std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>( - &boxed_resolver.resolver_arenas, - ), - )?; - boxed_resolver.resolver = - Some(std::mem::transmute::, Resolver<'_>>(resolver)); - Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver)))) + impl BoxedResolver { + pub(super) fn new(session: Lrc, make_resolver: F) -> Result<(ast::Crate, Self)> + where + F: for<'a> FnOnce( + &'a Session, + &'a ResolverArenas<'a>, + ) -> Result<(ast::Crate, Resolver<'a>)>, + { + let mut boxed_resolver = Box::new(BoxedResolverInner { + session, + resolver_arenas: Resolver::arenas(), + resolver: None, + _pin: PhantomPinned, + }); + unsafe { + let (crate_, resolver) = make_resolver( + std::mem::transmute::<&Session, &Session>(&boxed_resolver.session), + std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>( + &boxed_resolver.resolver_arenas, + ), + )?; + boxed_resolver.resolver = + Some(std::mem::transmute::, Resolver<'_>>(resolver)); + Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver)))) + } } - } - pub fn access FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R { - let mut resolver = unsafe { - self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) - }; - f((&mut *resolver).as_mut().unwrap()) - } + pub fn access FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R { + let mut resolver = unsafe { + self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) + }; + f((&mut *resolver).as_mut().unwrap()) + } - pub fn to_resolver_outputs(resolver: Rc>) -> ResolverOutputs { - match Rc::try_unwrap(resolver) { - Ok(resolver) => { - let mut resolver = resolver.into_inner(); - let mut resolver = unsafe { - resolver - .0 - .as_mut() - .map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) - }; - resolver.take().unwrap().into_outputs() + pub fn to_resolver_outputs(resolver: Rc>) -> ResolverOutputs { + match Rc::try_unwrap(resolver) { + Ok(resolver) => { + let mut resolver = resolver.into_inner(); + let mut resolver = unsafe { + resolver + .0 + .as_mut() + .map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) + }; + resolver.take().unwrap().into_outputs() + } + Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), } - Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), } } } From cf1f92a2ca29bd8ae183929fa44447c9d3bd6637 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 1 Jun 2021 11:51:32 +0200 Subject: [PATCH 13/17] Revert "Let several methods take &Resolver instead of a BoxedResolver wrapper" This reverts commit 5343ec338f72a61e2f51f9d90117092c8e8a725a. --- compiler/rustc_interface/src/passes.rs | 33 ++++++++++++++----------- compiler/rustc_interface/src/queries.rs | 21 ++++++---------- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a6115762a82ec..802d00faef9ac 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -7,6 +7,7 @@ use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; +use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorReported, PResult}; @@ -270,7 +271,7 @@ fn pre_expansion_lint( fn configure_and_expand_inner<'a>( sess: &'a Session, - lint_store: &LintStore, + lint_store: &'a LintStore, mut krate: ast::Crate, crate_name: &str, resolver_arenas: &'a ResolverArenas<'a>, @@ -593,7 +594,7 @@ fn escape_dep_env(symbol: Symbol) -> String { fn write_out_deps( sess: &Session, - resolver: &Resolver<'_>, + boxed_resolver: &Steal>>, outputs: &OutputFilenames, out_filenames: &[PathBuf], ) { @@ -620,18 +621,20 @@ fn write_out_deps( } if sess.binary_dep_depinfo() { - for cnum in resolver.cstore().crates_untracked() { - let source = resolver.cstore().crate_source_untracked(cnum); - if let Some((path, _)) = source.dylib { - files.push(escape_dep_filename(&path.display().to_string())); - } - if let Some((path, _)) = source.rlib { - files.push(escape_dep_filename(&path.display().to_string())); - } - if let Some((path, _)) = source.rmeta { - files.push(escape_dep_filename(&path.display().to_string())); + boxed_resolver.borrow().borrow_mut().access(|resolver| { + for cnum in resolver.cstore().crates_untracked() { + let source = resolver.cstore().crate_source_untracked(cnum); + if let Some((path, _)) = source.dylib { + files.push(escape_dep_filename(&path.display().to_string())); + } + if let Some((path, _)) = source.rlib { + files.push(escape_dep_filename(&path.display().to_string())); + } + if let Some((path, _)) = source.rmeta { + files.push(escape_dep_filename(&path.display().to_string())); + } } - } + }); } let mut file = BufWriter::new(fs::File::create(&deps_filename)?); @@ -687,7 +690,7 @@ pub fn prepare_outputs( sess: &Session, compiler: &Compiler, krate: &ast::Crate, - resolver: &Resolver<'_>, + boxed_resolver: &Steal>>, crate_name: &str, ) -> Result { let _timer = sess.timer("prepare_outputs"); @@ -727,7 +730,7 @@ pub fn prepare_outputs( } } - write_out_deps(sess, resolver, &outputs, &output_paths); + write_out_deps(sess, boxed_resolver, &outputs, &output_paths); let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index cc9c30986e917..2320f0b47d27d 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -246,20 +246,13 @@ impl<'tcx> Queries<'tcx> { let expansion_result = self.expansion()?; let (krate, boxed_resolver, _) = &*expansion_result.peek(); let crate_name = self.crate_name()?.peek(); - - // These borrow(), borrow_mut() and access() calls are separate statements to prevent a - // "temporary value dropped while borrowed" error. - let boxed_resolver = boxed_resolver.borrow(); - let mut boxed_resolver = boxed_resolver.borrow_mut(); - boxed_resolver.access(|resolver| { - passes::prepare_outputs( - self.session(), - self.compiler, - &krate, - resolver, - &crate_name, - ) - }) + passes::prepare_outputs( + self.session(), + self.compiler, + &krate, + &boxed_resolver, + &crate_name, + ) }) } From 2bf839e87086d1d636b22a938845bd5c33a39ca1 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 1 Jun 2021 11:52:44 +0200 Subject: [PATCH 14/17] Don't require LintStore to live for 'a in configure_and_expand_inner --- compiler/rustc_interface/src/passes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 802d00faef9ac..62abc5e696430 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -271,7 +271,7 @@ fn pre_expansion_lint( fn configure_and_expand_inner<'a>( sess: &'a Session, - lint_store: &'a LintStore, + lint_store: &LintStore, mut krate: ast::Crate, crate_name: &str, resolver_arenas: &'a ResolverArenas<'a>, From e1aa45b64d29ef03511c4fbd359ee42c6bb342ba Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 Jun 2021 14:47:01 +0200 Subject: [PATCH 15/17] Use explicit drop impl --- compiler/rustc_interface/src/passes.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 62abc5e696430..6bd8fc9e5eee9 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -93,17 +93,22 @@ mod boxed_resolver { pub struct BoxedResolver(Pin>); - // Note: Drop order is important to prevent dangling references. Resolver must be dropped first, - // then resolver_arenas and finally session. - // The drop order is defined to be from top to bottom in RFC1857, so there is no need for - // ManuallyDrop for as long as the fields are not reordered. struct BoxedResolverInner { - resolver: Option>, - resolver_arenas: ResolverArenas<'static>, session: Lrc, + resolver_arenas: Option>, + resolver: Option>, _pin: PhantomPinned, } + // Note: Drop order is important to prevent dangling references. Resolver must be dropped first, + // then resolver_arenas and finally session. + impl Drop for BoxedResolverInner { + fn drop(&mut self) { + self.resolver.take(); + self.resolver_arenas.take(); + } + } + impl BoxedResolver { pub(super) fn new(session: Lrc, make_resolver: F) -> Result<(ast::Crate, Self)> where @@ -114,7 +119,7 @@ mod boxed_resolver { { let mut boxed_resolver = Box::new(BoxedResolverInner { session, - resolver_arenas: Resolver::arenas(), + resolver_arenas: Some(Resolver::arenas()), resolver: None, _pin: PhantomPinned, }); @@ -122,7 +127,7 @@ mod boxed_resolver { let (crate_, resolver) = make_resolver( std::mem::transmute::<&Session, &Session>(&boxed_resolver.session), std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>( - &boxed_resolver.resolver_arenas, + boxed_resolver.resolver_arenas.as_ref().unwrap(), ), )?; boxed_resolver.resolver = From 2754d4e514157482dd2683640d7674634db2f89e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 Jun 2021 14:51:42 +0200 Subject: [PATCH 16/17] Add safety comments --- compiler/rustc_interface/src/passes.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6bd8fc9e5eee9..30092a02cc31e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -123,6 +123,9 @@ mod boxed_resolver { resolver: None, _pin: PhantomPinned, }); + // SAFETY: `make_resolver` takes a resolver arena with an arbitrary lifetime and + // returns a resolver with the same lifetime as the arena. We ensure that the arena + // outlives the resolver in the drop impl and elsewhere so these transmutes are sound. unsafe { let (crate_, resolver) = make_resolver( std::mem::transmute::<&Session, &Session>(&boxed_resolver.session), @@ -137,6 +140,7 @@ mod boxed_resolver { } pub fn access FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R { + // SAFETY: The resolver doesn't need to be pinned. let mut resolver = unsafe { self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) }; @@ -147,6 +151,7 @@ mod boxed_resolver { match Rc::try_unwrap(resolver) { Ok(resolver) => { let mut resolver = resolver.into_inner(); + // SAFETY: The resolver doesn't need to be pinned. let mut resolver = unsafe { resolver .0 From 4301d1ee7d9badf12a3e08d3642375ee754cdf03 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 10 Jun 2021 19:36:27 +0200 Subject: [PATCH 17/17] Remove unnecessary transmute --- compiler/rustc_interface/src/passes.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 30092a02cc31e..9f194238c0a65 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -133,8 +133,7 @@ mod boxed_resolver { boxed_resolver.resolver_arenas.as_ref().unwrap(), ), )?; - boxed_resolver.resolver = - Some(std::mem::transmute::, Resolver<'_>>(resolver)); + boxed_resolver.resolver = Some(resolver); Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver)))) } }