diff options
| author | bors <bors@rust-lang.org> | 2020-08-30 15:57:57 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-08-30 15:57:57 +0000 |
| commit | 85fbf49ce0e2274d0acf798f6e703747674feec3 (patch) | |
| tree | 158a05eb3f204a8e72939b58427d0c2787a4eade /compiler/rustc_plugin_impl | |
| parent | db534b3ac286cf45688c3bbae6aa6e77439e52d2 (diff) | |
| parent | 9e5f7d5631b8f4009ac1c693e585d4b7108d4275 (diff) | |
| download | rust-85fbf49ce0e2274d0acf798f6e703747674feec3.tar.gz rust-85fbf49ce0e2274d0acf798f6e703747674feec3.zip | |
Auto merge of #74862 - mark-i-m:mv-compiler, r=petrochenkov
Move almost all compiler crates to compiler/ This PR implements https://github.com/rust-lang/compiler-team/issues/336 and moves all `rustc_*` crates from `src` to the new `compiler` directory. `librustc_foo` directories are renamed to `rustc_foo`. `src` directories are introduced inside `rustc_*` directories to mirror the scheme already use for `library` crates.
Diffstat (limited to 'compiler/rustc_plugin_impl')
| -rw-r--r-- | compiler/rustc_plugin_impl/Cargo.toml | 19 | ||||
| -rw-r--r-- | compiler/rustc_plugin_impl/src/build.rs | 62 | ||||
| -rw-r--r-- | compiler/rustc_plugin_impl/src/lib.rs | 25 | ||||
| -rw-r--r-- | compiler/rustc_plugin_impl/src/load.rs | 99 |
4 files changed, 205 insertions, 0 deletions
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml new file mode 100644 index 00000000000..500d13a8c16 --- /dev/null +++ b/compiler/rustc_plugin_impl/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_plugin_impl" +version = "0.0.0" +build = false +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_middle = { path = "../rustc_middle" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_lint = { path = "../rustc_lint" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_ast = { path = "../rustc_ast" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_plugin_impl/src/build.rs b/compiler/rustc_plugin_impl/src/build.rs new file mode 100644 index 00000000000..d16dd701a12 --- /dev/null +++ b/compiler/rustc_plugin_impl/src/build.rs @@ -0,0 +1,62 @@ +//! Used by `rustc` when compiling a plugin crate. + +use rustc_hir as hir; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::sym; +use rustc_span::Span; + +struct RegistrarFinder<'tcx> { + tcx: TyCtxt<'tcx>, + registrars: Vec<(hir::HirId, Span)>, +} + +impl<'v, 'tcx> ItemLikeVisitor<'v> for RegistrarFinder<'tcx> { + fn visit_item(&mut self, item: &hir::Item<'_>) { + if let hir::ItemKind::Fn(..) = item.kind { + if self.tcx.sess.contains_name(&item.attrs, sym::plugin_registrar) { + self.registrars.push((item.hir_id, item.span)); + } + } + } + + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} +} + +/// Finds the function marked with `#[plugin_registrar]`, if any. +pub fn find_plugin_registrar(tcx: TyCtxt<'_>) -> Option<DefId> { + tcx.plugin_registrar_fn(LOCAL_CRATE) +} + +fn plugin_registrar_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<DefId> { + assert_eq!(cnum, LOCAL_CRATE); + + let mut finder = RegistrarFinder { tcx, registrars: Vec::new() }; + tcx.hir().krate().visit_all_item_likes(&mut finder); + + match finder.registrars.len() { + 0 => None, + 1 => { + let (hir_id, _) = finder.registrars.pop().unwrap(); + Some(tcx.hir().local_def_id(hir_id).to_def_id()) + } + _ => { + let diagnostic = tcx.sess.diagnostic(); + let mut e = diagnostic.struct_err("multiple plugin registration functions found"); + for &(_, span) in &finder.registrars { + e.span_note(span, "one is here"); + } + e.emit(); + diagnostic.abort_if_errors(); + unreachable!(); + } + } +} + +pub fn provide(providers: &mut Providers) { + *providers = Providers { plugin_registrar_fn, ..*providers }; +} diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs new file mode 100644 index 00000000000..1eb65dd96ba --- /dev/null +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -0,0 +1,25 @@ +//! Infrastructure for compiler plugins. +//! +//! Plugins are a deprecated way to extend the behavior of `rustc` in various ways. +//! +//! See the [`plugin` +//! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) +//! of the Unstable Book for some examples. + +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(nll)] +#![recursion_limit = "256"] + +use rustc_lint::LintStore; + +pub mod build; +pub mod load; + +/// Structure used to register plugins. +/// +/// A plugin registrar function takes an `&mut Registry` and should call +/// methods to register its plugins. +pub struct Registry<'a> { + /// The `LintStore` allows plugins to register new lints. + pub lint_store: &'a mut LintStore, +} diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs new file mode 100644 index 00000000000..687f7db221f --- /dev/null +++ b/compiler/rustc_plugin_impl/src/load.rs @@ -0,0 +1,99 @@ +//! Used by `rustc` when loading a plugin. + +use crate::Registry; +use rustc_ast::Crate; +use rustc_errors::struct_span_err; +use rustc_metadata::locator; +use rustc_middle::middle::cstore::MetadataLoader; +use rustc_session::Session; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::Span; + +use std::borrow::ToOwned; +use std::env; +use std::mem; +use std::path::PathBuf; + +/// Pointer to a registrar function. +type PluginRegistrarFn = fn(&mut Registry<'_>); + +fn call_malformed_plugin_attribute(sess: &Session, span: Span) { + struct_span_err!(sess, span, E0498, "malformed `plugin` attribute") + .span_label(span, "malformed attribute") + .emit(); +} + +/// Read plugin metadata and dynamically load registrar functions. +pub fn load_plugins( + sess: &Session, + metadata_loader: &dyn MetadataLoader, + krate: &Crate, +) -> Vec<PluginRegistrarFn> { + let mut plugins = Vec::new(); + + for attr in &krate.attrs { + if !sess.check_name(attr, sym::plugin) { + continue; + } + + for plugin in attr.meta_item_list().unwrap_or_default() { + match plugin.ident() { + Some(ident) if plugin.is_word() => { + load_plugin(&mut plugins, sess, metadata_loader, ident) + } + _ => call_malformed_plugin_attribute(sess, plugin.span()), + } + } + } + + plugins +} + +fn load_plugin( + plugins: &mut Vec<PluginRegistrarFn>, + sess: &Session, + metadata_loader: &dyn MetadataLoader, + ident: Ident, +) { + let (lib, disambiguator) = + locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name); + let symbol = sess.generate_plugin_registrar_symbol(disambiguator); + let fun = dylink_registrar(sess, ident.span, lib, symbol); + plugins.push(fun); +} + +// Dynamically link a registrar function into the compiler process. +fn dylink_registrar( + sess: &Session, + span: Span, + path: PathBuf, + symbol: String, +) -> PluginRegistrarFn { + use rustc_metadata::dynamic_lib::DynamicLibrary; + + // Make sure the path contains a / or the linker will search for it. + let path = env::current_dir().unwrap().join(&path); + + let lib = match DynamicLibrary::open(&path) { + Ok(lib) => lib, + // this is fatal: there are almost certainly macros we need + // inside this crate, so continue would spew "macro undefined" + // errors + Err(err) => sess.span_fatal(span, &err), + }; + + unsafe { + let registrar = match lib.symbol(&symbol) { + Ok(registrar) => mem::transmute::<*mut u8, PluginRegistrarFn>(registrar), + // again fatal if we can't register macros + Err(err) => sess.span_fatal(span, &err), + }; + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long + // (e.g., an @-box cycle or a thread). + mem::forget(lib); + + registrar + } +} |
