]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_plugin_impl/src/load.rs
Rollup merge of #103204 - jyn514:autolabels, r=Mark-Simulacrum
[rust.git] / compiler / rustc_plugin_impl / src / load.rs
1 //! Used by `rustc` when loading a plugin.
2
3 use crate::errors::{LoadPluginError, MalformedPluginAttribute};
4 use crate::Registry;
5 use libloading::Library;
6 use rustc_ast::Crate;
7 use rustc_metadata::locator;
8 use rustc_session::cstore::MetadataLoader;
9 use rustc_session::Session;
10 use rustc_span::symbol::{sym, Ident};
11
12 use std::env;
13 use std::mem;
14 use std::path::PathBuf;
15
16 /// Pointer to a registrar function.
17 type PluginRegistrarFn = fn(&mut Registry<'_>);
18
19 /// Read plugin metadata and dynamically load registrar functions.
20 pub fn load_plugins(
21     sess: &Session,
22     metadata_loader: &dyn MetadataLoader,
23     krate: &Crate,
24 ) -> Vec<PluginRegistrarFn> {
25     let mut plugins = Vec::new();
26
27     for attr in &krate.attrs {
28         if !attr.has_name(sym::plugin) {
29             continue;
30         }
31
32         for plugin in attr.meta_item_list().unwrap_or_default() {
33             match plugin.ident() {
34                 Some(ident) if plugin.is_word() => {
35                     load_plugin(&mut plugins, sess, metadata_loader, ident)
36                 }
37                 _ => {
38                     sess.emit_err(MalformedPluginAttribute { span: plugin.span() });
39                 }
40             }
41         }
42     }
43
44     plugins
45 }
46
47 fn load_plugin(
48     plugins: &mut Vec<PluginRegistrarFn>,
49     sess: &Session,
50     metadata_loader: &dyn MetadataLoader,
51     ident: Ident,
52 ) {
53     let lib = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
54     let fun = dylink_registrar(lib).unwrap_or_else(|err| {
55         // This is fatal: there are almost certainly macros we need inside this crate, so
56         // continuing would spew "macro undefined" errors.
57         sess.emit_fatal(LoadPluginError { span: ident.span, msg: err.to_string() });
58     });
59     plugins.push(fun);
60 }
61
62 /// Dynamically link a registrar function into the compiler process.
63 fn dylink_registrar(lib_path: PathBuf) -> Result<PluginRegistrarFn, libloading::Error> {
64     // Make sure the path contains a / or the linker will search for it.
65     let lib_path = env::current_dir().unwrap().join(&lib_path);
66
67     let lib = unsafe { Library::new(&lib_path) }?;
68
69     let registrar_sym = unsafe { lib.get::<PluginRegistrarFn>(b"__rustc_plugin_registrar") }?;
70
71     // Intentionally leak the dynamic library. We can't ever unload it
72     // since the library can make things that will live arbitrarily long
73     // (e.g., an Rc cycle or a thread).
74     let registrar_sym = unsafe { registrar_sym.into_raw() };
75     mem::forget(lib);
76
77     Ok(*registrar_sym)
78 }