]>
Commit | Line | Data |
---|---|---|
532ac7d7 | 1 | pub use crate::passes::BoxedResolver; |
dfeec247 | 2 | use crate::util; |
532ac7d7 | 3 | |
74b04a01 | 4 | use rustc_ast::token; |
3dfed10e | 5 | use rustc_ast::{self as ast, MetaItemKind}; |
ba9703b0 | 6 | use rustc_codegen_ssa::traits::CodegenBackend; |
dfeec247 | 7 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
532ac7d7 | 8 | use rustc_data_structures::sync::Lrc; |
dfeec247 | 9 | use rustc_data_structures::OnDrop; |
60c5eb7d | 10 | use rustc_errors::registry::Registry; |
6a06907d | 11 | use rustc_errors::{ErrorReported, Handler}; |
dfeec247 | 12 | use rustc_lint::LintStore; |
ba9703b0 | 13 | use rustc_middle::ty; |
a2a8927a | 14 | use rustc_parse::maybe_new_parser_from_source_str; |
136023e0 | 15 | use rustc_query_impl::QueryCtxt; |
ba9703b0 XL |
16 | use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; |
17 | use rustc_session::early_error; | |
18 | use rustc_session::lint; | |
74b04a01 | 19 | use rustc_session::parse::{CrateConfig, ParseSess}; |
ba9703b0 | 20 | use rustc_session::{DiagnosticOutput, Session}; |
f9f354fc | 21 | use rustc_span::source_map::{FileLoader, FileName}; |
532ac7d7 XL |
22 | use std::path::PathBuf; |
23 | use std::result; | |
24 | use std::sync::{Arc, Mutex}; | |
532ac7d7 XL |
25 | |
26 | pub 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 |
32 | pub 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 | ||
45 | impl 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`. |
84 | pub 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 |
135 | pub 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 | 179 | pub 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 | 229 | pub 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 | |
240 | pub 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 | } |