Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow large_assignments for Box/Arc/Rc initialization #115492

Merged
merged 1 commit into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 91 additions & 10 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,16 @@ 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};
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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<Span>,
/// 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<DefId>,
}

impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
Expand Down Expand Up @@ -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(_)),
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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>(
Expand Down Expand Up @@ -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<DefId>,
fn_ident: Ident,
skip_move_check_fns: &mut Vec<DefId>,
) {
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<DefId> {
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>(
Expand All @@ -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")]
Expand Down
22 changes: 19 additions & 3 deletions tests/ui/async-await/large_moves.attribute.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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

22 changes: 19 additions & 3 deletions tests/ui/async-await/large_moves.option.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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

18 changes: 18 additions & 0 deletions tests/ui/async-await/large_moves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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
}
}
}
Loading