From 789451b43a068b10b7073b8a3194c1c2128b48b2 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sun, 3 Sep 2023 08:15:25 +0200 Subject: [PATCH] Allow `large_assignments` for Box/Arc/Rc initialization Does the `stop linting in box/arc initialization` task of 83518. --- compiler/rustc_monomorphize/src/collector.rs | 101 ++++++++++++++++-- .../async-await/large_moves.attribute.stderr | 22 +++- .../ui/async-await/large_moves.option.stderr | 22 +++- tests/ui/async-await/large_moves.rs | 18 ++++ 4 files changed, 147 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index bf88360a8c1..77f19423318 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -179,8 +179,8 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, - VtblEntry, + self, AssocKind, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, + TypeVisitableExt, VtblEntry, }; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; @@ -188,6 +188,7 @@ use rustc_session::config::EntryFnType; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::Limit; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; +use rustc_span::symbol::{sym, Ident}; use rustc_target::abi::Size; use std::path::PathBuf; @@ -431,7 +432,7 @@ fn collect_items_rec<'tcx>( hir::InlineAsmOperand::SymFn { anon_const } => { let fn_ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); - visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items); + visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items, &[]); } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { let instance = Instance::mono(tcx, *def_id); @@ -592,6 +593,11 @@ struct MirUsedCollector<'a, 'tcx> { instance: Instance<'tcx>, /// Spans for move size lints already emitted. Helps avoid duplicate lints. move_size_spans: Vec, + /// If true, we should temporarily skip move size checks, because we are + /// processing an operand to a `skip_move_check_fns` function call. + skip_move_size_check: bool, + /// Set of functions for which it is OK to move large data into. + skip_move_check_fns: Vec, } impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { @@ -690,7 +696,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { ) => { let fn_ty = operand.ty(self.body, self.tcx); let fn_ty = self.monomorphize(fn_ty); - visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output); + visit_fn_use( + self.tcx, + fn_ty, + false, + span, + &mut self.output, + &self.skip_move_check_fns, + ); } mir::Rvalue::Cast( mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), @@ -789,7 +802,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.body, tcx); let callee_ty = self.monomorphize(callee_ty); - visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output) + self.skip_move_size_check = visit_fn_use( + self.tcx, + callee_ty, + true, + source, + &mut self.output, + &self.skip_move_check_fns, + ) } mir::TerminatorKind::Drop { ref place, .. } => { let ty = place.ty(self.body, self.tcx).ty; @@ -801,7 +821,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { match *op { mir::InlineAsmOperand::SymFn { ref value } => { let fn_ty = self.monomorphize(value.literal.ty()); - visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); + visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output, &[]); } mir::InlineAsmOperand::SymStatic { def_id } => { let instance = Instance::mono(self.tcx, def_id); @@ -840,12 +860,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { } self.super_terminator(terminator, location); + self.skip_move_size_check = false; } fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { self.super_operand(operand, location); let move_size_limit = self.tcx.move_size_limit().0; - if move_size_limit > 0 { + if move_size_limit > 0 && !self.skip_move_size_check { self.check_move_size(move_size_limit, operand, location); } } @@ -876,8 +897,11 @@ fn visit_fn_use<'tcx>( is_direct_call: bool, source: Span, output: &mut MonoItems<'tcx>, -) { + skip_move_check_fns: &[DefId], +) -> bool { + let mut skip_move_size_check = false; if let ty::FnDef(def_id, args) = *ty.kind() { + skip_move_size_check = skip_move_check_fns.contains(&def_id); let instance = if is_direct_call { ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) } else { @@ -888,6 +912,7 @@ fn visit_fn_use<'tcx>( }; visit_instance_use(tcx, instance, is_direct_call, source, output); } + skip_move_size_check } fn visit_instance_use<'tcx>( @@ -1365,6 +1390,31 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } } +fn add_assoc_fn<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: Option, + fn_ident: Ident, + skip_move_check_fns: &mut Vec, +) { + if let Some(def_id) = def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, fn_ident)) { + skip_move_check_fns.push(def_id); + } +} + +fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option { + for impl_def_id in tcx.inherent_impls(def_id) { + if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind( + tcx, + fn_ident, + AssocKind::Fn, + def_id, + ) { + return Some(new.def_id); + } + } + return None; +} + /// Scans the MIR in order to find function calls, closures, and drop-glue. #[instrument(skip(tcx, output), level = "debug")] fn collect_used_items<'tcx>( @@ -1373,8 +1423,39 @@ fn collect_used_items<'tcx>( output: &mut MonoItems<'tcx>, ) { let body = tcx.instance_mir(instance.def); - MirUsedCollector { tcx, body: &body, output, instance, move_size_spans: vec![] } - .visit_body(&body); + + let mut skip_move_check_fns = vec![]; + if tcx.move_size_limit().0 > 0 { + add_assoc_fn( + tcx, + tcx.lang_items().owned_box(), + Ident::from_str("new"), + &mut skip_move_check_fns, + ); + add_assoc_fn( + tcx, + tcx.get_diagnostic_item(sym::Arc), + Ident::from_str("new"), + &mut skip_move_check_fns, + ); + add_assoc_fn( + tcx, + tcx.get_diagnostic_item(sym::Rc), + Ident::from_str("new"), + &mut skip_move_check_fns, + ); + } + + MirUsedCollector { + tcx, + body: &body, + output, + instance, + move_size_spans: vec![], + skip_move_size_check: false, + skip_move_check_fns, + } + .visit_body(&body); } #[instrument(skip(tcx, output), level = "debug")] diff --git a/tests/ui/async-await/large_moves.attribute.stderr b/tests/ui/async-await/large_moves.attribute.stderr index ef9fd78ffe3..1d1999462ce 100644 --- a/tests/ui/async-await/large_moves.attribute.stderr +++ b/tests/ui/async-await/large_moves.attribute.stderr @@ -1,5 +1,5 @@ error: moving 10024 bytes - --> $DIR/large_moves.rs:19:14 + --> $DIR/large_moves.rs:21:14 | LL | let z = (x, 42); | ^ value moved from here @@ -12,12 +12,28 @@ LL | #![deny(large_assignments)] | ^^^^^^^^^^^^^^^^^ error: moving 10024 bytes - --> $DIR/large_moves.rs:20:13 + --> $DIR/large_moves.rs:22:13 | LL | let a = z.0; | ^^^ value moved from here | = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` -error: aborting due to 2 previous errors +error: moving 9999 bytes + --> $DIR/large_moves.rs:27:13 + | +LL | let _ = NotBox::new([0; 9999]); + | ^^^^^^^^^^^^^^^^^^^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 9999 bytes + --> $DIR/large_moves.rs:41:13 + | +LL | data, + | ^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 4 previous errors diff --git a/tests/ui/async-await/large_moves.option.stderr b/tests/ui/async-await/large_moves.option.stderr index ef9fd78ffe3..1d1999462ce 100644 --- a/tests/ui/async-await/large_moves.option.stderr +++ b/tests/ui/async-await/large_moves.option.stderr @@ -1,5 +1,5 @@ error: moving 10024 bytes - --> $DIR/large_moves.rs:19:14 + --> $DIR/large_moves.rs:21:14 | LL | let z = (x, 42); | ^ value moved from here @@ -12,12 +12,28 @@ LL | #![deny(large_assignments)] | ^^^^^^^^^^^^^^^^^ error: moving 10024 bytes - --> $DIR/large_moves.rs:20:13 + --> $DIR/large_moves.rs:22:13 | LL | let a = z.0; | ^^^ value moved from here | = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` -error: aborting due to 2 previous errors +error: moving 9999 bytes + --> $DIR/large_moves.rs:27:13 + | +LL | let _ = NotBox::new([0; 9999]); + | ^^^^^^^^^^^^^^^^^^^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 9999 bytes + --> $DIR/large_moves.rs:41:13 + | +LL | data, + | ^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 4 previous errors diff --git a/tests/ui/async-await/large_moves.rs b/tests/ui/async-await/large_moves.rs index faf6c66c612..62b12104694 100644 --- a/tests/ui/async-await/large_moves.rs +++ b/tests/ui/async-await/large_moves.rs @@ -9,6 +9,8 @@ // edition:2018 // compile-flags: -Zmir-opt-level=0 +use std::{sync::Arc, rc::Rc}; + fn main() { let x = async { let y = [0; 9999]; @@ -19,8 +21,24 @@ fn main() { let z = (x, 42); //~ ERROR large_assignments let a = z.0; //~ ERROR large_assignments let b = z.1; + let _ = Arc::new([0; 9999]); // OK! + let _ = Box::new([0; 9999]); // OK! + let _ = Rc::new([0; 9999]); // OK! + let _ = NotBox::new([0; 9999]); //~ ERROR large_assignments } async fn thing(y: &[u8]) { dbg!(y); } + +struct NotBox { + data: [u8; 9999], +} + +impl NotBox { + fn new(data: [u8; 9999]) -> Self { + Self { + data, //~ ERROR large_assignments + } + } +}