1 pub use crate::passes
::BoxedResolver
;
5 use rustc_ast
::{self as ast, LitKind, MetaItemKind}
;
6 use rustc_codegen_ssa
::traits
::CodegenBackend
;
7 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
8 use rustc_data_structures
::sync
::Lrc
;
9 use rustc_data_structures
::OnDrop
;
10 use rustc_errors
::registry
::Registry
;
11 use rustc_errors
::{ErrorGuaranteed, Handler}
;
12 use rustc_lint
::LintStore
;
14 use rustc_parse
::maybe_new_parser_from_source_str
;
15 use rustc_query_impl
::QueryCtxt
;
16 use rustc_session
::config
::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames}
;
17 use rustc_session
::early_error
;
18 use rustc_session
::lint
;
19 use rustc_session
::parse
::{CrateConfig, ParseSess}
;
20 use rustc_session
::{DiagnosticOutput, Session}
;
21 use rustc_span
::source_map
::{FileLoader, FileName}
;
22 use rustc_span
::symbol
::sym
;
23 use std
::path
::PathBuf
;
26 pub type Result
<T
> = result
::Result
<T
, ErrorGuaranteed
>;
28 /// Represents a compiler session.
30 /// Can be used to run `rustc_interface` queries.
31 /// Created by passing [`Config`] to [`run_compiler`].
33 pub(crate) sess
: Lrc
<Session
>,
34 codegen_backend
: Lrc
<Box
<dyn CodegenBackend
>>,
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
>,
39 pub(crate) temps_dir
: Option
<PathBuf
>,
40 pub(crate) register_lints
: Option
<Box
<dyn Fn(&Session
, &mut LintStore
) + Send
+ Sync
>>,
41 pub(crate) override_queries
:
42 Option
<fn(&Session
, &mut ty
::query
::Providers
, &mut ty
::query
::ExternProviders
)>,
46 pub fn session(&self) -> &Lrc
<Session
> {
49 pub fn codegen_backend(&self) -> &Lrc
<Box
<dyn CodegenBackend
>> {
52 pub fn input(&self) -> &Input
{
55 pub fn output_dir(&self) -> &Option
<PathBuf
> {
58 pub fn output_file(&self) -> &Option
<PathBuf
> {
61 pub fn temps_dir(&self) -> &Option
<PathBuf
> {
64 pub fn register_lints(&self) -> &Option
<Box
<dyn Fn(&Session
, &mut LintStore
) + Send
+ Sync
>> {
67 pub fn build_output_filenames(
70 attrs
: &[ast
::Attribute
],
71 ) -> OutputFilenames
{
72 util
::build_output_filenames(
83 /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
84 pub fn parse_cfgspecs(cfgspecs
: Vec
<String
>) -> FxHashSet
<(String
, Option
<String
>)> {
85 rustc_span
::create_default_session_if_not_set_then(move |_
| {
89 let sess
= ParseSess
::with_silent_emitter(Some(format
!(
90 "this error occurred on the command line: `--cfg={}`",
93 let filename
= FileName
::cfg_spec_source_code(&s
);
98 ErrorOutputType
::default(),
99 &format
!(concat
!("invalid `--cfg` argument: `{}` (", $reason
, ")"), s
),
104 match maybe_new_parser_from_source_str(&sess
, filename
, s
.to_string()) {
105 Ok(mut parser
) => match 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");
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");
115 MetaItemKind
::NameValue(..) | MetaItemKind
::Word
=> {
116 let ident
= meta_item
.ident().expect("multi-segment cfg key");
117 return (ident
.name
, meta_item
.value_str());
122 Err(err
) => err
.cancel(),
124 Err(errs
) => drop(errs
),
127 // If the user tried to use a key="value" flag, but is missing the quotes, provide
128 // a hint about how to resolve this.
129 if s
.contains('
='
) && !s
.contains("=\"") && !s
.ends_with('
"') {
131 r#"expected `key` or `key
="value"`
, ensure escaping is appropriate
"#,
132 r#" for your shell
, try 'key
="value"' or key
=\"value
\""#
135 error!(r#"expected `key` or `key
="value"`
"#);
138 .collect::<CrateConfig>();
139 cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect()
143 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
144 pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
145 rustc_span::create_default_session_if_not_set_then(move |_| {
146 let mut cfg = CheckCfg::default();
148 'specs: for s in specs {
149 let sess = ParseSess::with_silent_emitter(Some(format!(
150 "this error occurred on the command line
: `
--check
-cfg
={}`
",
153 let filename = FileName::cfg_spec_source_code(&s);
158 ErrorOutputType::default(),
160 concat!("invalid `
--check
-cfg` argument
: `{}`
(", $reason, ")"),
167 match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
168 Ok(mut parser) => match parser.parse_meta_item() {
169 Ok(meta_item) if parser.token == token::Eof => {
170 if let Some(args) = meta_item.meta_item_list() {
171 if meta_item.has_name(sym::names) {
173 cfg.names_valid.get_or_insert_with(|| FxHashSet::default());
175 if arg.is_word() && arg.ident().is_some() {
176 let ident = arg.ident().expect("multi
-segment cfg key
");
177 names_valid.insert(ident.name.to_string());
179 error!("`
names()` arguments must be simple identifers
");
183 } else if meta_item.has_name(sym::values) {
184 if let Some((name, values)) = args.split_first() {
185 if name.is_word() && name.ident().is_some() {
186 let ident = name.ident().expect("multi
-segment cfg key
");
187 let ident_values = cfg
189 .entry(ident.name.to_string())
190 .or_insert_with(|| FxHashSet::default());
193 if let Some(LitKind::Str(s, _)) =
194 val.literal().map(|lit| &lit.kind)
196 ident_values.insert(s.to_string());
199 "`
values()` arguments must be string literals
"
207 "`
values()` first argument must be a simple identifer
"
210 } else if args.is_empty() {
211 cfg.well_known_values = true;
218 Err(err) => err.cancel(),
220 Err(errs) => drop(errs),
224 "expected `
names(name1
, name2
, ... nameN
)` or
\
225 `
values(name
, \"value1
\", \"value2
\", ... \"valueN
\")`
"
229 if let Some(names_valid) = &mut cfg.names_valid {
230 names_valid.extend(cfg.values_valid.keys().cloned());
236 /// The compiler configuration
238 /// Command line options
239 pub opts: config::Options,
241 /// cfg! configuration in addition to the default ones
242 pub crate_cfg: FxHashSet<(String, Option<String>)>,
243 pub crate_check_cfg: CheckCfg,
246 pub input_path: Option<PathBuf>,
247 pub output_dir: Option<PathBuf>,
248 pub output_file: Option<PathBuf>,
249 pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
250 pub diagnostic_output: DiagnosticOutput,
252 pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
254 /// This is a callback from the driver that is called when [`ParseSess`] is created.
255 pub parse_sess_created: Option<Box<dyn FnOnce(&mut ParseSess) + Send>>,
257 /// This is a callback from the driver that is called when we're registering lints;
258 /// it is called during plugin registration when we have the LintStore in a non-shared state.
260 /// Note that if you find a Some here you probably want to call that function in the new
261 /// function being registered.
262 pub register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
264 /// This is a callback from the driver that is called just after we have populated
265 /// the list of queries.
267 /// The second parameter is local providers and the third parameter is external providers.
268 pub override_queries:
269 Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
271 /// This is a callback from the driver that is called to create a codegen backend.
272 pub make_codegen_backend:
273 Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
275 /// Registry of diagnostics codes.
276 pub registry: Registry,
279 pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
280 crate::callbacks::setup_callbacks();
282 let registry = &config.registry;
283 let (mut sess, codegen_backend) = util::create_session(
286 config.crate_check_cfg,
287 config.diagnostic_output,
289 config.input_path.clone(),
291 config.make_codegen_backend,
295 if let Some(parse_sess_created) = config.parse_sess_created {
297 &mut Lrc::get_mut(&mut sess)
298 .expect("create_session() should never share the returned session
")
303 let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
305 let compiler = Compiler {
309 input_path: config.input_path,
310 output_dir: config.output_dir,
311 output_file: config.output_file,
313 register_lints: config.register_lints,
314 override_queries: config.override_queries,
317 rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
319 let _sess_abort_error = OnDrop(|| {
320 compiler.sess.finish_diagnostics(registry);
326 let prof = compiler.sess.prof.clone();
327 prof.generic_activity("drop_compiler
").run(move || drop(compiler));
332 pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
333 tracing::trace!("run_compiler
");
334 util::run_in_thread_pool_with_globals(
336 config.opts.debugging_opts.threads,
337 || create_compiler_and_run(config, f),
341 pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
342 eprintln!("query stack during panic
:");
344 // Be careful relying on global state here: this code is called from
345 // a panic hook, which means that the global `Handler` may be in a weird
346 // state if it was responsible for triggering the panic.
347 let i = ty::tls::with_context_opt(|icx| {
348 if let Some(icx) = icx {
349 QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames)
355 if num_frames == None || num_frames >= Some(i) {
356 eprintln!("end of query stack
");
358 eprintln!("we're just showing a limited slice of the query stack
");