summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_interface/src/passes.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_interface/src/passes.rs
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_interface/src/passes.rs')
-rw-r--r--compiler/rustc_interface/src/passes.rs166
1 files changed, 136 insertions, 30 deletions
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(())
}