1
Fork 0

Auto merge of #116520 - Enselic:large-copy-into-fn, r=oli-obk

large_assignments: Lint on specific large args passed to functions

Requires lowering function call arg spans down to MIR, which is done in the second commit.

Part of #83518

Also see
* https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/arg.20Spans.20for.20TerminatorKind.3A.3ACall.3F
* https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/move_size_limit.20lint

r? `@oli-obk` (E-mentor)
This commit is contained in:
bors 2024-01-16 19:33:14 +00:00
commit 92f2e0aa62
52 changed files with 379 additions and 210 deletions

View file

@ -785,7 +785,7 @@ impl<'tcx> TerminatorKind<'tcx> {
Call { func, args, destination, .. } => {
write!(fmt, "{destination:?} = ")?;
write!(fmt, "{func:?}(")?;
for (index, arg) in args.iter().enumerate() {
for (index, arg) in args.iter().map(|a| &a.node).enumerate() {
if index > 0 {
write!(fmt, ", ")?;
}

View file

@ -16,6 +16,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::def_id::DefId;
use rustc_hir::{self, CoroutineKind};
use rustc_index::IndexVec;
use rustc_span::source_map::Spanned;
use rustc_target::abi::{FieldIdx, VariantIdx};
use rustc_ast::Mutability;
@ -673,7 +674,9 @@ pub enum TerminatorKind<'tcx> {
/// These are owned by the callee, which is free to modify them.
/// This allows the memory occupied by "by-value" arguments to be
/// reused across function calls without duplicating the contents.
args: Vec<Operand<'tcx>>,
/// The span for each arg is also included
/// (e.g. `a` and `b` in `x.foo(a, b)`).
args: Vec<Spanned<Operand<'tcx>>>,
/// Where the returned value will be written
destination: Place<'tcx>,
/// Where to go after this call returns. If none, the call necessarily diverges.

View file

@ -229,6 +229,18 @@ impl<'tcx> Operand<'tcx> {
Operand::Constant(c) => c.const_.ty(),
}
}
pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span
where
D: HasLocalDecls<'tcx>,
{
match self {
&Operand::Copy(ref l) | &Operand::Move(ref l) => {
local_decls.local_decls()[l.local].source_info.span
}
Operand::Constant(c) => c.span,
}
}
}
impl<'tcx> BinOp {

View file

@ -524,7 +524,7 @@ macro_rules! make_mir_visitor {
} => {
self.visit_operand(func, location);
for arg in args {
self.visit_operand(arg, location);
self.visit_operand(&$($mutability)? arg.node, location);
}
self.visit_place(
destination,

View file

@ -9,6 +9,7 @@ use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_hir::def::Namespace;
use rustc_span::source_map::Spanned;
use rustc_target::abi::TyAndLayout;
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx};
@ -819,3 +820,27 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for TyAndLayout<'tcx, Ty<'tcx>> {
visitor.visit_ty(self.ty)
}
}
impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>> + Debug + Clone> TypeVisitable<TyCtxt<'tcx>>
for Spanned<T>
{
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.node.visit_with(visitor)?;
self.span.visit_with(visitor)?;
ControlFlow::Continue(())
}
}
impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Debug + Clone> TypeFoldable<TyCtxt<'tcx>>
for Spanned<T>
{
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
Ok(Spanned {
node: self.node.try_fold_with(folder)?,
span: self.span.try_fold_with(folder)?,
})
}
}

View file

@ -2,6 +2,7 @@ use crate::mir::*;
use crate::ty::GenericArgsRef;
use crate::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_span::source_map::Spanned;
/// Checks if the specified `local` is used as the `self` parameter of a method call
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
@ -23,7 +24,13 @@ pub fn find_self_call<'tcx>(
tcx.opt_associated_item(def_id)
{
debug!("find_self_call: args={:?}", fn_args);
if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
if let [
Spanned {
node: Operand::Move(self_place) | Operand::Copy(self_place), ..
},
..,
] = **args
{
if self_place.as_local() == Some(local) {
return Some((def_id, fn_args));
}