diff options
| author | bors <bors@rust-lang.org> | 2021-09-23 12:26:51 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-09-23 12:26:51 +0000 |
| commit | 0132f8258ae0fbc4f2b461b28d510222d22aa979 (patch) | |
| tree | 206541cfe0136cc4311907dfc8699f1b4ff57768 /compiler/rustc_codegen_ssa/src | |
| parent | 15d9ba0133ce0b35348e1c8367afe00aec841ffa (diff) | |
| parent | 94b19fac263021dc85133138079d684da547a1e0 (diff) | |
| download | rust-0132f8258ae0fbc4f2b461b28d510222d22aa979.tar.gz rust-0132f8258ae0fbc4f2b461b28d510222d22aa979.zip | |
Auto merge of #87064 - Aaron1011:new-closure-track-caller, r=estebank
Support `#[track_caller]` on closures and generators ## Lang team summary This PR adds support for placing the `#[track_caller]` attribute on closure and generator expressions. This attribute's addition behaves identically (from a users perspective) to the attribute being placed on the method in impl Fn/FnOnce/FnMut for ... generated by compiler. The attribute is currently "double" feature gated -- both `stmt_expr_attributes` (preexisting) and `closure_track_caller` (newly added) must be enabled in order to place these attributes on closures. As the Fn* traits lack a `#[track_caller]` attribute in their definition, caller information does not propagate when invoking closures through dyn Fn*. There is no limitation that this PR adds in supporting this; it can be added in the future. # Implementation details This is implemented in the same way as for functions - an extra location argument is appended to the end of the ABI. For closures, this argument is *not* part of the 'tupled' argument storing the parameters - the final closure argument for `#[track_caller]` closures is no longer a tuple. For direct (monomorphized) calls, the necessary support was already implemented - we just needeed to adjust some assertions around checking the ABI and argument count to take closures into account. For calls through a trait object, more work was needed. When creating a `ReifyShim`, we need to create a shim for the trait method (e.g. `FnOnce::call_mut`) - unlike normal functions, closures are never invoked directly, and always go through a trait method. Additional handling was needed for `InstanceDef::ClosureOnceShim`. In order to pass location information throgh a direct (monomorphized) call to `FnOnce::call_once` on an `FnMut` closure, we need to make `ClosureOnceShim` aware of `#[tracked_caller]`. A new field `track_caller` is added to `ClosureOnceShim` - this is used by `InstanceDef::requires_caller` location, allowing codegen to pass through the extra location argument. Since `ClosureOnceShim.track_caller` is only used by codegen, we end up generating two identical MIR shims - one for `track_caller == true`, and one for `track_caller == false`. However, these two shims are used by the entire crate (i.e. it's two shims total, not two shims per unique closure), so this shouldn't a big deal.
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/block.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/mod.rs | 18 |
2 files changed, 30 insertions, 7 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 4be050fb88c..5aa2a422133 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -777,22 +777,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_argument(&mut bx, op, &mut llargs, &fn_abi.args[i]); } - if let Some(tup) = untuple { + let num_untupled = untuple.map(|tup| { self.codegen_arguments_untupled( &mut bx, tup, &mut llargs, &fn_abi.args[first_args.len()..], ) - } + }); let needs_location = instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx())); if needs_location { + let mir_args = if let Some(num_untupled) = num_untupled { + first_args.len() + num_untupled + } else { + args.len() + }; assert_eq!( fn_abi.args.len(), - args.len() + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + mir_args + 1, + "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {:?} {:?} {:?}", + instance, + fn_span, + fn_abi, ); let location = self.get_caller_location(&mut bx, mir::SourceInfo { span: fn_span, ..source_info }); @@ -1122,7 +1130,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { operand: &mir::Operand<'tcx>, llargs: &mut Vec<Bx::Value>, args: &[ArgAbi<'tcx, Ty<'tcx>>], - ) { + ) -> usize { let tuple = self.codegen_operand(bx, operand); // Handle both by-ref and immediate tuples. @@ -1142,6 +1150,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_argument(bx, op, llargs, &args[i]); } } + tuple.layout.fields.count() } fn get_caller_location( diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 37f5de309ba..476ddbd9398 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -258,6 +258,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut idx = 0; let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize; + let mut num_untupled = None; + let args = mir .args_iter() .enumerate() @@ -286,6 +288,11 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let pr_field = place.project_field(bx, i); bx.store_fn_arg(arg, &mut llarg_idx, pr_field); } + assert_eq!( + None, + num_untupled.replace(tupled_arg_tys.len()), + "Replaced existing num_tupled" + ); return LocalRef::Place(place); } @@ -362,10 +369,17 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( .collect::<Vec<_>>(); if fx.instance.def.requires_caller_location(bx.tcx()) { + let mir_args = if let Some(num_untupled) = num_untupled { + // Subtract off the tupled argument that gets 'expanded' + args.len() - 1 + num_untupled + } else { + args.len() + }; assert_eq!( fx.fn_abi.args.len(), - args.len() + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + mir_args + 1, + "#[track_caller] instance {:?} must have 1 more argument in their ABI than in their MIR", + fx.instance ); let arg = fx.fn_abi.args.last().unwrap(); |
