summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_interface
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:19 +0000
commita0b8f38ab54ac451646aa00cd5e91b6c76f22a84 (patch)
treefc451898ccaf445814e26b46664d78702178101d /compiler/rustc_interface
parentAdding debian version 1.71.1+dfsg1-2. (diff)
downloadrustc-a0b8f38ab54ac451646aa00cd5e91b6c76f22a84.tar.xz
rustc-a0b8f38ab54ac451646aa00cd5e91b6c76f22a84.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_interface')
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/messages.ftl1
-rw-r--r--compiler/rustc_interface/src/errors.rs4
-rw-r--r--compiler/rustc_interface/src/interface.rs49
-rw-r--r--compiler/rustc_interface/src/passes.rs166
-rw-r--r--compiler/rustc_interface/src/queries.rs44
-rw-r--r--compiler/rustc_interface/src/tests.rs122
-rw-r--r--compiler/rustc_interface/src/util.rs76
8 files changed, 328 insertions, 135 deletions
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 2c7438ed9..7826d42dc 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
[lib]
[dependencies]
+atty = "0.2.13"
libloading = "0.7.1"
tracing = "0.1"
rustc-rayon-core = { version = "0.5.0", optional = true }
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index be1a75f02..bd9fad8b0 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -33,6 +33,7 @@ interface_mixed_proc_macro_crate =
interface_multiple_output_types_adaption =
due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
+interface_multiple_output_types_to_stdout = can't use option `-o` or `--emit` to write multiple output types to stdout
interface_out_dir_error =
failed to find or create the directory specified by `--out-dir`
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index 0eedee250..a9ab2720d 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -108,3 +108,7 @@ pub struct IgnoringExtraFilename;
#[derive(Diagnostic)]
#[diag(interface_ignoring_out_dir)]
pub struct IgnoringOutDir;
+
+#[derive(Diagnostic)]
+#[diag(interface_multiple_output_types_to_stdout)]
+pub struct MultipleOutputTypesToStdout;
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 39d568979..953c2e4b8 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -14,12 +14,11 @@ 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, ErrorOutputType, Input, OutputFilenames};
-use rustc_session::config::{CheckCfg, ExpectedValues};
-use rustc_session::lint;
+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::{early_error, CompilerIO};
+use rustc_session::{lint, EarlyErrorHandler};
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
use std::path::PathBuf;
@@ -36,7 +35,7 @@ pub type Result<T> = result::Result<T, ErrorGuaranteed>;
/// Created by passing [`Config`] to [`run_compiler`].
pub struct Compiler {
pub(crate) sess: Lrc<Session>,
- codegen_backend: Lrc<Box<dyn CodegenBackend>>,
+ codegen_backend: Lrc<dyn CodegenBackend>,
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
pub(crate) override_queries: Option<fn(&Session, &mut Providers, &mut ExternProviders)>,
}
@@ -45,7 +44,7 @@ impl Compiler {
pub fn session(&self) -> &Lrc<Session> {
&self.sess
}
- pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
+ pub fn codegen_backend(&self) -> &Lrc<dyn CodegenBackend> {
&self.codegen_backend
}
pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
@@ -66,7 +65,10 @@ pub fn set_thread_safe_mode(sopts: &config::UnstableOptions) {
}
/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
-pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
+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()
@@ -78,10 +80,10 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
macro_rules! error {
($reason: expr) => {
- early_error(
- ErrorOutputType::default(),
- format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s),
- );
+ handler.early_error(format!(
+ concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
+ s
+ ));
};
}
@@ -125,7 +127,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
}
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
-pub fn parse_check_cfg(specs: Vec<String>) -> 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();
@@ -137,10 +139,10 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
macro_rules! error {
($reason: expr) => {
- early_error(
- ErrorOutputType::default(),
- format!(concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), s),
- )
+ handler.early_error(format!(
+ concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+ s
+ ))
};
}
@@ -252,7 +254,7 @@ pub struct Config {
pub input: Input,
pub output_dir: Option<PathBuf>,
- pub output_file: Option<PathBuf>,
+ pub output_file: Option<OutFileName>,
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
pub locale_resources: &'static [&'static str],
@@ -294,8 +296,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
let registry = &config.registry;
+ let handler = EarlyErrorHandler::new(config.opts.error_format);
+
let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let (mut sess, codegen_backend) = util::create_session(
+ &handler,
config.opts,
config.crate_cfg,
config.crate_check_cfg,
@@ -318,7 +323,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
let compiler = Compiler {
sess: Lrc::new(sess),
- codegen_backend: Lrc::new(codegen_backend),
+ codegen_backend: Lrc::from(codegen_backend),
register_lints: config.register_lints,
override_queries: config.override_queries,
};
@@ -333,6 +338,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
};
let prof = compiler.sess.prof.clone();
+
prof.generic_activity("drop_compiler").run(move || drop(compiler));
r
})
@@ -348,7 +354,12 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
// state if it was responsible for triggering the panic.
let i = ty::tls::with_context_opt(|icx| {
if let Some(icx) = icx {
- print_query_stack(QueryCtxt::new(icx.tcx), icx.query, handler, num_frames)
+ ty::print::with_no_queries!(print_query_stack(
+ QueryCtxt::new(icx.tcx),
+ icx.query,
+ handler,
+ num_frames
+ ))
} else {
0
}
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 42d8d2280..6b3facd04 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -24,7 +24,8 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_a
use rustc_passes::{self, hir_stats, layout_test};
use rustc_plugin_impl as plugin;
use rustc_resolve::Resolver;
-use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
+use rustc_session::code_stats::VTableSizeInfo;
+use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
use rustc_session::cstore::{MetadataLoader, Untracked};
use rustc_session::output::filename_for_input;
use rustc_session::search_paths::PathKind;
@@ -373,19 +374,23 @@ fn generated_output_paths(
) -> Vec<PathBuf> {
let mut out_filenames = Vec::new();
for output_type in sess.opts.output_types.keys() {
- let file = outputs.path(*output_type);
+ let out_filename = outputs.path(*output_type);
+ let file = out_filename.as_path().to_path_buf();
match *output_type {
// If the filename has been overridden using `-o`, it will not be modified
// by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
OutputType::Exe if !exact_name => {
for crate_type in sess.crate_types().iter() {
let p = filename_for_input(sess, *crate_type, crate_name, outputs);
- out_filenames.push(p);
+ out_filenames.push(p.as_path().to_path_buf());
}
}
OutputType::DepInfo if sess.opts.unstable_opts.dep_info_omit_d_target => {
// Don't add the dep-info output when omitting it from dep-info targets
}
+ OutputType::DepInfo if out_filename.is_stdout() => {
+ // Don't add the dep-info output when it goes to stdout
+ }
_ => {
out_filenames.push(file);
}
@@ -452,7 +457,8 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
return;
}
- let deps_filename = outputs.path(OutputType::DepInfo);
+ let deps_output = outputs.path(OutputType::DepInfo);
+ let deps_filename = deps_output.as_path();
let result: io::Result<()> = try {
// Build a list of files used to compile the output and
@@ -515,33 +521,47 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
}
}
- let mut file = BufWriter::new(fs::File::create(&deps_filename)?);
- for path in out_filenames {
- writeln!(file, "{}: {}\n", path.display(), files.join(" "))?;
- }
+ let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> {
+ for path in out_filenames {
+ writeln!(file, "{}: {}\n", path.display(), files.join(" "))?;
+ }
- // Emit a fake target for each input file to the compilation. This
- // prevents `make` from spitting out an error if a file is later
- // deleted. For more info see #28735
- for path in files {
- writeln!(file, "{path}:")?;
- }
+ // Emit a fake target for each input file to the compilation. This
+ // prevents `make` from spitting out an error if a file is later
+ // deleted. For more info see #28735
+ for path in files {
+ writeln!(file, "{path}:")?;
+ }
- // Emit special comments with information about accessed environment variables.
- let env_depinfo = sess.parse_sess.env_depinfo.borrow();
- if !env_depinfo.is_empty() {
- let mut envs: Vec<_> = env_depinfo
- .iter()
- .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
- .collect();
- envs.sort_unstable();
- writeln!(file)?;
- for (k, v) in envs {
- write!(file, "# env-dep:{k}")?;
- if let Some(v) = v {
- write!(file, "={v}")?;
- }
+ // Emit special comments with information about accessed environment variables.
+ let env_depinfo = sess.parse_sess.env_depinfo.borrow();
+ if !env_depinfo.is_empty() {
+ let mut envs: Vec<_> = env_depinfo
+ .iter()
+ .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
+ .collect();
+ envs.sort_unstable();
writeln!(file)?;
+ for (k, v) in envs {
+ write!(file, "# env-dep:{k}")?;
+ if let Some(v) = v {
+ write!(file, "={v}")?;
+ }
+ writeln!(file)?;
+ }
+ }
+
+ Ok(())
+ };
+
+ match deps_output {
+ OutFileName::Stdout => {
+ let mut file = BufWriter::new(io::stdout());
+ write_deps_to_file(&mut file)?;
+ }
+ OutFileName::Real(ref path) => {
+ let mut file = BufWriter::new(fs::File::create(path)?);
+ write_deps_to_file(&mut file)?;
}
}
};
@@ -720,8 +740,8 @@ pub fn create_global_ctxt<'tcx>(
})
}
-/// Runs the resolution, type-checking, region checking and other
-/// miscellaneous analysis passes on the crate.
+/// Runs the type-checking, region checking and other miscellaneous analysis
+/// passes on the crate.
fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
rustc_passes::hir_id_validator::check_crate(tcx);
@@ -847,6 +867,92 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
sess.time("check_lint_expectations", || tcx.check_expectations(None));
});
+ if sess.opts.unstable_opts.print_vtable_sizes {
+ let traits = tcx.traits(LOCAL_CRATE);
+
+ for &tr in traits {
+ if !tcx.check_is_object_safe(tr) {
+ continue;
+ }
+
+ let name = ty::print::with_no_trimmed_paths!(tcx.def_path_str(tr));
+
+ let mut first_dsa = true;
+
+ // Number of vtable entries, if we didn't have upcasting
+ let mut entries_ignoring_upcasting = 0;
+ // Number of vtable entries needed solely for upcasting
+ let mut entries_for_upcasting = 0;
+
+ 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.
+ //
+ // 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.
+ //
+ // Similarly this is wrong for traits that have methods with possibly-impossible bounds.
+ // For example:
+ //
+ // trait B<T> { fn f(&self) where T: Copy; }
+ //
+ // Here `dyn B<u8>` will have 4 entries, while `dyn B<String>` will only have 3.
+ // However, since we don't know `T`, we can't know if `T: Copy` holds or not,
+ // thus we lean on the bigger side and say it has 4 entries.
+ traits::vtable::prepare_vtable_segments(tcx, trait_ref, |segment| {
+ match segment {
+ traits::vtable::VtblSegment::MetadataDSA => {
+ // If this is the first dsa, it would be included either way,
+ // otherwise it's needed for upcasting
+ if std::mem::take(&mut first_dsa) {
+ entries_ignoring_upcasting += 3;
+ } else {
+ entries_for_upcasting += 3;
+ }
+ }
+
+ traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ // Lookup the shape of vtable for the trait.
+ 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.
+ entries_ignoring_upcasting += own_existential_entries.len();
+
+ if emit_vptr {
+ entries_for_upcasting += 1;
+ }
+ }
+ }
+
+ std::ops::ControlFlow::Continue::<std::convert::Infallible>(())
+ });
+
+ sess.code_stats.record_vtable_size(
+ tr,
+ &name,
+ VTableSizeInfo {
+ trait_name: name.clone(),
+ entries: entries_ignoring_upcasting + entries_for_upcasting,
+ entries_ignoring_upcasting,
+ entries_for_upcasting,
+ upcasting_cost_percent: entries_for_upcasting as f64
+ / entries_ignoring_upcasting as f64
+ * 100.,
+ },
+ )
+ }
+ }
+
Ok(())
}
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index c441a8ffd..8c4cdc669 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -5,6 +5,7 @@ use crate::passes;
use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
+use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceCell, RwLock, WorkerLocal};
@@ -92,7 +93,6 @@ pub struct Queries<'tcx> {
dep_graph: Query<DepGraph>,
// This just points to what's in `gcx_cell`.
gcx: Query<&'tcx GlobalCtxt<'tcx>>,
- ongoing_codegen: Query<Box<dyn Any>>,
}
impl<'tcx> Queries<'tcx> {
@@ -109,14 +109,13 @@ impl<'tcx> Queries<'tcx> {
register_plugins: Default::default(),
dep_graph: Default::default(),
gcx: Default::default(),
- ongoing_codegen: Default::default(),
}
}
fn session(&self) -> &Lrc<Session> {
&self.compiler.sess
}
- fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
+ fn codegen_backend(&self) -> &Lrc<dyn CodegenBackend> {
self.compiler.codegen_backend()
}
@@ -193,9 +192,15 @@ impl<'tcx> Queries<'tcx> {
let future_opt = self.dep_graph_future()?.steal();
let dep_graph = future_opt
.and_then(|future| {
- let (prev_graph, prev_work_products) =
+ let (prev_graph, mut prev_work_products) =
sess.time("blocked_on_dep_graph_loading", || future.open().open(sess));
-
+ // Convert from UnordMap to FxIndexMap by sorting
+ let prev_work_product_ids =
+ prev_work_products.items().map(|x| *x.0).into_sorted_stable_ord();
+ let prev_work_products = prev_work_product_ids
+ .into_iter()
+ .map(|x| (x, prev_work_products.remove(&x).unwrap()))
+ .collect::<FxIndexMap<_, _>>();
rustc_incremental::build_dep_graph(sess, prev_graph, prev_work_products)
})
.unwrap_or_else(DepGraph::new_disabled);
@@ -242,23 +247,19 @@ impl<'tcx> Queries<'tcx> {
})
}
- pub fn ongoing_codegen(&'tcx self) -> Result<QueryResult<'_, Box<dyn Any>>> {
- self.ongoing_codegen.compute(|| {
- self.global_ctxt()?.enter(|tcx| {
- tcx.analysis(()).ok();
-
- // Don't do code generation if there were any errors
- self.session().compile_status()?;
+ pub fn ongoing_codegen(&'tcx self) -> Result<Box<dyn Any>> {
+ self.global_ctxt()?.enter(|tcx| {
+ // Don't do code generation if there were any errors
+ self.session().compile_status()?;
- // If we have any delayed bugs, for example because we created TyKind::Error earlier,
- // it's likely that codegen will only cause more ICEs, obscuring the original problem
- self.session().diagnostic().flush_delayed();
+ // If we have any delayed bugs, for example because we created TyKind::Error earlier,
+ // it's likely that codegen will only cause more ICEs, obscuring the original problem
+ self.session().diagnostic().flush_delayed();
- // Hook for UI tests.
- Self::check_for_rustc_errors_attr(tcx);
+ // Hook for UI tests.
+ Self::check_for_rustc_errors_attr(tcx);
- Ok(passes::start_codegen(&***self.codegen_backend(), tcx))
- })
+ Ok(passes::start_codegen(&**self.codegen_backend(), tcx))
})
}
@@ -296,7 +297,7 @@ impl<'tcx> Queries<'tcx> {
}
}
- pub fn linker(&'tcx self) -> Result<Linker> {
+ pub fn linker(&'tcx self, ongoing_codegen: Box<dyn Any>) -> Result<Linker> {
let sess = self.session().clone();
let codegen_backend = self.codegen_backend().clone();
@@ -307,7 +308,6 @@ impl<'tcx> Queries<'tcx> {
tcx.dep_graph.clone(),
)
});
- let ongoing_codegen = self.ongoing_codegen()?.steal();
Ok(Linker {
sess,
@@ -324,7 +324,7 @@ impl<'tcx> Queries<'tcx> {
pub struct Linker {
// compilation inputs
sess: Lrc<Session>,
- codegen_backend: Lrc<Box<dyn CodegenBackend>>,
+ codegen_backend: Lrc<dyn CodegenBackend>,
// compilation outputs
dep_graph: DepGraph,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 28e719a40..09141afd1 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -8,10 +8,11 @@ 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, OutputType, OutputTypes, PAuthKey, PacRet,
+ BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
};
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
@@ -21,8 +22,8 @@ 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::CompilerIO;
use rustc_session::{build_session, getopts, Session};
+use rustc_session::{CompilerIO, EarlyErrorHandler};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
use rustc_span::FileName;
@@ -36,15 +37,18 @@ use std::path::{Path, PathBuf};
type CfgSpecs = FxHashSet<(String, Option<String>)>;
-fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options, CfgSpecs) {
- let sessopts = build_session_options(&matches);
- let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
+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(matches: getopts::Matches) -> (Session, CfgSpecs) {
+fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, CfgSpecs) {
let registry = registry::Registry::new(&[]);
- let (sessopts, cfg) = build_session_options_and_crate_config(matches);
+ let (sessopts, cfg) = build_session_options_and_crate_config(handler, matches);
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() },
@@ -52,8 +56,18 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
output_file: None,
temps_dir,
};
- let sess =
- build_session(sessopts, io, None, registry, vec![], Default::default(), None, None, "");
+ let sess = build_session(
+ handler,
+ sessopts,
+ io,
+ None,
+ registry,
+ vec![],
+ Default::default(),
+ None,
+ None,
+ "",
+ );
(sess, cfg)
}
@@ -120,7 +134,8 @@ fn assert_non_crate_hash_different(x: &Options, y: &Options) {
fn test_switch_implies_cfg_test() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["--test".to_string()]).unwrap();
- let (sess, cfg) = mk_session(matches);
+ let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+ let (sess, cfg) = mk_session(&mut handler, matches);
let cfg = build_configuration(&sess, to_crate_config(cfg));
assert!(cfg.contains(&(sym::test, None)));
});
@@ -131,7 +146,8 @@ fn test_switch_implies_cfg_test() {
fn test_switch_implies_cfg_test_unless_cfg_test() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
- let (sess, cfg) = mk_session(matches);
+ 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 mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
assert!(test_items.next().is_some());
@@ -143,20 +159,23 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
fn test_can_print_warnings() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
- let (sess, _) = mk_session(matches);
+ let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+ let (sess, _) = mk_session(&mut handler, matches);
assert!(!sess.diagnostic().can_emit_warnings());
});
rustc_span::create_default_session_globals_then(|| {
let matches =
optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
- let (sess, _) = mk_session(matches);
+ let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+ let (sess, _) = mk_session(&mut handler, matches);
assert!(sess.diagnostic().can_emit_warnings());
});
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
- let (sess, _) = mk_session(matches);
+ let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+ let (sess, _) = mk_session(&mut handler, matches);
assert!(sess.diagnostic().can_emit_warnings());
});
}
@@ -167,8 +186,14 @@ fn test_output_types_tracking_hash_different_paths() {
let mut v2 = Options::default();
let mut v3 = Options::default();
- v1.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
- v2.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
+ v1.output_types = OutputTypes::new(&[(
+ OutputType::Exe,
+ Some(OutFileName::Real(PathBuf::from("./some/thing"))),
+ )]);
+ v2.output_types = OutputTypes::new(&[(
+ OutputType::Exe,
+ Some(OutFileName::Real(PathBuf::from("/some/thing"))),
+ )]);
v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
assert_non_crate_hash_different(&v1, &v2);
@@ -182,13 +207,13 @@ fn test_output_types_tracking_hash_different_construction_order() {
let mut v2 = Options::default();
v1.output_types = OutputTypes::new(&[
- (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
- (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
+ (OutputType::Exe, Some(OutFileName::Real(PathBuf::from("./some/thing")))),
+ (OutputType::Bitcode, Some(OutFileName::Real(PathBuf::from("./some/thing.bc")))),
]);
v2.output_types = OutputTypes::new(&[
- (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
- (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
+ (OutputType::Bitcode, Some(OutFileName::Real(PathBuf::from("./some/thing.bc")))),
+ (OutputType::Exe, Some(OutFileName::Real(PathBuf::from("./some/thing")))),
]);
assert_same_hash(&v1, &v2);
@@ -296,35 +321,36 @@ fn test_search_paths_tracking_hash_different_order() {
let mut v3 = Options::default();
let mut v4 = Options::default();
+ let handler = EarlyErrorHandler::new(JSON);
const JSON: ErrorOutputType = ErrorOutputType::Json {
pretty: false,
json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
};
// Reference
- v1.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
- v1.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
- v1.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
- v1.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
- v1.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
-
- v2.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
- v2.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
- v2.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
- v2.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
- v2.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
-
- v3.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
- v3.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
- v3.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
- v3.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
- v3.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
-
- v4.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
- v4.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
- v4.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
- v4.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
- v4.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
+ v1.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
+ v1.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
+ v1.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
+ v1.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
+ v1.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
+
+ v2.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
+ v2.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
+ v2.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
+ v2.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
+ v2.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
+
+ v3.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
+ v3.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
+ v3.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
+ v3.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
+ v3.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
+
+ v4.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
+ v4.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
+ v4.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
+ v4.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
+ v4.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
assert_same_hash(&v1, &v2);
assert_same_hash(&v1, &v3);
@@ -554,7 +580,7 @@ fn test_codegen_options_tracking_hash() {
untracked!(incremental, Some(String::from("abc")));
// `link_arg` is omitted because it just forwards to `link_args`.
untracked!(link_args, vec![String::from("abc"), String::from("def")]);
- untracked!(link_self_contained, Some(true));
+ untracked!(link_self_contained, LinkSelfContained::on());
untracked!(linker, Some(PathBuf::from("linker")));
untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc));
untracked!(no_stack_check, true);
@@ -679,7 +705,7 @@ fn test_unstable_options_tracking_hash() {
untracked!(ls, true);
untracked!(macro_backtrace, true);
untracked!(meta_stats, true);
- untracked!(mir_pretty_relative_line_numbers, true);
+ untracked!(mir_include_spans, true);
untracked!(nll_facts, true);
untracked!(no_analysis, true);
untracked!(no_leak_check, true);
@@ -815,7 +841,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(thir_unsafeck, true);
tracked!(tiny_const_eval_limit, true);
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
- tracked!(trait_solver, TraitSolver::Chalk);
+ tracked!(trait_solver, TraitSolver::NextCoherence);
tracked!(translate_remapped_path_to_local_path, false);
tracked!(trap_unreachable, Some(false));
tracked!(treat_err_as_bug, NonZeroUsize::new(1));
@@ -845,7 +871,9 @@ fn test_edition_parsing() {
let options = Options::default();
assert!(options.edition == DEFAULT_EDITION);
+ let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
let matches = optgroups().parse(&["--edition=2018".to_string()]).unwrap();
- let (sessopts, _) = build_session_options_and_crate_config(matches);
+ let (sessopts, _) = build_session_options_and_crate_config(&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 cb1975020..035ea2414 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -11,16 +11,16 @@ 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::{ErrorOutputType, OutputFilenames};
+use rustc_session::config::{OutFileName, OutputFilenames, OutputTypes};
use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::CrateConfig;
-use rustc_session::{early_error, filesearch, output, Session};
+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;
+use session::{CompilerIO, EarlyErrorHandler};
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::mem;
@@ -58,6 +58,7 @@ pub fn add_configuration(
}
pub fn create_session(
+ handler: &EarlyErrorHandler,
sopts: config::Options,
cfg: FxHashSet<(String, Option<String>)>,
check_cfg: CheckCfg,
@@ -73,7 +74,11 @@ pub fn create_session(
let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
make_codegen_backend(&sopts)
} else {
- get_codegen_backend(&sopts.maybe_sysroot, sopts.unstable_opts.codegen_backend.as_deref())
+ 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
@@ -88,7 +93,7 @@ pub fn create_session(
) {
Ok(bundle) => bundle,
Err(e) => {
- early_error(sopts.error_format, format!("failed to load fluent bundle: {e}"));
+ handler.early_error(format!("failed to load fluent bundle: {e}"));
}
};
@@ -96,6 +101,7 @@ pub fn create_session(
locale_resources.push(codegen_backend.locale_resource());
let mut sess = session::build_session(
+ handler,
sopts,
io,
bundle,
@@ -218,16 +224,16 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
})
}
-fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
+fn load_backend_from_dylib(handler: &EarlyErrorHandler, path: &Path) -> MakeBackendFn {
let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
let err = format!("couldn't load codegen backend {path:?}: {err}");
- early_error(ErrorOutputType::default(), err);
+ handler.early_error(err);
});
let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
.unwrap_or_else(|e| {
let err = format!("couldn't load codegen backend: {e}");
- early_error(ErrorOutputType::default(), err);
+ handler.early_error(err);
});
// Intentionally leak the dynamic library. We can't ever unload it
@@ -242,6 +248,7 @@ fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
///
/// A name of `None` indicates that the default backend should be used.
pub fn get_codegen_backend(
+ handler: &EarlyErrorHandler,
maybe_sysroot: &Option<PathBuf>,
backend_name: Option<&str>,
) -> Box<dyn CodegenBackend> {
@@ -251,10 +258,12 @@ pub fn get_codegen_backend(
let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm");
match backend_name.unwrap_or(default_codegen_backend) {
- filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
+ filename if filename.contains('.') => {
+ load_backend_from_dylib(handler, filename.as_ref())
+ }
#[cfg(feature = "llvm")]
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
- backend_name => get_codegen_sysroot(maybe_sysroot, backend_name),
+ backend_name => get_codegen_sysroot(handler, maybe_sysroot, backend_name),
}
});
@@ -286,7 +295,11 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
})
}
-fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
+fn get_codegen_sysroot(
+ handler: &EarlyErrorHandler,
+ maybe_sysroot: &Option<PathBuf>,
+ backend_name: &str,
+) -> MakeBackendFn {
// For now we only allow this function to be called once as it'll dlopen a
// few things, which seems to work best if we only do that once. In
// general this assertion never trips due to the once guard in `get_codegen_backend`,
@@ -321,7 +334,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
"failed to find a `codegen-backends` folder \
in the sysroot candidates:\n* {candidates}"
);
- early_error(ErrorOutputType::default(), err);
+ handler.early_error(err);
});
info!("probing {} for a codegen backend", sysroot.display());
@@ -332,7 +345,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
sysroot.display(),
e
);
- early_error(ErrorOutputType::default(), err);
+ handler.early_error(err);
});
let mut file: Option<PathBuf> = None;
@@ -360,16 +373,16 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
prev.display(),
path.display()
);
- early_error(ErrorOutputType::default(), err);
+ handler.early_error(err);
}
file = Some(path.clone());
}
match file {
- Some(ref s) => load_backend_from_dylib(s),
+ Some(ref s) => load_backend_from_dylib(handler, s),
None => {
let err = format!("unsupported builtin codegen backend `{backend_name}`");
- early_error(ErrorOutputType::default(), err);
+ handler.early_error(err);
}
}
}
@@ -500,7 +513,36 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
base
}
+fn multiple_output_types_to_stdout(
+ output_types: &OutputTypes,
+ single_output_file_is_stdout: bool,
+) -> bool {
+ if atty::is(atty::Stream::Stdout) {
+ // If stdout is a tty, check if multiple text output types are
+ // specified by `--emit foo=- --emit bar=-` or `-o - --emit foo,bar`
+ let named_text_types = output_types
+ .iter()
+ .filter(|(f, o)| f.is_text_output() && *o == &Some(OutFileName::Stdout))
+ .count();
+ let unnamed_text_types =
+ output_types.iter().filter(|(f, o)| f.is_text_output() && o.is_none()).count();
+ named_text_types > 1 || unnamed_text_types > 1 && single_output_file_is_stdout
+ } else {
+ // Otherwise, all the output types should be checked
+ let named_types =
+ output_types.values().filter(|o| *o == &Some(OutFileName::Stdout)).count();
+ let unnamed_types = output_types.values().filter(|o| o.is_none()).count();
+ named_types > 1 || unnamed_types > 1 && single_output_file_is_stdout
+ }
+}
+
pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> OutputFilenames {
+ if multiple_output_types_to_stdout(
+ &sess.opts.output_types,
+ sess.io.output_file == Some(OutFileName::Stdout),
+ ) {
+ sess.emit_fatal(errors::MultipleOutputTypesToStdout);
+ }
match sess.io.output_file {
None => {
// "-" as input file will cause the parser to read from stdin so we
@@ -544,7 +586,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
OutputFilenames::new(
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
- out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
+ out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(),
ofile,
sess.io.temps_dir.clone(),
sess.opts.cg.extra_filename.clone(),