summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_interface/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_interface/src
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_interface/src')
-rw-r--r--compiler/rustc_interface/src/callbacks.rs6
-rw-r--r--compiler/rustc_interface/src/interface.rs497
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/passes.rs86
-rw-r--r--compiler/rustc_interface/src/queries.rs16
-rw-r--r--compiler/rustc_interface/src/tests.rs62
-rw-r--r--compiler/rustc_interface/src/util.rs112
7 files changed, 391 insertions, 389 deletions
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index 45b1aeb4a..ef00ced67 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -26,16 +26,14 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
})
}
-/// This is a callback from `rustc_ast` as it cannot access the implicit state
+/// This is a callback from `rustc_errors` as it cannot access the implicit state
/// in `rustc_middle` otherwise. It is used when diagnostic messages are
/// emitted and stores them in the current query, if there is one.
fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
tls::with_context_opt(|icx| {
if let Some(icx) = icx {
if let Some(diagnostics) = icx.diagnostics {
- let mut diagnostics = diagnostics.lock();
- diagnostics.extend(Some(diagnostic.clone()));
- std::mem::drop(diagnostics);
+ diagnostics.lock().extend(Some(diagnostic.clone()));
}
// Diagnostics are tracked, we can ignore the dependency.
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 1c330c064..c4962707f 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -5,6 +5,7 @@ use rustc_ast::{self as ast, LitKind, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::defer;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
use rustc_errors::{ErrorGuaranteed, Handler};
@@ -14,15 +15,18 @@ use rustc_middle::{bug, ty};
use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack;
-use rustc_session::config::{self, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames};
-use rustc_session::parse::{CrateConfig, ParseSess};
-use rustc_session::CompilerIO;
-use rustc_session::Session;
-use rustc_session::{lint, EarlyErrorHandler};
-use rustc_span::source_map::{FileLoader, FileName};
+use rustc_session::config::{
+ self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames,
+};
+use rustc_session::filesearch::sysroot_candidates;
+use rustc_session::parse::ParseSess;
+use rustc_session::{lint, CompilerIO, EarlyErrorHandler, Session};
+use rustc_span::source_map::FileLoader;
use rustc_span::symbol::sym;
+use rustc_span::FileName;
use std::path::PathBuf;
use std::result;
+use std::sync::Arc;
pub type Result<T> = result::Result<T, ErrorGuaranteed>;
@@ -59,184 +63,267 @@ impl Compiler {
}
}
-/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
-pub fn parse_cfgspecs(
- handler: &EarlyErrorHandler,
- cfgspecs: Vec<String>,
-) -> FxHashSet<(String, Option<String>)> {
- rustc_span::create_default_session_if_not_set_then(move |_| {
- let cfg = cfgspecs
- .into_iter()
- .map(|s| {
- let sess = ParseSess::with_silent_emitter(Some(format!(
- "this error occurred on the command line: `--cfg={s}`"
- )));
- let filename = FileName::cfg_spec_source_code(&s);
-
- macro_rules! error {
- ($reason: expr) => {
- handler.early_error(format!(
- concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
- s
- ));
- };
- }
-
- match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
- Ok(mut parser) => match parser.parse_meta_item() {
- Ok(meta_item) if parser.token == token::Eof => {
- if meta_item.path.segments.len() != 1 {
- error!("argument key must be an identifier");
- }
- match &meta_item.kind {
- MetaItemKind::List(..) => {}
- MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
- error!("argument value must be a string");
- }
- MetaItemKind::NameValue(..) | MetaItemKind::Word => {
- let ident = meta_item.ident().expect("multi-segment cfg key");
- return (ident.name, meta_item.value_str());
- }
- }
- }
- Ok(..) => {}
- Err(err) => err.cancel(),
- },
- Err(errs) => drop(errs),
- }
-
- // If the user tried to use a key="value" flag, but is missing the quotes, provide
- // a hint about how to resolve this.
- if s.contains('=') && !s.contains("=\"") && !s.ends_with('"') {
- error!(concat!(
- r#"expected `key` or `key="value"`, ensure escaping is appropriate"#,
- r#" for your shell, try 'key="value"' or key=\"value\""#
- ));
- } else {
- error!(r#"expected `key` or `key="value"`"#);
- }
- })
- .collect::<CrateConfig>();
- cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect()
- })
-}
-
-/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
-pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
- rustc_span::create_default_session_if_not_set_then(move |_| {
- let mut check_cfg = CheckCfg::default();
-
- for s in specs {
+/// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
+pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg {
+ cfgs.into_iter()
+ .map(|s| {
let sess = ParseSess::with_silent_emitter(Some(format!(
- "this error occurred on the command line: `--check-cfg={s}`"
+ "this error occurred on the command line: `--cfg={s}`"
)));
let filename = FileName::cfg_spec_source_code(&s);
macro_rules! error {
($reason: expr) => {
handler.early_error(format!(
- concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+ concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
s
- ))
+ ));
};
}
- let expected_error = || {
- error!(
- "expected `names(name1, name2, ... nameN)` or \
- `values(name, \"value1\", \"value2\", ... \"valueN\")`"
- )
- };
-
match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
Ok(mut parser) => match parser.parse_meta_item() {
Ok(meta_item) if parser.token == token::Eof => {
- if let Some(args) = meta_item.meta_item_list() {
- if meta_item.has_name(sym::names) {
- check_cfg.exhaustive_names = true;
- for arg in args {
- if arg.is_word() && arg.ident().is_some() {
- let ident = arg.ident().expect("multi-segment cfg key");
- check_cfg
- .expecteds
- .entry(ident.name.to_string())
- .or_insert(ExpectedValues::Any);
- } else {
- error!("`names()` arguments must be simple identifiers");
- }
- }
- } else if meta_item.has_name(sym::values) {
- if let Some((name, values)) = args.split_first() {
- if name.is_word() && name.ident().is_some() {
- let ident = name.ident().expect("multi-segment cfg key");
- let expected_values = check_cfg
- .expecteds
- .entry(ident.name.to_string())
- .and_modify(|expected_values| match expected_values {
- ExpectedValues::Some(_) => {}
- ExpectedValues::Any => {
- // handle the case where names(...) was done
- // before values by changing to a list
- *expected_values =
- ExpectedValues::Some(FxHashSet::default());
- }
- })
- .or_insert_with(|| {
- ExpectedValues::Some(FxHashSet::default())
- });
-
- let ExpectedValues::Some(expected_values) = expected_values
- else {
- bug!("`expected_values` should be a list a values")
- };
-
- for val in values {
- if let Some(LitKind::Str(s, _)) =
- val.lit().map(|lit| &lit.kind)
- {
- expected_values.insert(Some(s.to_string()));
- } else {
- error!(
- "`values()` arguments must be string literals"
- );
- }
- }
-
- if values.is_empty() {
- expected_values.insert(None);
- }
- } else {
- error!(
- "`values()` first argument must be a simple identifier"
- );
- }
- } else if args.is_empty() {
- check_cfg.exhaustive_values = true;
- } else {
- expected_error();
- }
- } else {
- expected_error();
+ if meta_item.path.segments.len() != 1 {
+ error!("argument key must be an identifier");
+ }
+ match &meta_item.kind {
+ MetaItemKind::List(..) => {}
+ MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
+ error!("argument value must be a string");
}
+ MetaItemKind::NameValue(..) | MetaItemKind::Word => {
+ let ident = meta_item.ident().expect("multi-segment cfg key");
+ return (ident.name, meta_item.value_str());
+ }
+ }
+ }
+ Ok(..) => {}
+ Err(err) => err.cancel(),
+ },
+ Err(errs) => drop(errs),
+ }
+
+ // If the user tried to use a key="value" flag, but is missing the quotes, provide
+ // a hint about how to resolve this.
+ if s.contains('=') && !s.contains("=\"") && !s.ends_with('"') {
+ error!(concat!(
+ r#"expected `key` or `key="value"`, ensure escaping is appropriate"#,
+ r#" for your shell, try 'key="value"' or key=\"value\""#
+ ));
+ } else {
+ error!(r#"expected `key` or `key="value"`"#);
+ }
+ })
+ .collect::<Cfg>()
+}
+
+/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
+pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
+ // If any --check-cfg is passed then exhaustive_values and exhaustive_names
+ // are enabled by default.
+ let exhaustive_names = !specs.is_empty();
+ let exhaustive_values = !specs.is_empty();
+ let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
+
+ let mut old_syntax = None;
+ for s in specs {
+ let sess = ParseSess::with_silent_emitter(Some(format!(
+ "this error occurred on the command line: `--check-cfg={s}`"
+ )));
+ let filename = FileName::cfg_spec_source_code(&s);
+
+ macro_rules! error {
+ ($reason:expr) => {
+ handler.early_error(format!(
+ concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+ s
+ ))
+ };
+ }
+
+ let expected_error = || -> ! {
+ error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
+ };
+
+ let Ok(mut parser) = maybe_new_parser_from_source_str(&sess, filename, s.to_string())
+ else {
+ expected_error();
+ };
+
+ let meta_item = match parser.parse_meta_item() {
+ Ok(meta_item) if parser.token == token::Eof => meta_item,
+ Ok(..) => expected_error(),
+ Err(err) => {
+ err.cancel();
+ expected_error();
+ }
+ };
+
+ let Some(args) = meta_item.meta_item_list() else {
+ expected_error();
+ };
+
+ let mut set_old_syntax = || {
+ // defaults are flipped for the old syntax
+ if old_syntax == None {
+ check_cfg.exhaustive_names = false;
+ check_cfg.exhaustive_values = false;
+ }
+ old_syntax = Some(true);
+ };
+
+ if meta_item.has_name(sym::names) {
+ set_old_syntax();
+
+ check_cfg.exhaustive_names = true;
+ for arg in args {
+ if arg.is_word() && let Some(ident) = arg.ident() {
+ check_cfg.expecteds.entry(ident.name).or_insert(ExpectedValues::Any);
+ } else {
+ error!("`names()` arguments must be simple identifiers");
+ }
+ }
+ } else if meta_item.has_name(sym::values) {
+ set_old_syntax();
+
+ if let Some((name, values)) = args.split_first() {
+ if name.is_word() && let Some(ident) = name.ident() {
+ let expected_values = check_cfg
+ .expecteds
+ .entry(ident.name)
+ .and_modify(|expected_values| match expected_values {
+ ExpectedValues::Some(_) => {}
+ ExpectedValues::Any => {
+ // handle the case where names(...) was done
+ // before values by changing to a list
+ *expected_values = ExpectedValues::Some(FxHashSet::default());
+ }
+ })
+ .or_insert_with(|| ExpectedValues::Some(FxHashSet::default()));
+
+ let ExpectedValues::Some(expected_values) = expected_values else {
+ bug!("`expected_values` should be a list a values")
+ };
+
+ for val in values {
+ if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) {
+ expected_values.insert(Some(*s));
} else {
- expected_error();
+ error!("`values()` arguments must be string literals");
}
}
- Ok(..) => expected_error(),
- Err(err) => {
- err.cancel();
- expected_error();
+
+ if values.is_empty() {
+ expected_values.insert(None);
}
- },
- Err(errs) => {
- drop(errs);
- expected_error();
+ } else {
+ error!("`values()` first argument must be a simple identifier");
+ }
+ } else if args.is_empty() {
+ check_cfg.exhaustive_values = true;
+ } else {
+ expected_error();
+ }
+ } else if meta_item.has_name(sym::cfg) {
+ old_syntax = Some(false);
+
+ let mut names = Vec::new();
+ let mut values: FxHashSet<_> = Default::default();
+
+ let mut any_specified = false;
+ let mut values_specified = false;
+ let mut values_any_specified = false;
+
+ for arg in args {
+ if arg.is_word() && let Some(ident) = arg.ident() {
+ if values_specified {
+ error!("`cfg()` names cannot be after values");
+ }
+ names.push(ident);
+ } else if arg.has_name(sym::any) && let Some(args) = arg.meta_item_list() {
+ if any_specified {
+ error!("`any()` cannot be specified multiple times");
+ }
+ any_specified = true;
+ if !args.is_empty() {
+ error!("`any()` must be empty");
+ }
+ } else if arg.has_name(sym::values) && let Some(args) = arg.meta_item_list() {
+ if names.is_empty() {
+ error!("`values()` cannot be specified before the names");
+ } else if values_specified {
+ error!("`values()` cannot be specified multiple times");
+ }
+ values_specified = true;
+
+ for arg in args {
+ if let Some(LitKind::Str(s, _)) = arg.lit().map(|lit| &lit.kind) {
+ values.insert(Some(*s));
+ } else if arg.has_name(sym::any) && let Some(args) = arg.meta_item_list() {
+ if values_any_specified {
+ error!("`any()` in `values()` cannot be specified multiple times");
+ }
+ values_any_specified = true;
+ if !args.is_empty() {
+ error!("`any()` must be empty");
+ }
+ } else {
+ error!("`values()` arguments must be string literals or `any()`");
+ }
+ }
+ } else {
+ error!(
+ "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
+ );
+ }
+ }
+
+ if values.is_empty() && !values_any_specified && !any_specified {
+ values.insert(None);
+ } else if !values.is_empty() && values_any_specified {
+ error!(
+ "`values()` arguments cannot specify string literals and `any()` at the same time"
+ );
+ }
+
+ if any_specified {
+ if names.is_empty()
+ && values.is_empty()
+ && !values_specified
+ && !values_any_specified
+ {
+ check_cfg.exhaustive_names = false;
+ } else {
+ error!("`cfg(any())` can only be provided in isolation");
+ }
+ } else {
+ for name in names {
+ check_cfg
+ .expecteds
+ .entry(name.name)
+ .and_modify(|v| match v {
+ ExpectedValues::Some(v) if !values_any_specified => {
+ v.extend(values.clone())
+ }
+ ExpectedValues::Some(_) => *v = ExpectedValues::Any,
+ ExpectedValues::Any => {}
+ })
+ .or_insert_with(|| {
+ if values_any_specified {
+ ExpectedValues::Any
+ } else {
+ ExpectedValues::Some(values.clone())
+ }
+ });
}
}
+ } else {
+ expected_error();
}
+ }
- check_cfg
- })
+ check_cfg
}
/// The compiler configuration
@@ -244,9 +331,9 @@ pub struct Config {
/// Command line options
pub opts: config::Options,
- /// cfg! configuration in addition to the default ones
- pub crate_cfg: FxHashSet<(String, Option<String>)>,
- pub crate_check_cfg: CheckCfg,
+ /// Unparsed cfg! configuration in addition to the default ones.
+ pub crate_cfg: Vec<String>,
+ pub crate_check_cfg: Vec<String>,
pub input: Input,
pub output_dir: Option<PathBuf>,
@@ -260,8 +347,14 @@ pub struct Config {
/// This is a callback from the driver that is called when [`ParseSess`] is created.
pub parse_sess_created: Option<Box<dyn FnOnce(&mut ParseSess) + Send>>,
+ /// This is a callback to hash otherwise untracked state used by the caller, if the
+ /// hash changes between runs the incremental cache will be cleared.
+ ///
+ /// e.g. used by Clippy to hash its config file
+ pub hash_untracked_state: Option<Box<dyn FnOnce(&Session, &mut StableHasher) + Send>>,
+
/// This is a callback from the driver that is called when we're registering lints;
- /// it is called during plugin registration when we have the LintStore in a non-shared state.
+ /// it is called during lint loading when we have the LintStore in a non-shared state.
///
/// Note that if you find a Some here you probably want to call that function in the new
/// function being registered.
@@ -269,8 +362,6 @@ pub struct Config {
/// This is a callback from the driver that is called just after we have populated
/// the list of queries.
- ///
- /// The second parameter is local providers and the third parameter is external providers.
pub override_queries: Option<fn(&Session, &mut Providers)>,
/// This is a callback from the driver that is called to create a codegen backend.
@@ -280,6 +371,12 @@ pub struct Config {
/// Registry of diagnostics codes.
pub registry: Registry,
+ /// The inner atomic value is set to true when a feature marked as `internal` is
+ /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
+ /// internal features are wontfix, and they are usually the cause of the ICEs.
+ /// None signifies that this is not tracked.
+ pub using_internal_features: Arc<std::sync::atomic::AtomicBool>,
+
/// All commandline args used to invoke the compiler, with @file args fully expanded.
/// This will only be used within debug info, e.g. in the pdb file on windows
/// This is mainly useful for other tools that reads that debuginfo to figure out
@@ -301,35 +398,81 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|| {
crate::callbacks::setup_callbacks();
- let registry = &config.registry;
-
let handler = EarlyErrorHandler::new(config.opts.error_format);
+ let codegen_backend = if let Some(make_codegen_backend) = config.make_codegen_backend {
+ make_codegen_backend(&config.opts)
+ } else {
+ util::get_codegen_backend(
+ &handler,
+ &config.opts.maybe_sysroot,
+ config.opts.unstable_opts.codegen_backend.as_deref(),
+ )
+ };
+
let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
- let (mut sess, codegen_backend) = util::create_session(
+
+ let bundle = match rustc_errors::fluent_bundle(
+ config.opts.maybe_sysroot.clone(),
+ sysroot_candidates().to_vec(),
+ config.opts.unstable_opts.translate_lang.clone(),
+ config.opts.unstable_opts.translate_additional_ftl.as_deref(),
+ config.opts.unstable_opts.translate_directionality_markers,
+ ) {
+ Ok(bundle) => bundle,
+ Err(e) => {
+ handler.early_error(format!("failed to load fluent bundle: {e}"));
+ }
+ };
+
+ let mut locale_resources = Vec::from(config.locale_resources);
+ locale_resources.push(codegen_backend.locale_resource());
+
+ // target_override is documented to be called before init(), so this is okay
+ let target_override = codegen_backend.target_override(&config.opts);
+
+ let mut sess = rustc_session::build_session(
&handler,
config.opts,
- config.crate_cfg,
- config.crate_check_cfg,
- config.locale_resources,
- config.file_loader,
CompilerIO {
input: config.input,
output_dir: config.output_dir,
output_file: config.output_file,
temps_dir,
},
+ bundle,
+ config.registry.clone(),
+ locale_resources,
config.lint_caps,
- config.make_codegen_backend,
- registry.clone(),
+ config.file_loader,
+ target_override,
+ util::rustc_version_str().unwrap_or("unknown"),
config.ice_file,
+ config.using_internal_features,
config.expanded_args,
);
+ codegen_backend.init(&sess);
+
+ let cfg = parse_cfg(&handler, config.crate_cfg);
+ let mut cfg = config::build_configuration(&sess, cfg);
+ util::add_configuration(&mut cfg, &mut sess, &*codegen_backend);
+ sess.parse_sess.config = cfg;
+
+ let mut check_cfg = parse_check_cfg(&handler, config.crate_check_cfg);
+ check_cfg.fill_well_known(&sess.target);
+ sess.parse_sess.check_config = check_cfg;
+
if let Some(parse_sess_created) = config.parse_sess_created {
parse_sess_created(&mut sess.parse_sess);
}
+ if let Some(hash_untracked_state) = config.hash_untracked_state {
+ let mut hasher = StableHasher::new();
+ hash_untracked_state(&sess, &mut hasher);
+ sess.opts.untracked_state_hash = hasher.finish()
+ }
+
let compiler = Compiler {
sess: Lrc::new(sess),
codegen_backend: Lrc::from(codegen_backend),
@@ -340,7 +483,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
let r = {
let _sess_abort_error = defer(|| {
- compiler.sess.finish_diagnostics(registry);
+ compiler.sess.finish_diagnostics(&config.registry);
});
f(&compiler)
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 76131c1ad..ffa2667a3 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -3,6 +3,7 @@
#![feature(internal_output_capture)]
#![feature(thread_spawn_unchecked)]
#![feature(lazy_cell)]
+#![feature(let_chains)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 0e8f93cef..7d14d088e 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -23,11 +23,10 @@ use rustc_middle::util::Providers;
use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{self, abi_test, hir_stats, layout_test};
-use rustc_plugin_impl as plugin;
use rustc_resolve::Resolver;
use rustc_session::code_stats::VTableSizeInfo;
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
-use rustc_session::cstore::{MetadataLoader, Untracked};
+use rustc_session::cstore::Untracked;
use rustc_session::output::filename_for_input;
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
@@ -75,25 +74,12 @@ fn count_nodes(krate: &ast::Crate) -> usize {
pub(crate) fn create_lint_store(
sess: &Session,
- metadata_loader: &dyn MetadataLoader,
register_lints: Option<impl Fn(&Session, &mut LintStore)>,
- pre_configured_attrs: &[ast::Attribute],
) -> LintStore {
let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
if let Some(register_lints) = register_lints {
register_lints(sess, &mut lint_store);
}
-
- let registrars = sess.time("plugin_loading", || {
- plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs)
- });
- sess.time("plugin_registration", || {
- let mut registry = plugin::Registry { lint_store: &mut lint_store };
- for registrar in registrars {
- registrar(&mut registry);
- }
- });
-
lint_store
}
@@ -392,34 +378,16 @@ fn generated_output_paths(
out_filenames
}
-// Runs `f` on every output file path and returns the first non-None result, or None if `f`
-// returns None for every file path.
-fn check_output<F, T>(output_paths: &[PathBuf], f: F) -> Option<T>
-where
- F: Fn(&PathBuf) -> Option<T>,
-{
- for output_path in output_paths {
- if let Some(result) = f(output_path) {
- return Some(result);
- }
- }
- None
-}
-
fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
let input_path = try_canonicalize(input_path).ok();
if input_path.is_none() {
return false;
}
- let check = |output_path: &PathBuf| {
- if try_canonicalize(output_path).ok() == input_path { Some(()) } else { None }
- };
- check_output(output_paths, check).is_some()
+ output_paths.iter().any(|output_path| try_canonicalize(output_path).ok() == input_path)
}
-fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
- let check = |output_path: &PathBuf| output_path.is_dir().then(|| output_path.clone());
- check_output(output_paths, check)
+fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<&PathBuf> {
+ output_paths.iter().find(|output_path| output_path.is_dir())
}
fn escape_dep_filename(filename: &str) -> String {
@@ -602,9 +570,7 @@ fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> {
let (_, krate) = &*tcx.resolver_for_lowering(()).borrow();
let crate_name = tcx.crate_name(LOCAL_CRATE);
- // FIXME: rustdoc passes &[] instead of &krate.attrs here
let outputs = util::build_output_filenames(&krate.attrs, sess);
-
let output_paths =
generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name);
@@ -775,12 +741,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
rustc_hir_analysis::check_crate(tcx)?;
sess.time("MIR_borrow_checking", || {
- tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
+ tcx.hir().par_body_owners(|def_id| {
+ // Run THIR unsafety check because it's responsible for stealing
+ // and deallocating THIR when enabled.
+ tcx.ensure().thir_check_unsafety(def_id);
+ tcx.ensure().mir_borrowck(def_id)
+ });
});
sess.time("MIR_effect_checking", || {
for def_id in tcx.hir().body_owners() {
- tcx.ensure().thir_check_unsafety(def_id);
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
}
@@ -799,9 +769,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
});
tcx.hir().par_body_owners(|def_id| {
- if let rustc_hir::def::DefKind::Generator = tcx.def_kind(def_id) {
- tcx.ensure().mir_generator_witnesses(def_id);
- tcx.ensure().check_generator_obligations(def_id);
+ if let rustc_hir::def::DefKind::Coroutine = tcx.def_kind(def_id) {
+ tcx.ensure().mir_coroutine_witnesses(def_id);
+ tcx.ensure().check_coroutine_obligations(def_id);
}
});
@@ -852,6 +822,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
// This check has to be run after all lints are done processing. We don't
// define a lint filter, as all lint checks should have finished at this point.
sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None));
+
+ // This query is only invoked normally if a diagnostic is emitted that needs any
+ // diagnostic item. If the crate compiles without checking any diagnostic items,
+ // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
+ let _ = tcx.all_diagnostic_items(());
});
if sess.opts.unstable_opts.print_vtable_sizes {
@@ -873,16 +848,18 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr));
- // A slightly edited version of the code in `rustc_trait_selection::traits::vtable::vtable_entries`,
- // that works without self type and just counts number of entries.
+ // A slightly edited version of the code in
+ // `rustc_trait_selection::traits::vtable::vtable_entries`, that works without self
+ // type and just counts number of entries.
//
- // Note that this is technically wrong, for traits which have associated types in supertraits:
+ // Note that this is technically wrong, for traits which have associated types in
+ // supertraits:
//
// trait A: AsRef<Self::T> + AsRef<()> { type T; }
//
- // Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>` and
- // `AsRef<()>` are the same trait, thus we assume that those are different, and potentially
- // over-estimate how many vtable entries there are.
+ // Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>`
+ // and `AsRef<()>` are the same trait, thus we assume that those are different, and
+ // potentially over-estimate how many vtable entries there are.
//
// Similarly this is wrong for traits that have methods with possibly-impossible bounds.
// For example:
@@ -909,10 +886,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
let own_existential_entries =
tcx.own_existential_vtable_entries(trait_ref.def_id());
- // The original code here ignores the method if its predicates are impossible.
- // We can't really do that as, for example, all not trivial bounds on generic
- // parameters are impossible (since we don't know the parameters...),
- // see the comment above.
+ // The original code here ignores the method if its predicates are
+ // impossible. We can't really do that as, for example, all not trivial
+ // bounds on generic parameters are impossible (since we don't know the
+ // parameters...), see the comment above.
entries_ignoring_upcasting += own_existential_entries.len();
if emit_vptr {
@@ -957,10 +934,9 @@ pub fn start_codegen<'tcx>(
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
});
- // Don't run these test assertions when not doing codegen. Compiletest tries to build
+ // Don't run this test assertions when not doing codegen. Compiletest tries to build
// build-fail tests in check mode first and expects it to not give an error in that case.
if tcx.sess.opts.output_types.should_codegen() {
- rustc_incremental::assert_module_sources::assert_module_sources(tcx);
rustc_symbol_mangling::test::report_symbol_names(tcx);
}
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index fe253febf..3a5f788e8 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -148,12 +148,8 @@ impl<'tcx> Queries<'tcx> {
);
let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?;
- let lint_store = Lrc::new(passes::create_lint_store(
- sess,
- &*self.codegen_backend().metadata_loader(),
- self.compiler.register_lints.as_deref(),
- &pre_configured_attrs,
- ));
+ let lint_store =
+ Lrc::new(passes::create_lint_store(sess, self.compiler.register_lints.as_deref()));
let cstore = FreezeLock::new(Box::new(CStore::new(
self.codegen_backend().metadata_loader(),
stable_crate_id,
@@ -181,9 +177,11 @@ impl<'tcx> Queries<'tcx> {
feed.crate_name(crate_name);
let feed = tcx.feed_unit_query();
- feed.features_query(
- tcx.arena.alloc(rustc_expand::config::features(sess, &pre_configured_attrs)),
- );
+ feed.features_query(tcx.arena.alloc(rustc_expand::config::features(
+ sess,
+ &pre_configured_attrs,
+ crate_name,
+ )));
feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
});
Ok(qcx)
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 2510ce714..d30816955 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -1,54 +1,33 @@
#![allow(rustc::bad_opt_access)]
-use crate::interface::parse_cfgspecs;
-
-use rustc_data_structures::fx::FxHashSet;
+use crate::interface::parse_cfg;
use rustc_data_structures::profiling::TimePassesFormat;
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
-use rustc_session::config::rustc_optgroups;
-use rustc_session::config::DebugInfo;
-use rustc_session::config::Input;
-use rustc_session::config::InstrumentXRay;
-use rustc_session::config::LinkSelfContained;
-use rustc_session::config::TraitSolver;
-use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
use rustc_session::config::{
- BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
- ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
+ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
+ DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
+ InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained,
+ LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, OomStrategy, Options, OutFileName,
+ OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip,
+ SwitchWithOptPath, SymbolManglingVersion, TraitSolver, WasiExecModel,
};
-use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
-use rustc_session::config::{DumpMonoStatsFormat, MirSpanview};
-use rustc_session::config::{ErrorOutputType, ExternLocation, LocationDetail, Options, Strip};
-use rustc_session::config::{InstrumentCoverage, Passes};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use rustc_session::{build_session, getopts, Session};
-use rustc_session::{CompilerIO, EarlyErrorHandler};
+use rustc_session::{build_session, getopts, CompilerIO, EarlyErrorHandler, Session};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
-use rustc_span::FileName;
-use rustc_span::SourceFileHashAlgorithm;
+use rustc_span::{FileName, SourceFileHashAlgorithm};
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
-
use std::collections::{BTreeMap, BTreeSet};
use std::num::NonZeroUsize;
use std::path::{Path, PathBuf};
+use std::sync::Arc;
-type CfgSpecs = FxHashSet<(String, Option<String>)>;
-
-fn build_session_options_and_crate_config(
- handler: &mut EarlyErrorHandler,
- matches: getopts::Matches,
-) -> (Options, CfgSpecs) {
- let sessopts = build_session_options(handler, &matches);
- let cfg = parse_cfgspecs(handler, matches.opt_strs("cfg"));
- (sessopts, cfg)
-}
-
-fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, CfgSpecs) {
+fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, Cfg) {
let registry = registry::Registry::new(&[]);
- let (sessopts, cfg) = build_session_options_and_crate_config(handler, matches);
+ let sessopts = build_session_options(handler, &matches);
+ let cfg = parse_cfg(handler, matches.opt_strs("cfg"));
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let io = CompilerIO {
input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
@@ -68,6 +47,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
None,
"",
None,
+ Arc::default(),
Default::default(),
);
(sess, cfg)
@@ -138,7 +118,7 @@ fn test_switch_implies_cfg_test() {
let matches = optgroups().parse(&["--test".to_string()]).unwrap();
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, cfg) = mk_session(&mut handler, matches);
- let cfg = build_configuration(&sess, to_crate_config(cfg));
+ let cfg = build_configuration(&sess, cfg);
assert!(cfg.contains(&(sym::test, None)));
});
}
@@ -150,7 +130,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, cfg) = mk_session(&mut handler, matches);
- let cfg = build_configuration(&sess, to_crate_config(cfg));
+ let cfg = build_configuration(&sess, cfg);
let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
@@ -611,7 +591,7 @@ fn test_codegen_options_tracking_hash() {
tracked!(force_frame_pointers, Some(false));
tracked!(force_unwind_tables, Some(true));
tracked!(inline_threshold, Some(0xf007ba11));
- tracked!(instrument_coverage, Some(InstrumentCoverage::All));
+ tracked!(instrument_coverage, InstrumentCoverage::All);
tracked!(link_dead_code, Some(true));
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
@@ -681,7 +661,6 @@ fn test_unstable_options_tracking_hash() {
// tidy-alphabetical-start
untracked!(assert_incr_state, Some(String::from("loaded")));
untracked!(deduplicate_diagnostics, false);
- untracked!(dep_tasks, true);
untracked!(dont_buffer_diagnostics, true);
untracked!(dump_dep_graph, true);
untracked!(dump_mir, Some(String::from("abc")));
@@ -769,6 +748,7 @@ fn test_unstable_options_tracking_hash() {
);
tracked!(codegen_backend, Some("abc".to_string()));
tracked!(crate_attr, vec!["abc".to_string()]);
+ tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
tracked!(debug_info_for_profiling, true);
tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true);
@@ -787,7 +767,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(inline_mir, Some(true));
tracked!(inline_mir_hint_threshold, Some(123));
tracked!(inline_mir_threshold, Some(123));
- tracked!(instrument_coverage, Some(InstrumentCoverage::All));
tracked!(instrument_mcount, true);
tracked!(instrument_xray, Some(InstrumentXRay::default()));
tracked!(link_directives, false);
@@ -814,7 +793,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(panic_abort_tests, true);
tracked!(panic_in_drop, PanicStrategy::Abort);
tracked!(plt, Some(true));
- tracked!(polonius, true);
+ tracked!(polonius, Polonius::Legacy);
tracked!(precise_enum_drop_elaboration, false);
tracked!(print_fuel, Some("abc".to_string()));
tracked!(profile, true);
@@ -838,7 +817,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(split_lto_unit, Some(true));
tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
tracked!(stack_protector, StackProtector::All);
- tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
tracked!(teach, true);
tracked!(thinlto, Some(true));
tracked!(thir_unsafeck, true);
@@ -877,6 +855,6 @@ fn test_edition_parsing() {
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let matches = optgroups().parse(&["--edition=2018".to_string()]).unwrap();
- let (sessopts, _) = build_session_options_and_crate_config(&mut handler, matches);
+ let sessopts = build_session_options(&mut handler, &matches);
assert!(sessopts.edition == Edition::Edition2018)
}
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0634e44c5..22d127934 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -3,24 +3,18 @@ use info;
use libloading::Library;
use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)]
use rustc_data_structures::sync;
-use rustc_errors::registry::Registry;
use rustc_parse::validate_attr;
use rustc_session as session;
-use rustc_session::config::CheckCfg;
-use rustc_session::config::{self, CrateType};
-use rustc_session::config::{OutFileName, OutputFilenames, OutputTypes};
+use rustc_session::config::{self, Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes};
use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
-use rustc_session::parse::CrateConfig;
use rustc_session::{filesearch, output, Session};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
-use rustc_span::source_map::FileLoader;
use rustc_span::symbol::{sym, Symbol};
-use session::{CompilerIO, EarlyErrorHandler};
+use session::EarlyErrorHandler;
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::mem;
@@ -37,11 +31,7 @@ pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
///
/// This is performed by checking whether a set of permitted features
/// is available on the target machine, by querying the codegen backend.
-pub fn add_configuration(
- cfg: &mut CrateConfig,
- sess: &mut Session,
- codegen_backend: &dyn CodegenBackend,
-) {
+pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dyn CodegenBackend) {
let tf = sym::target_feature;
let unstable_target_features = codegen_backend.target_features(sess, true);
@@ -57,80 +47,6 @@ pub fn add_configuration(
}
}
-pub fn create_session(
- handler: &EarlyErrorHandler,
- sopts: config::Options,
- cfg: FxHashSet<(String, Option<String>)>,
- check_cfg: CheckCfg,
- locale_resources: &'static [&'static str],
- file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
- io: CompilerIO,
- lint_caps: FxHashMap<lint::LintId, lint::Level>,
- make_codegen_backend: Option<
- Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
- >,
- descriptions: Registry,
- ice_file: Option<PathBuf>,
- expanded_args: Vec<String>,
-) -> (Session, Box<dyn CodegenBackend>) {
- let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
- make_codegen_backend(&sopts)
- } else {
- get_codegen_backend(
- handler,
- &sopts.maybe_sysroot,
- sopts.unstable_opts.codegen_backend.as_deref(),
- )
- };
-
- // target_override is documented to be called before init(), so this is okay
- let target_override = codegen_backend.target_override(&sopts);
-
- let bundle = match rustc_errors::fluent_bundle(
- sopts.maybe_sysroot.clone(),
- sysroot_candidates().to_vec(),
- sopts.unstable_opts.translate_lang.clone(),
- sopts.unstable_opts.translate_additional_ftl.as_deref(),
- sopts.unstable_opts.translate_directionality_markers,
- ) {
- Ok(bundle) => bundle,
- Err(e) => {
- handler.early_error(format!("failed to load fluent bundle: {e}"));
- }
- };
-
- let mut locale_resources = Vec::from(locale_resources);
- locale_resources.push(codegen_backend.locale_resource());
-
- let mut sess = session::build_session(
- handler,
- sopts,
- io,
- bundle,
- descriptions,
- locale_resources,
- lint_caps,
- file_loader,
- target_override,
- rustc_version_str().unwrap_or("unknown"),
- ice_file,
- expanded_args,
- );
-
- codegen_backend.init(&sess);
-
- let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
- add_configuration(&mut cfg, &mut sess, &*codegen_backend);
-
- let mut check_cfg = config::to_crate_check_config(check_cfg);
- check_cfg.fill_well_known(&sess.target);
-
- sess.parse_sess.config = cfg;
- sess.parse_sess.check_config = check_cfg;
-
- (sess, codegen_backend)
-}
-
const STACK_SIZE: usize = 8 * 1024 * 1024;
fn get_stack_size() -> Option<usize> {
@@ -485,21 +401,6 @@ fn categorize_crate_type(s: Symbol) -> Option<CrateType> {
}
pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<CrateType> {
- // Unconditionally collect crate types from attributes to make them used
- let attr_types: Vec<CrateType> = attrs
- .iter()
- .filter_map(|a| {
- if a.has_name(sym::crate_type) {
- match a.value_str() {
- Some(s) => categorize_crate_type(s),
- _ => None,
- }
- } else {
- None
- }
- })
- .collect();
-
// If we're generating a test executable, then ignore all other output
// styles at all other locations
if session.opts.test {
@@ -513,6 +414,13 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
#[allow(rustc::bad_opt_access)]
let mut base = session.opts.crate_types.clone();
if base.is_empty() {
+ let attr_types = attrs.iter().filter_map(|a| {
+ if a.has_name(sym::crate_type) && let Some(s) = a.value_str() {
+ categorize_crate_type(s)
+ } else {
+ None
+ }
+ });
base.extend(attr_types);
if base.is_empty() {
base.push(output::default_output_for_target(session));