summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_plugin_impl
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_plugin_impl')
-rw-r--r--compiler/rustc_plugin_impl/Cargo.toml17
-rw-r--r--compiler/rustc_plugin_impl/src/lib.rs23
-rw-r--r--compiler/rustc_plugin_impl/src/load.rs84
3 files changed, 124 insertions, 0 deletions
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml
new file mode 100644
index 000000000..b6ea533c8
--- /dev/null
+++ b/compiler/rustc_plugin_impl/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "rustc_plugin_impl"
+version = "0.0.0"
+build = false
+edition = "2021"
+
+[lib]
+doctest = false
+
+[dependencies]
+libloading = "0.7.1"
+rustc_errors = { path = "../rustc_errors" }
+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/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
new file mode 100644
index 000000000..1195045bd
--- /dev/null
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -0,0 +1,23 @@
+//! 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/nightly-rustc/")]
+#![recursion_limit = "256"]
+
+use rustc_lint::LintStore;
+
+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 000000000..618682da4
--- /dev/null
+++ b/compiler/rustc_plugin_impl/src/load.rs
@@ -0,0 +1,84 @@
+//! Used by `rustc` when loading a plugin.
+
+use crate::Registry;
+use libloading::Library;
+use rustc_ast::Crate;
+use rustc_errors::struct_span_err;
+use rustc_metadata::locator;
+use rustc_session::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 !attr.has_name(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 = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
+ let fun = dylink_registrar(lib).unwrap_or_else(|err| {
+ // This is fatal: there are almost certainly macros we need inside this crate, so
+ // continuing would spew "macro undefined" errors.
+ sess.span_fatal(ident.span, &err.to_string());
+ });
+ plugins.push(fun);
+}
+
+/// Dynamically link a registrar function into the compiler process.
+fn dylink_registrar(lib_path: PathBuf) -> Result<PluginRegistrarFn, libloading::Error> {
+ // Make sure the path contains a / or the linker will search for it.
+ let lib_path = env::current_dir().unwrap().join(&lib_path);
+
+ let lib = unsafe { Library::new(&lib_path) }?;
+
+ let registrar_sym = unsafe { lib.get::<PluginRegistrarFn>(b"__rustc_plugin_registrar") }?;
+
+ // 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 Rc cycle or a thread).
+ let registrar_sym = unsafe { registrar_sym.into_raw() };
+ mem::forget(lib);
+
+ Ok(*registrar_sym)
+}