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; 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 }); } } 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/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_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_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/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 72aa790c36357..960e98243ac72 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); } }); @@ -649,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(); } } } 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_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_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_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/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_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 83328093e9fa8..5725c240320ad 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -34,7 +34,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; @@ -906,6 +906,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> { @@ -953,6 +976,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<'_> { @@ -975,6 +1002,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/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 40601bb5aad47..9fc2249b29019 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -520,6 +520,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 diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1cd19c7eaab35..48f441e69d642 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -232,6 +232,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. 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..78080fcd581f6 --- /dev/null +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -0,0 +1,147 @@ +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_data_structures::graph::dominators::{dominators, Dominators}; +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) + } + + #[inline] + pub fn dominators(&self) -> Dominators { + dominators(&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..9368612810198 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}; @@ -27,8 +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::{self, GraphSuccessors}; +use rustc_data_structures::graph::dominators::Dominators; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::{Idx, IndexVec}; use rustc_serialize::{Decodable, Encodable}; @@ -43,11 +41,10 @@ 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}; pub use self::query::*; -use self::switch_sources::{SwitchSourceCache, SwitchSources}; +pub use basic_blocks::BasicBlocks; +mod basic_blocks; pub mod coverage; mod generic_graph; pub mod generic_graphviz; @@ -189,7 +186,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 +254,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 +281,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 +299,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 +314,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 +325,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 +338,7 @@ 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(); - } - - /// 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.as_mut() } #[inline] @@ -495,14 +412,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]; @@ -538,23 +447,6 @@ impl<'tcx> Body<'tcx> { .unwrap_or_else(|| Either::Right(block_data.terminator())) } - #[inline] - pub fn predecessors(&self) -> &Predecessors { - self.predecessor_cache.compute(&self.basic_blocks) - } - - /// `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) - } - - #[inline] - pub fn dominators(&self) -> Dominators { - dominators(self) - } - #[inline] pub fn yield_ty(&self) -> Option> { self.generator.as_ref().and_then(|generator| generator.yield_ty) @@ -599,7 +491,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 +2782,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. @@ -2968,7 +2818,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_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_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 05a4d7bbf3e6f..5c77f3ea39533 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. // @@ -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; 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); } 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, 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/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..759ea7cd32820 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); @@ -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/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/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/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/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/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" 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/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4d33b7a376a23..efa73a79e9973 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1705,8 +1705,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"), @@ -1760,7 +1760,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), } } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 04638aa1af62b..7ec6eb0be6527 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -237,9 +237,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. diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index e62a8bcfba667..796bd7715180c 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1412,7 +1412,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, @@ -1435,7 +1438,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, @@ -1457,7 +1463,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, @@ -1480,7 +1489,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, 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()); +} 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 } +} 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); 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/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; } 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