From 907ea5584173464b31326480dd11d9a71cbd4141 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 3 Jun 2022 22:46:01 +0200 Subject: [PATCH 01/20] Adapt tests to be able to run in miri Decrease the Ns of bug loops to a smaller N, which makes them a lot faster in miri. --- compiler/rustc_arena/src/tests.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_arena/src/tests.rs b/compiler/rustc_arena/src/tests.rs index 911e577c1edc7..ad61464343a4a 100644 --- a/compiler/rustc_arena/src/tests.rs +++ b/compiler/rustc_arena/src/tests.rs @@ -79,7 +79,11 @@ fn test_arena_alloc_nested() { #[test] pub fn test_copy() { let arena = TypedArena::default(); - for _ in 0..100000 { + #[cfg(not(miri))] + const N: usize = 100000; + #[cfg(miri)] + const N: usize = 1000; + for _ in 0..N { arena.alloc(Point { x: 1, y: 2, z: 3 }); } } @@ -106,7 +110,11 @@ struct Noncopy { #[test] pub fn test_noncopy() { let arena = TypedArena::default(); - for _ in 0..100000 { + #[cfg(not(miri))] + const N: usize = 100000; + #[cfg(miri)] + const N: usize = 1000; + for _ in 0..N { arena.alloc(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] }); } } @@ -114,7 +122,11 @@ pub fn test_noncopy() { #[test] pub fn test_typed_arena_zero_sized() { let arena = TypedArena::default(); - for _ in 0..100000 { + #[cfg(not(miri))] + const N: usize = 100000; + #[cfg(miri)] + const N: usize = 1000; + for _ in 0..N { arena.alloc(()); } } @@ -124,7 +136,11 @@ pub fn test_typed_arena_clear() { let mut arena = TypedArena::default(); for _ in 0..10 { arena.clear(); - for _ in 0..10000 { + #[cfg(not(miri))] + const N: usize = 10000; + #[cfg(miri)] + const N: usize = 100; + for _ in 0..N { arena.alloc(Point { x: 1, y: 2, z: 3 }); } } From 4d67f5bfc3b02da5d3cb37b6f9bc482eff9fb2f3 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 29 Jun 2022 15:14:09 -0700 Subject: [PATCH 02/20] Remove needless FIXME In this case, it seems fine to have the field be the inverse of the flag, especially the `enable` vs `disable` terminology is clear. --- src/librustdoc/config.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 6e3651665c8c4..1ae4c65f5aa6a 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -240,9 +240,6 @@ pub(crate) struct RenderOptions { pub(crate) resource_suffix: String, /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by /// default. - // - // FIXME(misdreavus): the flag name is `--disable-minification` but the meaning is inverted - // once read. pub(crate) enable_minification: bool, /// Whether to create an index page in the root of the output directory. If this is true but /// `enable_index_page` is None, generate a static listing of crates instead. From 8192288ee067054faf255335bfc249ed5cafa6d3 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 29 Jun 2022 15:24:15 -0700 Subject: [PATCH 03/20] Replace weird handling of edge case with panic --- src/librustdoc/clean/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 12467001271fd..c64df71f41ddc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1704,8 +1704,8 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option Tuple(vec![]), // FIXME(pcwalton) - + ty::Closure(..) => panic!("Closure"), + ty::Generator(..) => panic!("Generator"), ty::Bound(..) => panic!("Bound"), ty::Placeholder(..) => panic!("Placeholder"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"), From 2d2fd3168707567a1349230c0be609a860e60759 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 29 Jun 2022 15:25:14 -0700 Subject: [PATCH 04/20] Remove FIXME that hasn't been an issue in practice --- src/librustdoc/clean/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c64df71f41ddc..181416a2b4ac9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1759,7 +1759,6 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { match tcx.def_kind(parent) { DefKind::Struct | DefKind::Union => false, DefKind::Variant => true, - // FIXME: what about DefKind::Ctor? parent_kind => panic!("unexpected parent kind: {:?}", parent_kind), } } From a2799b2de80bafe8039c2cf7ea33754e0558acb1 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sun, 8 May 2022 21:23:52 -0700 Subject: [PATCH 05/20] fix projectionelem validation --- .../src/transform/validate.rs | 49 ++++++++++++++++--- .../ui/mir/ssa-analysis-regression-50041.rs | 4 +- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 7b9c6329d326e..56ecc5535285b 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -12,6 +12,7 @@ use rustc_middle::mir::{ Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, }; use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_live_locals; @@ -275,7 +276,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } }; - match parent_ty.ty.kind() { + let kind = match parent_ty.ty.kind() { + &ty::Opaque(def_id, substs) => { + self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind() + } + kind => kind, + }; + + match kind { ty::Tuple(fields) => { let Some(f_ty) = fields.get(f.as_usize()) else { fail_out_of_bounds(self, location); @@ -299,12 +307,39 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; check_equal(self, location, f_ty); } - ty::Generator(_, substs, _) => { - let substs = substs.as_generator(); - let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else { - fail_out_of_bounds(self, location); - return; + &ty::Generator(def_id, substs, _) => { + let f_ty = if let Some(var) = parent_ty.variant_index { + let gen_body = if def_id == self.body.source.def_id() { + self.body + } else { + self.tcx.optimized_mir(def_id) + }; + + let Some(layout) = gen_body.generator_layout() else { + self.fail(location, format!("No generator layout for {:?}", parent_ty)); + return; + }; + + let Some(&local) = layout.variant_fields[var].get(f) else { + fail_out_of_bounds(self, location); + return; + }; + + let Some(&f_ty) = layout.field_tys.get(local) else { + self.fail(location, format!("Out of bounds local {:?} for {:?}", local, parent_ty)); + return; + }; + + f_ty + } else { + let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else { + fail_out_of_bounds(self, location); + return; + }; + + f_ty }; + check_equal(self, location, f_ty); } _ => { @@ -328,6 +363,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { { self.fail(location, format!("{:?}, has deref at the wrong place", place)); } + + self.super_place(place, cntxt, location); } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { diff --git a/src/test/ui/mir/ssa-analysis-regression-50041.rs b/src/test/ui/mir/ssa-analysis-regression-50041.rs index 8e9c14a03c386..ebc3e2f8c0e31 100644 --- a/src/test/ui/mir/ssa-analysis-regression-50041.rs +++ b/src/test/ui/mir/ssa-analysis-regression-50041.rs @@ -5,7 +5,7 @@ #![feature(lang_items)] #![no_std] -struct NonNull(*mut T); +struct NonNull(*const T); struct Unique(NonNull); @@ -23,7 +23,7 @@ unsafe fn box_free(ptr: Unique) { } #[inline(never)] -fn dealloc(_: *mut T) {} +fn dealloc(_: *const T) {} pub struct Foo(T); From 8371a036ea485ef8a830349c779e5acc116cfd8d Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 4 Jul 2022 14:38:42 +0100 Subject: [PATCH 06/20] incr: cache dwarf objects in work products Cache DWARF objects alongside object files in work products when those exist so that DWARF object files are available for thorin in packed mode in incremental scenarios. Signed-off-by: David Wood --- .../rustc_codegen_cranelift/src/driver/aot.rs | 11 ++- compiler/rustc_codegen_ssa/src/back/write.rs | 75 +++++++++++++------ .../rustc_incremental/src/persist/load.rs | 18 ++--- .../rustc_incremental/src/persist/save.rs | 11 +-- .../src/persist/work_product.rs | 46 ++++++------ .../rustc_query_system/src/dep_graph/graph.rs | 8 +- .../incremental/split_debuginfo_cached.rs | 25 +++++++ 7 files changed, 128 insertions(+), 66 deletions(-) create mode 100644 src/test/incremental/split_debuginfo_cached.rs diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 05457ce15e9a7..50d8fc30d7d7c 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -66,7 +66,11 @@ fn emit_module( let work_product = if backend_config.disable_incr_cache { None } else { - rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(tcx.sess, &name, &tmp_file) + rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( + tcx.sess, + &name, + &[("o", &tmp_file)], + ) }; ModuleCodegenResult( @@ -82,7 +86,10 @@ fn reuse_workproduct_for_cgu( ) -> CompiledModule { let work_product = cgu.previous_work_product(tcx); let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str())); - let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &work_product.saved_file); + let source_file = rustc_incremental::in_incr_comp_dir_sess( + &tcx.sess, + &work_product.saved_files.get("o").expect("no saved object file in work product"), + ); if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) { tcx.sess.err(&format!( "unable to copy {} to {}: {}", diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 632f07c5c2d80..f4a5cac872e05 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -494,12 +494,18 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir"); for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) { - if let Some(path) = &module.object { - if let Some((id, product)) = - copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, path) - { - work_products.insert(id, product); - } + let mut files = Vec::new(); + if let Some(object_file_path) = &module.object { + files.push(("o", object_file_path.as_path())); + } + if let Some(dwarf_object_file_path) = &module.dwarf_object { + files.push(("dwo", dwarf_object_file_path.as_path())); + } + + if let Some((id, product)) = + copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice()) + { + work_products.insert(id, product); } } @@ -856,29 +862,50 @@ fn execute_copy_from_cache_work_item( assert!(module_config.emit_obj != EmitObj::None); let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); - let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)); - let source_file = in_incr_comp_dir(&incr_comp_session_dir, &module.source.saved_file); - debug!( - "copying pre-existing module `{}` from {:?} to {}", - module.name, - source_file, - obj_out.display() + + let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| { + let source_file = in_incr_comp_dir(&incr_comp_session_dir, saved_path); + debug!( + "copying pre-existing module `{}` from {:?} to {}", + module.name, + source_file, + output_path.display() + ); + match link_or_copy(&source_file, &output_path) { + Ok(_) => Some(output_path), + Err(err) => { + let diag_handler = cgcx.create_diag_handler(); + diag_handler.err(&format!( + "unable to copy {} to {}: {}", + source_file.display(), + output_path.display(), + err + )); + None + } + } + }; + + let object = load_from_incr_comp_dir( + cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)), + &module.source.saved_files.get("o").expect("no saved object file in work product"), ); - if let Err(err) = link_or_copy(&source_file, &obj_out) { - let diag_handler = cgcx.create_diag_handler(); - diag_handler.err(&format!( - "unable to copy {} to {}: {}", - source_file.display(), - obj_out.display(), - err - )); - } + let dwarf_object = + module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| { + let dwarf_obj_out = cgcx + .output_filenames + .split_dwarf_path(cgcx.split_debuginfo, cgcx.split_dwarf_kind, Some(&module.name)) + .expect( + "saved dwarf object in work product but `split_dwarf_path` returned `None`", + ); + load_from_incr_comp_dir(dwarf_obj_out, &saved_dwarf_object_file) + }); WorkItemResult::Compiled(CompiledModule { name: module.name, kind: ModuleKind::Regular, - object: Some(obj_out), - dwarf_object: None, + object, + dwarf_object, bytecode: None, }) } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 9c325faae8058..f59d8d596b98e 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -161,19 +161,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { Decodable::decode(&mut work_product_decoder); for swp in work_products { - let mut all_files_exist = true; - let path = in_incr_comp_dir_sess(sess, &swp.work_product.saved_file); - if !path.exists() { - all_files_exist = false; - - if sess.opts.debugging_opts.incremental_info { - eprintln!( - "incremental: could not find file for work \ - product: {}", - path.display() - ); + let all_files_exist = swp.work_product.saved_files.iter().all(|(_, path)| { + let exists = in_incr_comp_dir_sess(sess, path).exists(); + if !exists && sess.opts.debugging_opts.incremental_info { + eprintln!("incremental: could not find file for work product: {path}",); } - } + exists + }); if all_files_exist { debug!("reconcile_work_products: all files for {:?} exist", swp); diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 79836d66011a2..4059b7cfc8eb9 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -108,16 +108,17 @@ pub fn save_work_product_index( for (id, wp) in previous_work_products.iter() { if !new_work_products.contains_key(id) { work_product::delete_workproduct_files(sess, wp); - debug_assert!(!in_incr_comp_dir_sess(sess, &wp.saved_file).exists()); + debug_assert!( + !wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists()) + ); } } // Check that we did not delete one of the current work-products: debug_assert!({ - new_work_products - .iter() - .map(|(_, wp)| in_incr_comp_dir_sess(sess, &wp.saved_file)) - .all(|path| path.exists()) + new_work_products.iter().all(|(_, wp)| { + wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists()) + }) }); } diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs index 4789c0f581fdb..1b184eca964c3 100644 --- a/compiler/rustc_incremental/src/persist/work_product.rs +++ b/compiler/rustc_incremental/src/persist/work_product.rs @@ -3,6 +3,7 @@ //! [work products]: WorkProduct use crate::persist::fs::*; +use rustc_data_structures::stable_map::FxHashMap; use rustc_fs_util::link_or_copy; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; @@ -13,38 +14,41 @@ use std::path::Path; pub fn copy_cgu_workproduct_to_incr_comp_cache_dir( sess: &Session, cgu_name: &str, - path: &Path, + files: &[(&'static str, &Path)], ) -> Option<(WorkProductId, WorkProduct)> { - debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path); + debug!(?cgu_name, ?files); sess.opts.incremental.as_ref()?; - let file_name = format!("{}.o", cgu_name); - let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name); - let saved_file = match link_or_copy(path, &path_in_incr_dir) { - Ok(_) => file_name, - Err(err) => { - sess.warn(&format!( - "error copying object file `{}` to incremental directory as `{}`: {}", - path.display(), - path_in_incr_dir.display(), - err - )); - return None; + let mut saved_files = FxHashMap::default(); + for (ext, path) in files { + let file_name = format!("{cgu_name}.{ext}"); + let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name); + match link_or_copy(path, &path_in_incr_dir) { + Ok(_) => { + let _ = saved_files.insert(ext.to_string(), file_name); + } + Err(err) => { + sess.warn(&format!( + "error copying object file `{}` to incremental directory as `{}`: {}", + path.display(), + path_in_incr_dir.display(), + err + )); + } } - }; - - let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_file }; + } + let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_files }; + debug!(?work_product); let work_product_id = WorkProductId::from_cgu_name(cgu_name); Some((work_product_id, work_product)) } /// Removes files for a given work product. pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) { - let path = in_incr_comp_dir_sess(sess, &work_product.saved_file); - match std_fs::remove_file(&path) { - Ok(()) => {} - Err(err) => { + for (_, path) in &work_product.saved_files { + let path = in_incr_comp_dir_sess(sess, path); + if let Err(err) = std_fs::remove_file(&path) { sess.warn(&format!( "file-system error deleting outdated file `{}`: {}", path.display(), diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 341cf8f827bc9..3291717c550df 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -886,8 +886,12 @@ impl DepGraph { #[derive(Clone, Debug, Encodable, Decodable)] pub struct WorkProduct { pub cgu_name: String, - /// Saved file associated with this CGU. - pub saved_file: String, + /// Saved files associated with this CGU. In each key/value pair, the value is the path to the + /// saved file and the key is some identifier for the type of file being saved. + /// + /// By convention, file extensions are currently used as identifiers, i.e. the key "o" maps to + /// the object file's path, and "dwo" to the dwarf object file's path. + pub saved_files: FxHashMap, } // Index type for `DepNodeData`'s edges. diff --git a/src/test/incremental/split_debuginfo_cached.rs b/src/test/incremental/split_debuginfo_cached.rs new file mode 100644 index 0000000000000..25c802d5a1d2e --- /dev/null +++ b/src/test/incremental/split_debuginfo_cached.rs @@ -0,0 +1,25 @@ +// Check that compiling with packed Split DWARF twice succeeds. This should confirm that DWARF +// objects are cached as work products and available to the incremental compilation for `thorin` to +// pack into a DWARF package. + +// ignore-tidy-linelength +// only-x86_64-unknown-linux-gnu +// revisions:rpass1 rpass2 + +// [rpass1]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split +// [rpass2]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split + +#![feature(rustc_attrs)] +// For `rpass2`, nothing has changed so everything should re-used. +#![rustc_partition_reused(module = "split_debuginfo_cached", cfg = "rpass2")] +#![rustc_partition_reused(module = "split_debuginfo_cached-another_module", cfg = "rpass2")] + +mod another_module { + pub fn foo() -> &'static str { + "hello world" + } +} + +pub fn main() { + println!("{}", another_module::foo()); +} From fc641f21c2f1ba0dcf7bc7750844f097e25b3029 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 6 Jul 2022 10:15:45 +0100 Subject: [PATCH 07/20] ssa: remove dwo of metadata and allocator module Compiling with `-Csplit-debuginfo=packed` was leaving behind `.dwo` files because either the metadata or allocator module contained a DWARF object which was not being removed by the `maybe_remove_temps_from_module` closure. --- compiler/rustc_codegen_ssa/src/back/link.rs | 32 ++++++++++++--------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 72aa790c36357..c85c3bf571068 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -151,11 +151,23 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( return; } - let remove_temps_from_module = |module: &CompiledModule| { - if let Some(ref obj) = module.object { - ensure_removed(sess.diagnostic(), obj); - } - }; + let maybe_remove_temps_from_module = + |preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| { + if !preserve_objects { + if let Some(ref obj) = module.object { + ensure_removed(sess.diagnostic(), obj); + } + } + + if !preserve_dwarf_objects { + if let Some(ref dwo_obj) = module.dwarf_object { + ensure_removed(sess.diagnostic(), dwo_obj); + } + } + }; + + let remove_temps_from_module = + |module: &CompiledModule| maybe_remove_temps_from_module(false, false, module); // Otherwise, always remove the metadata and allocator module temporaries. if let Some(ref metadata_module) = codegen_results.metadata_module { @@ -177,15 +189,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( debug!(?preserve_objects, ?preserve_dwarf_objects); for module in &codegen_results.modules { - if !preserve_objects { - remove_temps_from_module(module); - } - - if !preserve_dwarf_objects { - if let Some(ref obj) = module.dwarf_object { - ensure_removed(sess.diagnostic(), obj); - } - } + maybe_remove_temps_from_module(preserve_objects, preserve_dwarf_objects, module); } }); From e1065239fe768dbad7ecbe37be39cb3204476a87 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 6 Jul 2022 10:56:08 +0100 Subject: [PATCH 08/20] ssa: abort if dwarf packaging fails This should have been here from the start... oops. When `thorin` fails to package a DWARF package, that should fail compilation. --- compiler/rustc_codegen_ssa/src/back/link.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c85c3bf571068..960e98243ac72 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -653,6 +653,7 @@ fn link_dwarf_object<'a>( sess.struct_err("linking dwarf objects with thorin failed") .note(&format!("{:?}", e)) .emit(); + sess.abort_if_errors(); } } } From 7d205afae46c499a9196eeac8a35c999012051e9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Jul 2022 13:48:51 +0200 Subject: [PATCH 09/20] Don't generate anchors on inherent impl methods --- src/librustdoc/html/render/mod.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 548f6c3a98729..461b2f1549434 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1415,7 +1415,10 @@ fn render_impl( id, item_type, in_trait_class, ); render_rightside(w, cx, item, containing_item, render_mode); - write!(w, "", id); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "", id); + } w.write_str("

"); render_assoc_item( w, @@ -1438,7 +1441,10 @@ fn render_impl( id, item_type, in_trait_class ); render_rightside(w, cx, item, containing_item, render_mode); - write!(w, "", id); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "", id); + } w.write_str("

"); assoc_const( w, @@ -1460,7 +1466,10 @@ fn render_impl( let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); write!(w, "
", id, item_type, in_trait_class); - write!(w, "", id); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "", id); + } w.write_str("

"); assoc_type( w, @@ -1483,7 +1492,10 @@ fn render_impl( "
", id, item_type, in_trait_class ); - write!(w, "", id); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "", id); + } w.write_str("

"); assoc_type( w, From 7967152eeeffbf86f20186d08f6faff1c859a211 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Jul 2022 14:07:41 +0200 Subject: [PATCH 10/20] Add test for inherent impls anchors --- src/test/rustdoc/anchors.no_const_anchor.html | 1 + .../rustdoc/anchors.no_const_anchor2.html | 1 + .../rustdoc/anchors.no_method_anchor.html | 1 + .../anchors.no_trait_method_anchor.html | 1 + .../rustdoc/anchors.no_tymethod_anchor.html | 1 + src/test/rustdoc/anchors.no_type_anchor.html | 1 + src/test/rustdoc/anchors.no_type_anchor2.html | 1 + src/test/rustdoc/anchors.rs | 49 +++++++++++++++++++ 8 files changed, 56 insertions(+) create mode 100644 src/test/rustdoc/anchors.no_const_anchor.html create mode 100644 src/test/rustdoc/anchors.no_const_anchor2.html create mode 100644 src/test/rustdoc/anchors.no_method_anchor.html create mode 100644 src/test/rustdoc/anchors.no_trait_method_anchor.html create mode 100644 src/test/rustdoc/anchors.no_tymethod_anchor.html create mode 100644 src/test/rustdoc/anchors.no_type_anchor.html create mode 100644 src/test/rustdoc/anchors.no_type_anchor2.html create mode 100644 src/test/rustdoc/anchors.rs diff --git a/src/test/rustdoc/anchors.no_const_anchor.html b/src/test/rustdoc/anchors.no_const_anchor.html new file mode 100644 index 0000000000000..98f47e53038a9 --- /dev/null +++ b/src/test/rustdoc/anchors.no_const_anchor.html @@ -0,0 +1 @@ + diff --git a/src/test/rustdoc/anchors.no_const_anchor2.html b/src/test/rustdoc/anchors.no_const_anchor2.html new file mode 100644 index 0000000000000..6d37e8e5eee5e --- /dev/null +++ b/src/test/rustdoc/anchors.no_const_anchor2.html @@ -0,0 +1 @@ + diff --git a/src/test/rustdoc/anchors.no_method_anchor.html b/src/test/rustdoc/anchors.no_method_anchor.html new file mode 100644 index 0000000000000..f46d3090ed370 --- /dev/null +++ b/src/test/rustdoc/anchors.no_method_anchor.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_trait_method_anchor.html b/src/test/rustdoc/anchors.no_trait_method_anchor.html new file mode 100644 index 0000000000000..445a7bb560aca --- /dev/null +++ b/src/test/rustdoc/anchors.no_trait_method_anchor.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_tymethod_anchor.html b/src/test/rustdoc/anchors.no_tymethod_anchor.html new file mode 100644 index 0000000000000..bb0771b10035d --- /dev/null +++ b/src/test/rustdoc/anchors.no_tymethod_anchor.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_type_anchor.html b/src/test/rustdoc/anchors.no_type_anchor.html new file mode 100644 index 0000000000000..d317eb5005017 --- /dev/null +++ b/src/test/rustdoc/anchors.no_type_anchor.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_type_anchor2.html b/src/test/rustdoc/anchors.no_type_anchor2.html new file mode 100644 index 0000000000000..72a1186bf7e30 --- /dev/null +++ b/src/test/rustdoc/anchors.no_type_anchor2.html @@ -0,0 +1 @@ + diff --git a/src/test/rustdoc/anchors.rs b/src/test/rustdoc/anchors.rs new file mode 100644 index 0000000000000..034cf8eaf4ff7 --- /dev/null +++ b/src/test/rustdoc/anchors.rs @@ -0,0 +1,49 @@ +// This test ensures that anchors are generated in the right places. + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] +#![crate_name = "foo"] + +pub struct Foo; + +// @has 'foo/trait.Bar.html' +pub trait Bar { + // There should be no anchors here. + // @snapshot no_type_anchor - '//*[@id="associatedtype.T"]' + type T; + // There should be no anchors here. + // @snapshot no_const_anchor - '//*[@id="associatedconstant.YOLO"]' + const YOLO: u32; + + // There should be no anchors here. + // @snapshot no_tymethod_anchor - '//*[@id="tymethod.foo"]' + fn foo(); + // There should be no anchors here. + // @snapshot no_trait_method_anchor - '//*[@id="method.bar"]' + fn bar() {} +} + +// @has 'foo/struct.Foo.html' +impl Bar for Foo { + // @has - '//*[@id="associatedtype.T"]/a[@class="anchor"]' '' + type T = u32; + // @has - '//*[@id="associatedconstant.YOLO"]/a[@class="anchor"]' '' + const YOLO: u32 = 0; + + // @has - '//*[@id="method.foo"]/a[@class="anchor"]' '' + fn foo() {} + // Same check for provided "bar" method. + // @has - '//*[@id="method.bar"]/a[@class="anchor"]' '' +} + +impl Foo { + // @snapshot no_const_anchor2 - '//*[@id="associatedconstant.X"]' + // There should be no anchors here. + pub const X: i32 = 0; + // @snapshot no_type_anchor2 - '//*[@id="associatedtype.Y"]' + // There should be no anchors here. + pub type Y = u32; + // @snapshot no_method_anchor - '//*[@id="method.new"]' + // There should be no anchors here. + pub fn new() -> Self { Self } +} From 8c9a130056fc28a925a668ef49f31b588005c0ca Mon Sep 17 00:00:00 2001 From: pierwill Date: Wed, 6 Jul 2022 11:16:29 -0500 Subject: [PATCH 11/20] Edit `rustc_mir_dataflow::framework` documentation --- compiler/rustc_mir_dataflow/src/framework/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 67c16e6c0849d..f9fd6c9c56b42 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -1,7 +1,7 @@ //! A framework that can express both [gen-kill] and generic dataflow problems. //! -//! To actually use this framework, you must implement either the `Analysis` or the -//! `GenKillAnalysis` trait. If your transfer function can be expressed with only gen/kill +//! To use this framework, implement either the [`Analysis`] or the +//! [`GenKillAnalysis`] trait. If your transfer function can be expressed with only gen/kill //! operations, prefer `GenKillAnalysis` since it will run faster while iterating to fixpoint. The //! `impls` module contains several examples of gen/kill dataflow analyses. //! @@ -96,7 +96,7 @@ impl BitSetExt for ChunkedBitSet { } } -/// Define the domain of a dataflow problem. +/// Defines the domain of a dataflow problem. /// /// This trait specifies the lattice on which this analysis operates (the domain) as well as its /// initial value at the entry point of each basic block. @@ -113,12 +113,12 @@ pub trait AnalysisDomain<'tcx> { /// suitable as part of a filename. const NAME: &'static str; - /// The initial value of the dataflow state upon entry to each basic block. + /// Returns the initial value of the dataflow state upon entry to each basic block. fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; /// Mutates the initial value of the dataflow state upon entry to the `START_BLOCK`. /// - /// For backward analyses, initial state besides the bottom value is not yet supported. Trying + /// For backward analyses, initial state (besides the bottom value) is not yet supported. Trying /// to mutate the initial state will result in a panic. // // FIXME: For backward dataflow analyses, the initial state should be applied to every basic @@ -155,9 +155,9 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// Updates the current dataflow state with an effect that occurs immediately *before* the /// given statement. /// - /// This method is useful if the consumer of the results of this analysis needs only to observe + /// This method is useful if the consumer of the results of this analysis only needs to observe /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule, - /// analyses should not implement this without implementing `apply_statement_effect`. + /// analyses should not implement this without also implementing `apply_statement_effect`. fn apply_before_statement_effect( &self, _state: &mut Self::Domain, @@ -184,7 +184,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// /// This method is useful if the consumer of the results of this analysis needs only to observe /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule, - /// analyses should not implement this without implementing `apply_terminator_effect`. + /// analyses should not implement this without also implementing `apply_terminator_effect`. fn apply_before_terminator_effect( &self, _state: &mut Self::Domain, From 211fb66810c978576201bb2054f1ccea0e176f10 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 3 Jun 2022 22:47:05 +0200 Subject: [PATCH 12/20] Fix stacked borrows violation in rustc_arena There was a problem with storing a `Box` in a struct, where the current rules would invalidate the value. this makes it store a raw pointer instead, circumventing the aliasing problems. --- compiler/rustc_arena/src/lib.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 62995dfd2e2f0..a5f1cbc96daa7 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -19,6 +19,7 @@ #![feature(rustc_attrs)] #![cfg_attr(test, feature(test))] #![feature(strict_provenance)] +#![feature(ptr_const_cast)] use smallvec::SmallVec; @@ -27,7 +28,7 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::marker::{PhantomData, Send}; use std::mem::{self, MaybeUninit}; -use std::ptr; +use std::ptr::{self, NonNull}; use std::slice; #[inline(never)] @@ -55,15 +56,24 @@ pub struct TypedArena { struct ArenaChunk { /// The raw storage for the arena chunk. - storage: Box<[MaybeUninit]>, + storage: NonNull<[MaybeUninit]>, /// The number of valid entries in the chunk. entries: usize, } +unsafe impl<#[may_dangle] T> Drop for ArenaChunk { + fn drop(&mut self) { + unsafe { Box::from_raw(self.storage.as_mut()) }; + } +} + impl ArenaChunk { #[inline] unsafe fn new(capacity: usize) -> ArenaChunk { - ArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } + ArenaChunk { + storage: NonNull::new(Box::into_raw(Box::new_uninit_slice(capacity))).unwrap(), + entries: 0, + } } /// Destroys this arena chunk. @@ -72,14 +82,15 @@ impl ArenaChunk { // The branch on needs_drop() is an -O1 performance optimization. // Without the branch, dropping TypedArena takes linear time. if mem::needs_drop::() { - ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len])); + let slice = &mut *(self.storage.as_mut()); + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len])); } } // Returns a pointer to the first allocated object. #[inline] fn start(&mut self) -> *mut T { - MaybeUninit::slice_as_mut_ptr(&mut self.storage) + self.storage.as_ptr() as *mut T } // Returns a pointer to the end of the allocated space. @@ -90,7 +101,7 @@ impl ArenaChunk { // A pointer as large as possible for zero-sized elements. ptr::invalid_mut(!0) } else { - self.start().add(self.storage.len()) + self.start().add((*self.storage.as_ptr()).len()) } } } @@ -274,7 +285,7 @@ impl TypedArena { // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2); + new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / elem_size / 2); new_cap *= 2; } else { new_cap = PAGE / elem_size; @@ -382,7 +393,7 @@ impl DroplessArena { // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2); + new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / 2); new_cap *= 2; } else { new_cap = PAGE; From 6c6388cd6c264904e3dc961c59d9187d640ed25d Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 16 Jun 2022 12:52:35 +0200 Subject: [PATCH 13/20] Document, that some lint have to be expected on the crate level (RFC 2383) Examples: NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS, MIXED_SCRIPT_CONFUSABLES --- compiler/rustc_lint_defs/src/builtin.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b1bfd612b90e5..2cce6434b0fab 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -519,6 +519,11 @@ declare_lint! { /// The `expect` attribute can be removed if this is intended behavior otherwise /// it should be investigated why the expected lint is no longer issued. /// + /// In rare cases, the expectation might be emitted at a different location than + /// shown in the shown code snippet. In most cases, the `#[expect]` attribute + /// works when added to the outer scope. A few lints can only be expected + /// on a crate level. + /// /// Part of RFC 2383. The progress is being tracked in [#54503] /// /// [#54503]: https://github.com/rust-lang/rust/issues/54503 From c8b4873cf90c542efbda7a27a8ad6ebdb099275e Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 16 Jun 2022 13:20:57 +0200 Subject: [PATCH 14/20] Add function to manually fulfill lint expectations (RFC 2383) --- compiler/rustc_lint/src/context.rs | 33 ++++++++++++++++++++++++++++- compiler/rustc_lint_defs/src/lib.rs | 7 ++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index eeb66f2d73871..cf5af7d481242 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -33,7 +33,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt}; -use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; use rustc_span::lev_distance::find_best_match_for_name; @@ -887,6 +887,29 @@ pub trait LintContext: Sized { ) { self.lookup(lint, None as Option, decorate); } + + /// This returns the lint level for the given lint at the current location. + fn get_lint_level(&self, lint: &'static Lint) -> Level; + + /// This function can be used to manually fulfill an expectation. This can + /// be used for lints which contain several spans, and should be suppressed, + /// if either location was marked with an expectation. + /// + /// Note that this function should only be called for [`LintExpectationId`]s + /// retrieved from the current lint pass. Buffered or manually created ids can + /// cause ICEs. + fn fulfill_expectation(&self, expectation: LintExpectationId) { + // We need to make sure that submitted expectation ids are correctly fulfilled suppressed + // and stored between compilation sessions. To not manually do these steps, we simply create + // a dummy diagnostic and emit is as usual, which will be suppressed and stored like a normal + // expected lint diagnostic. + self.sess() + .struct_expect( + "this is a dummy diagnostic, to submit and store an expectation", + expectation, + ) + .emit(); + } } impl<'a> EarlyContext<'a> { @@ -934,6 +957,10 @@ impl LintContext for LateContext<'_> { None => self.tcx.struct_lint_node(lint, hir_id, decorate), } } + + fn get_lint_level(&self, lint: &'static Lint) -> Level { + self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs).0 + } } impl LintContext for EarlyContext<'_> { @@ -956,6 +983,10 @@ impl LintContext for EarlyContext<'_> { ) { self.builder.struct_lint(lint, span.map(|s| s.into()), decorate) } + + fn get_lint_level(&self, lint: &'static Lint) -> Level { + self.builder.lint_level(lint).0 + } } impl<'tcx> LateContext<'tcx> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index cb1c6f4098767..a35d830f711a5 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -229,6 +229,13 @@ impl Level { Level::Deny | Level::Forbid => true, } } + + pub fn get_expectation_id(&self) -> Option { + match self { + Level::Expect(id) | Level::ForceWarn(Some(id)) => Some(*id), + _ => None, + } + } } /// Specification of a single lint. From a2810cd277a8b747e5cb4ddd57d310e770599357 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 26 Jun 2022 00:00:47 +0200 Subject: [PATCH 15/20] Fix `#[expect]` and `#[allow]` for `clippy::duplicate_mod` --- .../clippy/clippy_lints/src/duplicate_mod.rs | 22 +++++++++++++++++-- .../ui-cargo/duplicate_mod/fail/src/d.rs | 0 .../ui-cargo/duplicate_mod/fail/src/main.rs | 13 +++++++++++ .../duplicate_mod/fail/src/main.stderr | 19 ++++++++++++---- 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs index c6c7b959d4f49..4f49bb879f503 100644 --- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs +++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind}; use rustc_errors::MultiSpan; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext, Level}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{FileName, Span}; use std::collections::BTreeMap; @@ -49,6 +49,7 @@ declare_clippy_lint! { struct Modules { local_path: PathBuf, spans: Vec, + lint_levels: Vec, } #[derive(Default)] @@ -70,13 +71,30 @@ impl EarlyLintPass for DuplicateMod { let modules = self.modules.entry(absolute_path).or_insert(Modules { local_path, spans: Vec::new(), + lint_levels: Vec::new(), }); modules.spans.push(item.span_with_attributes()); + modules.lint_levels.push(cx.get_lint_level(DUPLICATE_MOD)); } } fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) { - for Modules { local_path, spans } in self.modules.values() { + for Modules { local_path, spans, lint_levels } in self.modules.values() { + if spans.len() < 2 { + continue; + } + + // At this point the lint would be emitted + assert_eq!(spans.len(), lint_levels.len()); + let spans: Vec<_> = spans.into_iter().zip(lint_levels).filter_map(|(span, lvl)|{ + if let Some(id) = lvl.get_expectation_id() { + cx.fulfill_expectation(id); + } + + (!matches!(lvl, Level::Allow | Level::Expect(_))).then_some(*span) + }) + .collect(); + if spans.len() < 2 { continue; } diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs index 79b343da24700..99ca538b6e4a5 100644 --- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs @@ -1,3 +1,5 @@ +#[feature(lint_reasons)] + mod a; mod b; @@ -13,4 +15,15 @@ mod c3; mod from_other_module; mod other_module; +mod d; +#[path = "d.rs"] +mod d2; +#[path = "d.rs"] +#[expect(clippy::duplicate_mod)] +mod d3; +#[path = "d.rs"] +#[allow(clippy::duplicate_mod)] +mod d4; + + fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr index 00d7739c8a2ea..61df1ad5d501a 100644 --- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr +++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr @@ -1,5 +1,5 @@ error: file is loaded as a module multiple times: `$DIR/b.rs` - --> $DIR/main.rs:3:1 + --> $DIR/main.rs:5:1 | LL | mod b; | ^^^^^^ first loaded here @@ -11,7 +11,7 @@ LL | | mod b2; = help: replace all but one `mod` item with `use` items error: file is loaded as a module multiple times: `$DIR/c.rs` - --> $DIR/main.rs:7:1 + --> $DIR/main.rs:9:1 | LL | mod c; | ^^^^^^ first loaded here @@ -25,7 +25,7 @@ LL | | mod c3; = help: replace all but one `mod` item with `use` items error: file is loaded as a module multiple times: `$DIR/from_other_module.rs` - --> $DIR/main.rs:13:1 + --> $DIR/main.rs:15:1 | LL | mod from_other_module; | ^^^^^^^^^^^^^^^^^^^^^^ first loaded here @@ -38,5 +38,16 @@ LL | | mod m; | = help: replace all but one `mod` item with `use` items -error: aborting due to 3 previous errors +error: file is loaded as a module multiple times: `$DIR/b.rs` + --> $DIR/main.rs:18:1 + | +LL | mod d; + | ^^^^^^ first loaded here +LL | / #[path = "d.rs"] +LL | | mod d2; + | |_______^ loaded again here + | + = help: replace all but one `mod` item with `use` items + +error: aborting due to 4 previous errors From c9dd1d9983b9a08159c2e3c86071d1a5ef7ebb20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 4 Jul 2022 00:00:00 +0000 Subject: [PATCH 16/20] Make MIR basic blocks field public This makes it possible to mutably borrow different fields of the MIR body without resorting to methods like `basic_blocks_local_decls_mut_and_var_debug_info`. To preserve validity of control flow graph caches in the presence of modifications, a new struct `BasicBlocks` wraps together basic blocks and control flow graph caches. The `BasicBlocks` dereferences to `IndexVec`. On the other hand a mutable access requires explicit `as_mut()` call. --- .../src/transform/promote_consts.rs | 5 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 141 ++++++++++++++++ compiler/rustc_middle/src/mir/mod.rs | 151 ++---------------- compiler/rustc_middle/src/mir/traversal.rs | 31 ++-- compiler/rustc_mir_build/src/lints.rs | 8 +- compiler/rustc_mir_transform/src/add_retag.rs | 3 +- .../rustc_mir_transform/src/coverage/graph.rs | 2 +- .../rustc_mir_transform/src/coverage/spans.rs | 3 +- .../rustc_mir_transform/src/coverage/tests.rs | 1 + .../src/dead_store_elimination.rs | 2 +- .../rustc_mir_transform/src/deaggregator.rs | 6 +- .../src/elaborate_box_derefs.rs | 4 +- .../rustc_mir_transform/src/instcombine.rs | 5 +- .../src/lower_intrinsics.rs | 4 +- .../src/lower_slice_len.rs | 6 +- .../rustc_mir_transform/src/match_branches.rs | 4 +- .../src/normalize_array_len.rs | 4 +- .../src/remove_storage_markers.rs | 2 +- .../src/remove_unneeded_drops.rs | 5 +- .../rustc_mir_transform/src/remove_zsts.rs | 6 +- .../rustc_mir_transform/src/simplify_try.rs | 15 +- 21 files changed, 213 insertions(+), 195 deletions(-) create mode 100644 compiler/rustc_middle/src/mir/basic_blocks.rs diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 6298fa7f062cb..12527a9b2ae66 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -856,7 +856,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { literal: ConstantKind::from_const(_const, tcx), })) }; - let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); + let blocks = self.source.basic_blocks.as_mut(); + let local_decls = &mut self.source.local_decls; let loc = candidate.location; let statement = &mut blocks[loc.block].statements[loc.statement_index]; match statement.kind { @@ -865,7 +866,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Rvalue::Ref(ref mut region, borrow_kind, ref mut place), )) => { // Use the underlying local for this (necessarily interior) borrow. - let ty = local_decls.local_decls()[place.local].ty; + let ty = local_decls[place.local].ty; let span = statement.source_info.span; let ref_ty = tcx.mk_ref( diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs new file mode 100644 index 0000000000000..ec3a818472bd0 --- /dev/null +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -0,0 +1,141 @@ +use crate::mir::graph_cyclic_cache::GraphIsCyclicCache; +use crate::mir::predecessors::{PredecessorCache, Predecessors}; +use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources}; +use crate::mir::traversal::PostorderCache; +use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK}; + +use rustc_data_structures::graph; +use rustc_index::vec::IndexVec; + +#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] +pub struct BasicBlocks<'tcx> { + basic_blocks: IndexVec>, + predecessor_cache: PredecessorCache, + switch_source_cache: SwitchSourceCache, + is_cyclic: GraphIsCyclicCache, + postorder_cache: PostorderCache, +} + +impl<'tcx> BasicBlocks<'tcx> { + #[inline] + pub fn new(basic_blocks: IndexVec>) -> Self { + BasicBlocks { + basic_blocks, + predecessor_cache: PredecessorCache::new(), + switch_source_cache: SwitchSourceCache::new(), + is_cyclic: GraphIsCyclicCache::new(), + postorder_cache: PostorderCache::new(), + } + } + + /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`. + #[inline] + pub fn is_cfg_cyclic(&self) -> bool { + self.is_cyclic.is_cyclic(self) + } + + /// Returns predecessors for each basic block. + #[inline] + pub fn predecessors(&self) -> &Predecessors { + self.predecessor_cache.compute(&self.basic_blocks) + } + + /// Returns basic blocks in a postorder. + #[inline] + pub fn postorder(&self) -> &[BasicBlock] { + self.postorder_cache.compute(&self.basic_blocks) + } + + /// `switch_sources()[&(target, switch)]` returns a list of switch + /// values that lead to a `target` block from a `switch` block. + #[inline] + pub fn switch_sources(&self) -> &SwitchSources { + self.switch_source_cache.compute(&self.basic_blocks) + } + + /// Returns mutable reference to basic blocks. Invalidates CFG cache. + #[inline] + pub fn as_mut(&mut self) -> &mut IndexVec> { + self.invalidate_cfg_cache(); + &mut self.basic_blocks + } + + /// Get mutable access to basic blocks without invalidating the CFG cache. + /// + /// By calling this method instead of e.g. [`BasicBlocks::as_mut`] you promise not to change + /// the CFG. This means that + /// + /// 1) The number of basic blocks remains unchanged + /// 2) The set of successors of each terminator remains unchanged. + /// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator + /// kind is not changed. + /// + /// If any of these conditions cannot be upheld, you should call [`BasicBlocks::invalidate_cfg_cache`]. + #[inline] + pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec> { + &mut self.basic_blocks + } + + /// Invalidates cached information about the CFG. + /// + /// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`]. + /// All other methods that allow you to mutate the basic blocks also call this method + /// themselves, thereby avoiding any risk of accidentaly cache invalidation. + pub fn invalidate_cfg_cache(&mut self) { + self.predecessor_cache.invalidate(); + self.switch_source_cache.invalidate(); + self.is_cyclic.invalidate(); + self.postorder_cache.invalidate(); + } +} + +impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> { + type Target = IndexVec>; + + #[inline] + fn deref(&self) -> &IndexVec> { + &self.basic_blocks + } +} + +impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> { + type Node = BasicBlock; +} + +impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> { + #[inline] + fn num_nodes(&self) -> usize { + self.basic_blocks.len() + } +} + +impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> { + #[inline] + fn start_node(&self) -> Self::Node { + START_BLOCK + } +} + +impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> { + #[inline] + fn successors(&self, node: Self::Node) -> >::Iter { + self.basic_blocks[node].terminator().successors() + } +} + +impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> { + type Item = BasicBlock; + type Iter = Successors<'b>; +} + +impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> { + type Item = BasicBlock; + type Iter = std::iter::Copied>; +} + +impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> { + #[inline] + fn predecessors(&self, node: Self::Node) -> >::Iter { + self.predecessors()[node].iter().copied() + } +} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e7d7317456c74..6a0aa247a94e5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -5,7 +5,6 @@ use crate::mir::interpret::{ AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar, }; -use crate::mir::traversal::PostorderCache; use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; @@ -28,7 +27,6 @@ use polonius_engine::Atom; pub use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{dominators, Dominators}; -use rustc_data_structures::graph::{self, GraphSuccessors}; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::{Idx, IndexVec}; use rustc_serialize::{Decodable, Encodable}; @@ -43,11 +41,12 @@ use std::fmt::{self, Debug, Display, Formatter, Write}; use std::ops::{ControlFlow, Index, IndexMut}; use std::{iter, mem}; -use self::graph_cyclic_cache::GraphIsCyclicCache; -use self::predecessors::{PredecessorCache, Predecessors}; +use self::predecessors::Predecessors; pub use self::query::*; -use self::switch_sources::{SwitchSourceCache, SwitchSources}; +use self::switch_sources::SwitchSources; +pub use basic_blocks::BasicBlocks; +mod basic_blocks; pub mod coverage; mod generic_graph; pub mod generic_graphviz; @@ -189,7 +188,7 @@ pub struct GeneratorInfo<'tcx> { pub struct Body<'tcx> { /// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`] /// that indexes into this vector. - basic_blocks: IndexVec>, + pub basic_blocks: BasicBlocks<'tcx>, /// Records how far through the "desugaring and optimization" process this particular /// MIR has traversed. This is particularly useful when inlining, since in that context @@ -257,11 +256,6 @@ pub struct Body<'tcx> { /// potentially allow things like `[u8; std::mem::size_of::() * 0]` due to this. pub is_polymorphic: bool, - predecessor_cache: PredecessorCache, - switch_source_cache: SwitchSourceCache, - is_cyclic: GraphIsCyclicCache, - postorder_cache: PostorderCache, - pub tainted_by_errors: Option, } @@ -289,7 +283,7 @@ impl<'tcx> Body<'tcx> { let mut body = Body { phase: MirPhase::Built, source, - basic_blocks, + basic_blocks: BasicBlocks::new(basic_blocks), source_scopes, generator: generator_kind.map(|generator_kind| { Box::new(GeneratorInfo { @@ -307,10 +301,6 @@ impl<'tcx> Body<'tcx> { span, required_consts: Vec::new(), is_polymorphic: false, - predecessor_cache: PredecessorCache::new(), - switch_source_cache: SwitchSourceCache::new(), - is_cyclic: GraphIsCyclicCache::new(), - postorder_cache: PostorderCache::new(), tainted_by_errors, }; body.is_polymorphic = body.has_param_types_or_consts(); @@ -326,7 +316,7 @@ impl<'tcx> Body<'tcx> { let mut body = Body { phase: MirPhase::Built, source: MirSource::item(CRATE_DEF_ID.to_def_id()), - basic_blocks, + basic_blocks: BasicBlocks::new(basic_blocks), source_scopes: IndexVec::new(), generator: None, local_decls: IndexVec::new(), @@ -337,10 +327,6 @@ impl<'tcx> Body<'tcx> { required_consts: Vec::new(), var_debug_info: Vec::new(), is_polymorphic: false, - predecessor_cache: PredecessorCache::new(), - switch_source_cache: SwitchSourceCache::new(), - is_cyclic: GraphIsCyclicCache::new(), - postorder_cache: PostorderCache::new(), tainted_by_errors: None, }; body.is_polymorphic = body.has_param_types_or_consts(); @@ -354,74 +340,13 @@ impl<'tcx> Body<'tcx> { #[inline] pub fn basic_blocks_mut(&mut self) -> &mut IndexVec> { - // Because the user could mutate basic block terminators via this reference, we need to - // invalidate the caches. - // - // FIXME: Use a finer-grained API for this, so only transformations that alter terminators - // invalidate the caches. - self.invalidate_cfg_cache(); - &mut self.basic_blocks - } - - #[inline] - pub fn basic_blocks_and_local_decls_mut( - &mut self, - ) -> (&mut IndexVec>, &mut LocalDecls<'tcx>) { - self.invalidate_cfg_cache(); - (&mut self.basic_blocks, &mut self.local_decls) - } - - #[inline] - pub fn basic_blocks_local_decls_mut_and_var_debug_info( - &mut self, - ) -> ( - &mut IndexVec>, - &mut LocalDecls<'tcx>, - &mut Vec>, - ) { - self.invalidate_cfg_cache(); - (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info) - } - - /// Get mutable access to parts of the Body without invalidating the CFG cache. - /// - /// By calling this method instead of eg [`Body::basic_blocks_mut`], you promise not to change - /// the CFG. This means that - /// - /// 1) The number of basic blocks remains unchanged - /// 2) The set of successors of each terminator remains unchanged. - /// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator - /// kind is not changed. - /// - /// If any of these conditions cannot be upheld, you should call [`Body::invalidate_cfg_cache`]. - #[inline] - pub fn basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate( - &mut self, - ) -> ( - &mut IndexVec>, - &mut LocalDecls<'tcx>, - &mut Vec>, - ) { - (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info) - } - - /// Invalidates cached information about the CFG. - /// - /// You will only ever need this if you have also called - /// [`Body::basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate`]. All other methods - /// that allow you to mutate the body also call this method themselves, thereby avoiding any - /// risk of accidentaly cache invalidation. - pub fn invalidate_cfg_cache(&mut self) { - self.predecessor_cache.invalidate(); - self.switch_source_cache.invalidate(); - self.is_cyclic.invalidate(); - self.postorder_cache.invalidate(); + self.basic_blocks.as_mut() } /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the /// `START_BLOCK`. pub fn is_cfg_cyclic(&self) -> bool { - self.is_cyclic.is_cyclic(self) + self.basic_blocks.is_cfg_cyclic() } #[inline] @@ -495,14 +420,6 @@ impl<'tcx> Body<'tcx> { self.local_decls.drain(self.arg_count + 1..) } - /// Changes a statement to a nop. This is both faster than deleting instructions and avoids - /// invalidating statement indices in `Location`s. - pub fn make_statement_nop(&mut self, location: Location) { - let block = &mut self.basic_blocks[location.block]; - debug_assert!(location.statement_index < block.statements.len()); - block.statements[location.statement_index].make_nop() - } - /// Returns the source info associated with `location`. pub fn source_info(&self, location: Location) -> &SourceInfo { let block = &self[location.block]; @@ -540,19 +457,19 @@ impl<'tcx> Body<'tcx> { #[inline] pub fn predecessors(&self) -> &Predecessors { - self.predecessor_cache.compute(&self.basic_blocks) + self.basic_blocks.predecessors() } /// `body.switch_sources()[&(target, switch)]` returns a list of switch /// values that lead to a `target` block from a `switch` block. #[inline] pub fn switch_sources(&self) -> &SwitchSources { - self.switch_source_cache.compute(&self.basic_blocks) + self.basic_blocks.switch_sources() } #[inline] pub fn dominators(&self) -> Dominators { - dominators(self) + dominators(&self.basic_blocks) } #[inline] @@ -599,7 +516,7 @@ impl<'tcx> Index for Body<'tcx> { impl<'tcx> IndexMut for Body<'tcx> { #[inline] fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { - &mut self.basic_blocks_mut()[index] + &mut self.basic_blocks.as_mut()[index] } } @@ -2890,48 +2807,6 @@ fn pretty_print_const_value<'tcx>( }) } -impl<'tcx> graph::DirectedGraph for Body<'tcx> { - type Node = BasicBlock; -} - -impl<'tcx> graph::WithNumNodes for Body<'tcx> { - #[inline] - fn num_nodes(&self) -> usize { - self.basic_blocks.len() - } -} - -impl<'tcx> graph::WithStartNode for Body<'tcx> { - #[inline] - fn start_node(&self) -> Self::Node { - START_BLOCK - } -} - -impl<'tcx> graph::WithSuccessors for Body<'tcx> { - #[inline] - fn successors(&self, node: Self::Node) -> >::Iter { - self.basic_blocks[node].terminator().successors() - } -} - -impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { - type Item = BasicBlock; - type Iter = Successors<'b>; -} - -impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> { - type Item = BasicBlock; - type Iter = std::iter::Copied>; -} - -impl<'tcx> graph::WithPredecessors for Body<'tcx> { - #[inline] - fn predecessors(&self, node: Self::Node) -> >::Iter { - self.predecessors()[node].iter().copied() - } -} - /// `Location` represents the position of the start of the statement; or, if /// `statement_index` equals the number of statements, then the start of the /// terminator. diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 30648679daebf..627dc32f37eb5 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -104,22 +104,25 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { /// /// A Postorder traversal of this graph is `D B C A` or `D C B A` pub struct Postorder<'a, 'tcx> { - body: &'a Body<'tcx>, + basic_blocks: &'a IndexVec>, visited: BitSet, visit_stack: Vec<(BasicBlock, Successors<'a>)>, root_is_start_block: bool, } impl<'a, 'tcx> Postorder<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> { + pub fn new( + basic_blocks: &'a IndexVec>, + root: BasicBlock, + ) -> Postorder<'a, 'tcx> { let mut po = Postorder { - body, - visited: BitSet::new_empty(body.basic_blocks().len()), + basic_blocks, + visited: BitSet::new_empty(basic_blocks.len()), visit_stack: Vec::new(), root_is_start_block: root == START_BLOCK, }; - let data = &po.body[root]; + let data = &po.basic_blocks[root]; if let Some(ref term) = data.terminator { po.visited.insert(root); @@ -190,7 +193,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { }; if self.visited.insert(bb) { - if let Some(term) = &self.body[bb].terminator { + if let Some(term) = &self.basic_blocks[bb].terminator { self.visit_stack.push((bb, term.successors())); } } @@ -199,7 +202,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { } pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> { - Postorder::new(body, START_BLOCK) + Postorder::new(&body.basic_blocks, START_BLOCK) } impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { @@ -211,12 +214,12 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { self.traverse_successor(); } - next.map(|(bb, _)| (bb, &self.body[bb])) + next.map(|(bb, _)| (bb, &self.basic_blocks[bb])) } fn size_hint(&self) -> (usize, Option) { // All the blocks, minus the number of blocks we've visited. - let upper = self.body.basic_blocks().len() - self.visited.count(); + let upper = self.basic_blocks.len() - self.visited.count(); let lower = if self.root_is_start_block { // We will visit all remaining blocks exactly once. @@ -263,10 +266,8 @@ pub struct ReversePostorder<'a, 'tcx> { impl<'a, 'tcx> ReversePostorder<'a, 'tcx> { pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> { - let blocks: Vec<_> = Postorder::new(body, root).map(|(bb, _)| bb).collect(); - + let blocks: Vec<_> = Postorder::new(&body.basic_blocks, root).map(|(bb, _)| bb).collect(); let len = blocks.len(); - ReversePostorder { body, blocks, idx: len } } } @@ -334,10 +335,8 @@ impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> { impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {} pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> { - let blocks = body.postorder_cache.compute(body); - + let blocks = body.basic_blocks.postorder(); let len = blocks.len(); - ReversePostorderIter { body, blocks, idx: len } } @@ -360,7 +359,7 @@ impl PostorderCache { /// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR. #[inline] - pub(super) fn compute(&self, body: &Body<'_>) -> &[BasicBlock] { + pub(super) fn compute(&self, body: &IndexVec>) -> &[BasicBlock] { self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect()) } } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 5470cc1262e84..d21a8c4f9b9a3 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -2,7 +2,7 @@ use rustc_data_structures::graph::iterate::{ NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, }; use rustc_hir::intravisit::FnKind; -use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind}; +use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt}; use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; @@ -30,7 +30,9 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { }; let mut vis = Search { tcx, body, reachable_recursive_calls: vec![], trait_substs }; - if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) { + if let Some(NonRecursive) = + TriColorDepthFirstSearch::new(&body.basic_blocks).run_from_start(&mut vis) + { return; } if vis.reachable_recursive_calls.is_empty() { @@ -101,7 +103,7 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> { } } -impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { +impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { type BreakVal = NonRecursive; fn node_examined( diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 0f87e638d2618..5d15f03491d79 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -91,7 +91,8 @@ impl<'tcx> MirPass<'tcx> for AddRetag { super::add_call_guards::AllCallEdges.run_pass(tcx, body); let (span, arg_count) = (body.span, body.arg_count); - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + let basic_blocks = body.basic_blocks.as_mut(); + let local_decls = &body.local_decls; let needs_retag = |place: &Place<'tcx>| { // FIXME: Instead of giving up for unstable places, we should introduce // a temporary and retag on that. diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 510f1e64ed1c0..47f851c97092d 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -80,7 +80,7 @@ impl CoverageGraph { IndexVec, IndexVec>, ) { - let num_basic_blocks = mir_body.num_nodes(); + let num_basic_blocks = mir_body.basic_blocks.len(); let mut bcbs = IndexVec::with_capacity(num_basic_blocks); let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks); diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 82070b903256c..423e78317aadb 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -321,7 +321,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } fn mir_to_initial_sorted_coverage_spans(&self) -> Vec { - let mut initial_spans = Vec::::with_capacity(self.mir_body.num_nodes() * 2); + let mut initial_spans = + Vec::::with_capacity(self.mir_body.basic_blocks.len() * 2); for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() { initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data)); } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 213bb6608e139..6380f03528ae8 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -222,6 +222,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { bb, debug::term_type(&data.terminator().kind), mir_body + .basic_blocks .successors(bb) .map(|successor| { format!(" {:?} -> {:?};", bb, successor) }) .join("\n") diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index c96497abf8f27..9163672f57039 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -66,7 +66,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS return; } - let bbs = body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate().0; + let bbs = body.basic_blocks.as_mut_preserves_cfg(); for Location { block, statement_index } in patch { bbs[block].statements[statement_index].make_nop(); } diff --git a/compiler/rustc_mir_transform/src/deaggregator.rs b/compiler/rustc_mir_transform/src/deaggregator.rs index 01f490e23bfde..b93fe5879f4fd 100644 --- a/compiler/rustc_mir_transform/src/deaggregator.rs +++ b/compiler/rustc_mir_transform/src/deaggregator.rs @@ -11,9 +11,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls, _) = - body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate(); - let local_decls = &*local_decls; + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); for bb in basic_blocks { bb.expand_statements(|stmt| { // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL). @@ -38,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { Some(expand_aggregate( lhs, operands.into_iter().map(|op| { - let ty = op.ty(local_decls, tcx); + let ty = op.ty(&body.local_decls, tcx); (op, ty) }), *kind, diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index a80d2fbd644d4..44e3945d6fc89 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -110,13 +110,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { let patch = MirPatch::new(body); - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + let local_decls = &mut body.local_decls; let mut visitor = ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; for (block, BasicBlockData { statements, terminator, .. }) in - basic_blocks.iter_enumerated_mut() + body.basic_blocks.as_mut().iter_enumerated_mut() { let mut index = 0; for statement in statements { diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index ea10ec5f25c15..2f3c65869ef3b 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -16,9 +16,8 @@ impl<'tcx> MirPass<'tcx> for InstCombine { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - let ctx = InstCombineContext { tcx, local_decls }; - for block in basic_blocks.iter_mut() { + let ctx = InstCombineContext { tcx, local_decls: &body.local_decls }; + for block in body.basic_blocks.as_mut() { for statement in block.statements.iter_mut() { match statement.kind { StatementKind::Assign(box (_place, ref mut rvalue)) => { diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 989b94b68c101..b7ba616510c28 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -11,8 +11,8 @@ pub struct LowerIntrinsics; impl<'tcx> MirPass<'tcx> for LowerIntrinsics { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks { + let local_decls = &body.local_decls; + for block in body.basic_blocks.as_mut() { let terminator = block.terminator.as_mut().unwrap(); if let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 813ab4001a7d8..47848cfa497f3 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -27,12 +27,10 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { }; // The one successor remains unchanged, so no need to invalidate - let (basic_blocks, local_decls, _) = - body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate(); - + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); for block in basic_blocks { // lower `<[_]>::len` calls - lower_slice_len_call(tcx, block, &*local_decls, slice_len_fn_item_def_id); + lower_slice_len_call(tcx, block, &body.local_decls, slice_len_fn_item_def_id); } } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 7cd7d26328a1a..a0ba69c89b048 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -48,7 +48,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { let def_id = body.source.def_id(); let param_env = tcx.param_env(def_id); - let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut(); + let bbs = body.basic_blocks.as_mut(); let mut should_cleanup = false; 'outer: for bb_idx in bbs.indices() { if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) { @@ -108,7 +108,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { // Introduce a temporary for the discriminant value. let source_info = bbs[bb_idx].terminator().source_info; - let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span)); + let discr_local = body.local_decls.push(LocalDecl::new(switch_ty, source_info.span)); // We already checked that first and second are different blocks, // and bb_idx has a different terminator from both of them. diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 3396a446df2c9..c0217a105414b 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -33,8 +33,8 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // We don't ever touch terminators, so no need to invalidate the CFG cache - let (basic_blocks, local_decls, _) = - body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate(); + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); + let local_decls = &mut body.local_decls; // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]` let mut interesting_locals = BitSet::new_empty(local_decls.len()); diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs index 5bb4f8bb9b3c9..dbe082e909371 100644 --- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs +++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs @@ -17,7 +17,7 @@ impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers { } trace!("Running RemoveStorageMarkers on {:?}", body.source); - for data in body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate().0 { + for data in body.basic_blocks.as_mut_preserves_cfg() { data.statements.retain(|statement| match statement.kind { StatementKind::StorageLive(..) | StatementKind::StorageDead(..) diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 921a11a3a06d2..84ccf6e1f61d4 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -20,11 +20,10 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { let param_env = tcx.param_env_reveal_all_normalized(did); let mut should_simplify = false; - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks { + for block in body.basic_blocks.as_mut() { let terminator = block.terminator_mut(); if let TerminatorKind::Drop { place, target, .. } = terminator.kind { - let ty = place.ty(local_decls, tcx); + let ty = place.ty(&body.local_decls, tcx); if ty.ty.needs_drop(tcx, param_env) { continue; } diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 34941c1907df4..40be4f146db98 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -18,9 +18,9 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts { return; } let param_env = tcx.param_env(body.source.def_id()); - let (basic_blocks, local_decls, _) = - body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate(); - for block in basic_blocks.iter_mut() { + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); + let local_decls = &body.local_decls; + for block in basic_blocks { for statement in block.statements.iter_mut() { if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) = statement.kind diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs index 6902213ddad4f..fca9f7eeb2461 100644 --- a/compiler/rustc_mir_transform/src/simplify_try.rs +++ b/compiler/rustc_mir_transform/src/simplify_try.rs @@ -386,14 +386,17 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { trace!("running SimplifyArmIdentity on {:?}", source); let local_uses = LocalUseCounter::get_local_uses(body); - let (basic_blocks, local_decls, debug_info) = - body.basic_blocks_local_decls_mut_and_var_debug_info(); - for bb in basic_blocks { + for bb in body.basic_blocks.as_mut() { if let Some(opt_info) = - get_arm_identity_info(&bb.statements, local_decls.len(), debug_info) + get_arm_identity_info(&bb.statements, body.local_decls.len(), &body.var_debug_info) { trace!("got opt_info = {:#?}", opt_info); - if !optimization_applies(&opt_info, local_decls, &local_uses, &debug_info) { + if !optimization_applies( + &opt_info, + &body.local_decls, + &local_uses, + &body.var_debug_info, + ) { debug!("optimization skipped for {:?}", source); continue; } @@ -431,7 +434,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { // Fix the debug info to point to the right local for dbg_index in opt_info.dbg_info_to_adjust { - let dbg_info = &mut debug_info[dbg_index]; + let dbg_info = &mut body.var_debug_info[dbg_index]; assert!( matches!(dbg_info.value, VarDebugInfoContents::Place(_)), "value was not a Place" From 2446b17745517170aee5707cc75ef3661f365f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 5 Jul 2022 00:00:00 +0000 Subject: [PATCH 17/20] Move `is_cfg_cyclic` from Body to BasicBlocks --- compiler/rustc_middle/src/mir/mod.rs | 6 ------ compiler/rustc_mir_dataflow/src/framework/engine.rs | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 6a0aa247a94e5..cfe8b0bddecff 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -343,12 +343,6 @@ impl<'tcx> Body<'tcx> { self.basic_blocks.as_mut() } - /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the - /// `START_BLOCK`. - pub fn is_cfg_cyclic(&self) -> bool { - self.basic_blocks.is_cfg_cyclic() - } - #[inline] pub fn local_kind(&self, local: Local) -> LocalKind { let index = local.as_usize(); diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 20e14a77c1e57..180376d648a1c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -101,7 +101,7 @@ where // transfer function for each block exactly once (assuming that we process blocks in RPO). // // In this case, there's no need to compute the block transfer functions ahead of time. - if !body.is_cfg_cyclic() { + if !body.basic_blocks.is_cfg_cyclic() { return Self::new(tcx, body, analysis, None); } From 39d9c1cb1fd00c4deab6f3ef2a69886c36670d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 5 Jul 2022 00:00:00 +0000 Subject: [PATCH 18/20] Move `predecessors` from Body to BasicBlocks --- .../rustc_borrowck/src/diagnostics/conflict_errors.rs | 2 +- compiler/rustc_borrowck/src/type_check/liveness/trace.rs | 4 ++-- compiler/rustc_middle/src/mir/mod.rs | 8 +------- compiler/rustc_mir_dataflow/src/framework/direction.rs | 2 +- compiler/rustc_mir_transform/src/add_call_guards.rs | 2 +- compiler/rustc_mir_transform/src/coverage/graph.rs | 2 +- compiler/rustc_mir_transform/src/nrvo.rs | 2 +- compiler/rustc_mir_transform/src/separate_const_switch.rs | 2 +- src/tools/clippy/clippy_lints/src/redundant_clone.rs | 2 +- 9 files changed, 10 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 73c0bf16a1f99..d2a54a646ec6d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1628,7 +1628,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, ) -> impl Iterator + Captures<'tcx> + 'a { if location.statement_index == 0 { - let predecessors = body.predecessors()[location.block].to_vec(); + let predecessors = body.basic_blocks.predecessors()[location.block].to_vec(); Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) } else { Either::Right(std::iter::once(Location { diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index d4e61ec213b60..3795378b56861 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -258,7 +258,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { let block = self.cx.elements.to_location(block_start).block; self.stack.extend( - self.cx.body.predecessors()[block] + self.cx.body.basic_blocks.predecessors()[block] .iter() .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb)) .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)), @@ -354,7 +354,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { } let body = self.cx.body; - for &pred_block in body.predecessors()[block].iter() { + for &pred_block in body.basic_blocks.predecessors()[block].iter() { debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,); // Check whether the variable is (at least partially) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cfe8b0bddecff..9a2c7fa7cc4bc 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -41,7 +41,6 @@ use std::fmt::{self, Debug, Display, Formatter, Write}; use std::ops::{ControlFlow, Index, IndexMut}; use std::{iter, mem}; -use self::predecessors::Predecessors; pub use self::query::*; use self::switch_sources::SwitchSources; pub use basic_blocks::BasicBlocks; @@ -449,11 +448,6 @@ impl<'tcx> Body<'tcx> { .unwrap_or_else(|| Either::Right(block_data.terminator())) } - #[inline] - pub fn predecessors(&self) -> &Predecessors { - self.basic_blocks.predecessors() - } - /// `body.switch_sources()[&(target, switch)]` returns a list of switch /// values that lead to a `target` block from a `switch` block. #[inline] @@ -2837,7 +2831,7 @@ impl Location { return true; } - let predecessors = body.predecessors(); + let predecessors = body.basic_blocks.predecessors(); // If we're in another block, then we want to check that block is a predecessor of `other`. let mut queue: Vec = predecessors[other.block].to_vec(); diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 05a4d7bbf3e6f..5d9bf6194a427 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -228,7 +228,7 @@ impl Direction for Backward { ) where A: Analysis<'tcx>, { - for pred in body.predecessors()[bb].iter().copied() { + for pred in body.basic_blocks.predecessors()[bb].iter().copied() { match body[pred].terminator().kind { // Apply terminator-specific edge effects. // diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index 10d522717344d..f12c8560c0e82 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -39,7 +39,7 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards { impl AddCallGuards { pub fn add_call_guards(&self, body: &mut Body<'_>) { let mut pred_count: IndexVec<_, _> = - body.predecessors().iter().map(|ps| ps.len()).collect(); + body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect(); pred_count[START_BLOCK] += 1; // We need a place to store the new blocks generated diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 47f851c97092d..759ea7cd32820 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -95,7 +95,7 @@ impl CoverageGraph { let mut basic_blocks = Vec::new(); for (bb, data) in mir_cfg_without_unwind { if let Some(last) = basic_blocks.last() { - let predecessors = &mir_body.predecessors()[bb]; + let predecessors = &mir_body.basic_blocks.predecessors()[bb]; if predecessors.len() > 1 || !predecessors.contains(last) { // The `bb` has more than one _incoming_ edge, and should start its own // `BasicCoverageBlockData`. (Note, the `basic_blocks` vector does not yet diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index d29d17399af3a..bb063915f55a9 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -133,7 +133,7 @@ fn find_local_assigned_to_return_place( return local; } - match body.predecessors()[block].as_slice() { + match body.basic_blocks.predecessors()[block].as_slice() { &[pred] => block = pred, _ => return None, } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 33ea1c4ba2f59..194c2794aacb6 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -61,7 +61,7 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { /// Returns the amount of blocks that were duplicated pub fn separate_const_switch(body: &mut Body<'_>) -> usize { let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new(); - let predecessors = body.predecessors(); + let predecessors = body.basic_blocks.predecessors(); 'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() { if let TerminatorKind::SwitchInt { discr: Operand::Copy(switch_place) | Operand::Move(switch_place), diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 6d0b9a0f03fa8..eddca60457574 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // `arg` is a reference as it is `.deref()`ed in the previous block. // Look into the predecessor block and find out the source of deref. - let ps = &mir.predecessors()[bb]; + let ps = &mir.basic_blocks.predecessors()[bb]; if ps.len() != 1 { continue; } From dfa6a7cbde0eb34d7cd7d23a37ca03b9c7568a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 5 Jul 2022 00:00:00 +0000 Subject: [PATCH 19/20] Move `switch_sources` from Body to BasicBlocks --- compiler/rustc_middle/src/mir/mod.rs | 8 -------- compiler/rustc_mir_dataflow/src/framework/direction.rs | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 9a2c7fa7cc4bc..7d14934b0898c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -42,7 +42,6 @@ use std::ops::{ControlFlow, Index, IndexMut}; use std::{iter, mem}; pub use self::query::*; -use self::switch_sources::SwitchSources; pub use basic_blocks::BasicBlocks; mod basic_blocks; @@ -448,13 +447,6 @@ impl<'tcx> Body<'tcx> { .unwrap_or_else(|| Either::Right(block_data.terminator())) } - /// `body.switch_sources()[&(target, switch)]` returns a list of switch - /// values that lead to a `target` block from a `switch` block. - #[inline] - pub fn switch_sources(&self) -> &SwitchSources { - self.basic_blocks.switch_sources() - } - #[inline] pub fn dominators(&self) -> Dominators { dominators(&self.basic_blocks) diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 5d9bf6194a427..5c77f3ea39533 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -316,7 +316,7 @@ where fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { assert!(!self.effects_applied); - let values = &self.body.switch_sources()[&(self.bb, self.pred)]; + let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)]; let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb }); let mut tmp = None; From 17adfeb2b477231515dfcb20a371f9f778969d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 5 Jul 2022 00:00:00 +0000 Subject: [PATCH 20/20] Move `dominators` from Body to BasicBlocks --- compiler/rustc_borrowck/src/invalidation.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 2 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 6 ++++++ compiler/rustc_middle/src/mir/mod.rs | 7 +------ 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 0425c53d9dc3c..721fd3e1c0fde 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -26,7 +26,7 @@ pub(super) fn generate_invalidates<'tcx>( if let Some(all_facts) = all_facts { let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); - let dominators = body.dominators(); + let dominators = body.basic_blocks.dominators(); let mut ig = InvalidationGenerator { all_facts, borrow_set, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 7d6f37340c2bb..338df3c70e340 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -334,7 +334,7 @@ fn do_mir_borrowck<'a, 'tcx>( }; } - let dominators = body.dominators(); + let dominators = body.basic_blocks.dominators(); let mut mbcx = MirBorrowckCtxt { infcx, diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 5c26168b50d65..24da48ead63a2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -15,7 +15,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx: &FunctionCx<'a, 'tcx, Bx>, ) -> BitSet { let mir = fx.mir; - let dominators = mir.dominators(); + let dominators = mir.basic_blocks.dominators(); let locals = mir .local_decls .iter() diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index ec3a818472bd0..78080fcd581f6 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -5,6 +5,7 @@ use crate::mir::traversal::PostorderCache; use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK}; use rustc_data_structures::graph; +use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_index::vec::IndexVec; #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] @@ -34,6 +35,11 @@ impl<'tcx> BasicBlocks<'tcx> { self.is_cyclic.is_cyclic(self) } + #[inline] + pub fn dominators(&self) -> Dominators { + dominators(&self) + } + /// Returns predecessors for each basic block. #[inline] pub fn predecessors(&self) -> &Predecessors { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7d14934b0898c..9368612810198 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -26,7 +26,7 @@ use rustc_target::abi::{Size, VariantIdx}; use polonius_engine::Atom; pub use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::dominators::{dominators, Dominators}; +use rustc_data_structures::graph::dominators::Dominators; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::{Idx, IndexVec}; use rustc_serialize::{Decodable, Encodable}; @@ -447,11 +447,6 @@ impl<'tcx> Body<'tcx> { .unwrap_or_else(|| Either::Right(block_data.terminator())) } - #[inline] - pub fn dominators(&self) -> Dominators { - dominators(&self.basic_blocks) - } - #[inline] pub fn yield_ty(&self) -> Option> { self.generator.as_ref().and_then(|generator| generator.yield_ty)