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};
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;
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)]
-pub struct Marker<T>(PhantomData<T>);
-
-impl<T> Marker<T> {
- pub unsafe fn new() -> Self {
- Marker(PhantomData)
- }
-}
-
-pub enum YieldType<I, A> {
- Initial(I),
- Accessor(Marker<A>),
-}
-
-pub struct BoxedResolver {
- generator: Pin<
- Box<
- dyn Generator<
- Action,
- Yield = YieldType<Result<ast::Crate>, for<'a> fn(&mut Resolver<'a>)>,
- Return = ResolverOutputs,
- >,
- >,
- >,
-}
-
-impl BoxedResolver {
- fn new<T>(generator: T) -> (Result<ast::Crate>, Self)
- where
- T: ::std::ops::Generator<
- Action,
- Yield = YieldType<Result<ast::Crate>, fn(&mut Resolver<'_>)>,
- Return = ResolverOutputs,
- > + 'static,
- {
- 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, BoxedResolver { generator })
+pub use boxed_resolver::BoxedResolver;
+mod boxed_resolver {
+ use super::*;
+
+ pub struct BoxedResolver(Pin<Box<BoxedResolverInner>>);
+
+ // 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<'static>>,
+ resolver_arenas: ResolverArenas<'static>,
+ session: Lrc<Session>,
+ _pin: PhantomPinned,
}
- pub fn access<F: for<'a> 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_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!()
+ impl BoxedResolver {
+ pub(super) fn new<F>(session: Lrc<Session>, 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<'_>>(resolver));
+ Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver))))
}
}
- // Unwrap the result
- 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!() }
- }
+ pub fn access<F: for<'a> 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())
+ }
- fn initial_yield(
- value: Result<ast::Crate>,
- ) -> YieldType<Result<ast::Crate>, fn(&mut Resolver<'_>)> {
- YieldType::Initial(value)
+ pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> 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()),
+ }
+ }
}
}
// 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| {
- 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 BoxedResolver::initial_yield(Err(v));
- panic!()
- }
- Ok((krate, resolver)) => {
- action = yield BoxedResolver::initial_yield(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::<fn(&mut Resolver<'_>)>::new();
- action = yield YieldType::Accessor(marker);
- };
- }
- Action::Complete => break,
- Action::Initial => {
- panic!("unexpected box_region action: Initial")
- }
- }
- }
-
- resolver.into_outputs()
- });
- result.map(|k| (k, resolver))
-}
-
-impl BoxedResolver {
- pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> 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>(
fn write_out_deps(
sess: &Session,
- resolver: &Resolver<'_>,
+ boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
outputs: &OutputFilenames,
out_filenames: &[PathBuf],
) {
}
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)?);
sess: &Session,
compiler: &Compiler,
krate: &ast::Crate,
- resolver: &Resolver<'_>,
+ boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
crate_name: &str,
) -> Result<OutputFilenames> {
let _timer = sess.timer("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;