]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_interface/src/interface.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / compiler / rustc_interface / src / interface.rs
CommitLineData
532ac7d7 1pub use crate::passes::BoxedResolver;
dfeec247 2use crate::util;
532ac7d7 3
74b04a01 4use rustc_ast::token;
3dfed10e 5use rustc_ast::{self as ast, MetaItemKind};
ba9703b0 6use rustc_codegen_ssa::traits::CodegenBackend;
dfeec247 7use rustc_data_structures::fx::{FxHashMap, FxHashSet};
532ac7d7 8use rustc_data_structures::sync::Lrc;
dfeec247 9use rustc_data_structures::OnDrop;
60c5eb7d 10use rustc_errors::registry::Registry;
6a06907d 11use rustc_errors::{ErrorReported, Handler};
dfeec247 12use rustc_lint::LintStore;
ba9703b0 13use rustc_middle::ty;
a2a8927a 14use rustc_parse::maybe_new_parser_from_source_str;
136023e0 15use rustc_query_impl::QueryCtxt;
ba9703b0
XL
16use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
17use rustc_session::early_error;
18use rustc_session::lint;
74b04a01 19use rustc_session::parse::{CrateConfig, ParseSess};
ba9703b0 20use rustc_session::{DiagnosticOutput, Session};
f9f354fc 21use rustc_span::source_map::{FileLoader, FileName};
532ac7d7
XL
22use std::path::PathBuf;
23use std::result;
24use std::sync::{Arc, Mutex};
532ac7d7
XL
25
26pub type Result<T> = result::Result<T, ErrorReported>;
27
28/// Represents a compiler session.
fc512014 29///
dfeec247 30/// Can be used to run `rustc_interface` queries.
fc512014 31/// Created by passing [`Config`] to [`run_compiler`].
532ac7d7
XL
32pub struct Compiler {
33 pub(crate) sess: Lrc<Session>,
34 codegen_backend: Lrc<Box<dyn CodegenBackend>>,
532ac7d7
XL
35 pub(crate) input: Input,
36 pub(crate) input_path: Option<PathBuf>,
37 pub(crate) output_dir: Option<PathBuf>,
38 pub(crate) output_file: Option<PathBuf>,
3c0e092e 39 pub(crate) temps_dir: Option<PathBuf>,
dfeec247 40 pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
60c5eb7d 41 pub(crate) override_queries:
3c0e092e 42 Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
532ac7d7
XL
43}
44
45impl Compiler {
46 pub fn session(&self) -> &Lrc<Session> {
47 &self.sess
48 }
49 pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
50 &self.codegen_backend
51 }
532ac7d7
XL
52 pub fn input(&self) -> &Input {
53 &self.input
54 }
55 pub fn output_dir(&self) -> &Option<PathBuf> {
56 &self.output_dir
57 }
58 pub fn output_file(&self) -> &Option<PathBuf> {
59 &self.output_file
60 }
3c0e092e
XL
61 pub fn temps_dir(&self) -> &Option<PathBuf> {
62 &self.temps_dir
63 }
fc512014
XL
64 pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
65 &self.register_lints
66 }
74b04a01
XL
67 pub fn build_output_filenames(
68 &self,
69 sess: &Session,
70 attrs: &[ast::Attribute],
71 ) -> OutputFilenames {
3c0e092e
XL
72 util::build_output_filenames(
73 &self.input,
74 &self.output_dir,
75 &self.output_file,
76 &self.temps_dir,
77 attrs,
78 sess,
79 )
74b04a01 80 }
532ac7d7
XL
81}
82
e74abb32
XL
83/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
84pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
136023e0 85 rustc_span::create_default_session_if_not_set_then(move |_| {
dfeec247
XL
86 let cfg = cfgspecs
87 .into_iter()
88 .map(|s| {
3c0e092e
XL
89 let sess = ParseSess::with_silent_emitter(Some(format!(
90 "this error occurred on the command line: `--cfg={}`",
91 s
92 )));
dfeec247 93 let filename = FileName::cfg_spec_source_code(&s);
dfeec247
XL
94
95 macro_rules! error {
96 ($reason: expr) => {
97 early_error(
98 ErrorOutputType::default(),
99 &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s),
100 );
101 };
102 }
103
a2a8927a
XL
104 match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
105 Ok(mut parser) => match &mut parser.parse_meta_item() {
106 Ok(meta_item) if parser.token == token::Eof => {
107 if meta_item.path.segments.len() != 1 {
108 error!("argument key must be an identifier");
dfeec247 109 }
a2a8927a
XL
110 match &meta_item.kind {
111 MetaItemKind::List(..) => {}
112 MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
113 error!("argument value must be a string");
114 }
115 MetaItemKind::NameValue(..) | MetaItemKind::Word => {
116 let ident = meta_item.ident().expect("multi-segment cfg key");
117 return (ident.name, meta_item.value_str());
118 }
dfeec247 119 }
e74abb32 120 }
a2a8927a
XL
121 Ok(..) => {}
122 Err(err) => err.cancel(),
123 },
124 Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()),
e74abb32 125 }
dfeec247
XL
126
127 error!(r#"expected `key` or `key="value"`"#);
128 })
74b04a01 129 .collect::<CrateConfig>();
dfeec247 130 cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect()
e74abb32
XL
131 })
132}
133
532ac7d7
XL
134/// The compiler configuration
135pub struct Config {
136 /// Command line options
137 pub opts: config::Options,
138
139 /// cfg! configuration in addition to the default ones
140 pub crate_cfg: FxHashSet<(String, Option<String>)>,
141
142 pub input: Input,
143 pub input_path: Option<PathBuf>,
144 pub output_dir: Option<PathBuf>,
145 pub output_file: Option<PathBuf>,
146 pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
147 pub diagnostic_output: DiagnosticOutput,
148
149 /// Set to capture stderr output during compiler execution
150 pub stderr: Option<Arc<Mutex<Vec<u8>>>>,
151
532ac7d7 152 pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
e74abb32 153
6a06907d
XL
154 /// This is a callback from the driver that is called when [`ParseSess`] is created.
155 pub parse_sess_created: Option<Box<dyn FnOnce(&mut ParseSess) + Send>>,
156
e74abb32
XL
157 /// This is a callback from the driver that is called when we're registering lints;
158 /// it is called during plugin registration when we have the LintStore in a non-shared state.
159 ///
160 /// Note that if you find a Some here you probably want to call that function in the new
161 /// function being registered.
dfeec247 162 pub register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
60c5eb7d
XL
163
164 /// This is a callback from the driver that is called just after we have populated
165 /// the list of queries.
166 ///
167 /// The second parameter is local providers and the third parameter is external providers.
168 pub override_queries:
3c0e092e 169 Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
60c5eb7d 170
1b1a35ee
XL
171 /// This is a callback from the driver that is called to create a codegen backend.
172 pub make_codegen_backend:
173 Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
174
60c5eb7d
XL
175 /// Registry of diagnostics codes.
176 pub registry: Registry,
532ac7d7
XL
177}
178
f035d41b 179pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
60c5eb7d 180 let registry = &config.registry;
6a06907d 181 let (mut sess, codegen_backend) = util::create_session(
532ac7d7
XL
182 config.opts,
183 config.crate_cfg,
184 config.diagnostic_output,
185 config.file_loader,
186 config.input_path.clone(),
187 config.lint_caps,
1b1a35ee 188 config.make_codegen_backend,
60c5eb7d 189 registry.clone(),
532ac7d7
XL
190 );
191
6a06907d
XL
192 if let Some(parse_sess_created) = config.parse_sess_created {
193 parse_sess_created(
194 &mut Lrc::get_mut(&mut sess)
195 .expect("create_session() should never share the returned session")
196 .parse_sess,
197 );
198 }
199
3c0e092e
XL
200 let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
201
532ac7d7
XL
202 let compiler = Compiler {
203 sess,
204 codegen_backend,
532ac7d7
XL
205 input: config.input,
206 input_path: config.input_path,
207 output_dir: config.output_dir,
208 output_file: config.output_file,
3c0e092e 209 temps_dir,
e74abb32 210 register_lints: config.register_lints,
60c5eb7d 211 override_queries: config.override_queries,
532ac7d7
XL
212 };
213
f035d41b
XL
214 rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
215 let r = {
216 let _sess_abort_error = OnDrop(|| {
217 compiler.sess.finish_diagnostics(registry);
218 });
dfeec247 219
f035d41b
XL
220 f(&compiler)
221 };
532ac7d7 222
f035d41b
XL
223 let prof = compiler.sess.prof.clone();
224 prof.generic_activity("drop_compiler").run(move || drop(compiler));
225 r
226 })
532ac7d7
XL
227}
228
60c5eb7d 229pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
3dfed10e 230 tracing::trace!("run_compiler");
532ac7d7 231 let stderr = config.stderr.take();
f035d41b 232 util::setup_callbacks_and_run_in_thread_pool_with_globals(
dc9dc135 233 config.opts.edition,
532ac7d7
XL
234 config.opts.debugging_opts.threads,
235 &stderr,
f035d41b 236 || create_compiler_and_run(config, f),
532ac7d7
XL
237 )
238}
6a06907d
XL
239
240pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
241 eprintln!("query stack during panic:");
242
243 // Be careful relying on global state here: this code is called from
244 // a panic hook, which means that the global `Handler` may be in a weird
245 // state if it was responsible for triggering the panic.
246 let i = ty::tls::with_context_opt(|icx| {
247 if let Some(icx) = icx {
136023e0 248 QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames)
6a06907d
XL
249 } else {
250 0
251 }
252 });
253
254 if num_frames == None || num_frames >= Some(i) {
255 eprintln!("end of query stack");
256 } else {
257 eprintln!("we're just showing a limited slice of the query stack");
258 }
259}