Skip to content

Commit 28946b3

Browse files
committed
Track span of function in method calls, and use this in #[track_caller]
Fixes #69977 When we parse a chain of method calls like `foo.a().b().c()`, each `MethodCallExpr` gets assigned a span that starts at the beginning of the call chain (`foo`). While this is useful for diagnostics, it means that `Location::caller` will return the same location for every call in a call chain. This PR makes us separately record the span of the function name and arguments for a method call (e.g. `b()` in `foo.a().b().c()`). This `Span` is passed through HIR lowering and MIR building to `TerminatorKind::Call`, where it is used in preference to `Terminator.source_info.span` when determining `Location::caller`. This new span is also useful for diagnostics where we want to emphasize a particular method call - for an example, see #72389 (comment)
1 parent bb86748 commit 28946b3

File tree

42 files changed

+141
-50
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+141
-50
lines changed

src/librustc_ast/ast.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,9 @@ pub enum ExprKind {
11651165
/// and the remaining elements are the rest of the arguments.
11661166
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
11671167
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
1168-
MethodCall(PathSegment, Vec<P<Expr>>),
1168+
/// The `Span` is the span of the function, without the dot and receiver
1169+
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
1170+
MethodCall(PathSegment, Vec<P<Expr>>, Span),
11691171
/// A tuple (e.g., `(a, b, c, d)`).
11701172
Tup(Vec<P<Expr>>),
11711173
/// A binary operation (e.g., `a + b`, `a * b`).

src/librustc_ast/mut_visit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1111,11 +1111,12 @@ pub fn noop_visit_expr<T: MutVisitor>(
11111111
vis.visit_expr(f);
11121112
visit_exprs(args, vis);
11131113
}
1114-
ExprKind::MethodCall(PathSegment { ident, id, args }, exprs) => {
1114+
ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => {
11151115
vis.visit_ident(ident);
11161116
vis.visit_id(id);
11171117
visit_opt(args, |args| vis.visit_generic_args(args));
11181118
visit_exprs(exprs, vis);
1119+
vis.visit_span(span);
11191120
}
11201121
ExprKind::Binary(_binop, lhs, rhs) => {
11211122
vis.visit_expr(lhs);

src/librustc_ast/util/parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
394394
contains_exterior_struct_lit(&x)
395395
}
396396

397-
ast::ExprKind::MethodCall(.., ref exprs) => {
397+
ast::ExprKind::MethodCall(.., ref exprs, _) => {
398398
// X { y: 1 }.bar(...)
399399
contains_exterior_struct_lit(&exprs[0])
400400
}

src/librustc_ast/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
726726
visitor.visit_expr(callee_expression);
727727
walk_list!(visitor, visit_expr, arguments);
728728
}
729-
ExprKind::MethodCall(ref segment, ref arguments) => {
729+
ExprKind::MethodCall(ref segment, ref arguments, _span) => {
730730
visitor.visit_path_segment(expression.span, segment);
731731
walk_list!(visitor, visit_expr, arguments);
732732
}

src/librustc_ast_lowering/expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
3939
let f = self.lower_expr(f);
4040
hir::ExprKind::Call(f, self.lower_exprs(args))
4141
}
42-
ExprKind::MethodCall(ref seg, ref args) => {
42+
ExprKind::MethodCall(ref seg, ref args, span) => {
4343
let hir_seg = self.arena.alloc(self.lower_path_segment(
4444
e.span,
4545
seg,
@@ -50,7 +50,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
5050
None,
5151
));
5252
let args = self.lower_exprs(args);
53-
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
53+
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span)
5454
}
5555
ExprKind::Binary(binop, ref lhs, ref rhs) => {
5656
let binop = self.lower_binop(binop);

src/librustc_ast_pretty/pprust.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,7 @@ impl<'a> State<'a> {
18181818
ast::ExprKind::Call(ref func, ref args) => {
18191819
self.print_expr_call(func, &args[..]);
18201820
}
1821-
ast::ExprKind::MethodCall(ref segment, ref args) => {
1821+
ast::ExprKind::MethodCall(ref segment, ref args, _) => {
18221822
self.print_expr_method_call(segment, &args[..]);
18231823
}
18241824
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {

src/librustc_codegen_ssa/mir/block.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
530530
args: &Vec<mir::Operand<'tcx>>,
531531
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
532532
cleanup: Option<mir::BasicBlock>,
533+
fn_span: Span,
533534
) {
534535
let span = terminator.source_info.span;
535536
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
@@ -634,7 +635,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
634635

635636
if intrinsic == Some("caller_location") {
636637
if let Some((_, target)) = destination.as_ref() {
637-
let location = self.get_caller_location(&mut bx, span);
638+
let location = self.get_caller_location(&mut bx, fn_span);
638639

639640
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
640641
location.val.store(&mut bx, tmp);
@@ -798,7 +799,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
798799
args.len() + 1,
799800
"#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
800801
);
801-
let location = self.get_caller_location(&mut bx, span);
802+
let location = self.get_caller_location(&mut bx, fn_span);
803+
debug!(
804+
"codegen_call_terminator({:?}): location={:?} (fn_span {:?})",
805+
terminator, location, fn_span
806+
);
807+
802808
let last_arg = fn_abi.args.last().unwrap();
803809
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
804810
}
@@ -1016,6 +1022,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10161022
ref destination,
10171023
cleanup,
10181024
from_hir_call: _,
1025+
fn_span,
10191026
} => {
10201027
self.codegen_call_terminator(
10211028
helper,
@@ -1025,6 +1032,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10251032
args,
10261033
destination,
10271034
cleanup,
1035+
fn_span,
10281036
);
10291037
}
10301038
mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Yield { .. } => {

src/librustc_expand/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ impl<'a> ExtCtxt<'a> {
272272
) -> P<ast::Expr> {
273273
args.insert(0, expr);
274274
let segment = ast::PathSegment::from_ident(ident.with_span_pos(span));
275-
self.expr(span, ast::ExprKind::MethodCall(segment, args))
275+
self.expr(span, ast::ExprKind::MethodCall(segment, args, span))
276276
}
277277
pub fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> {
278278
self.expr(b.span, ast::ExprKind::Block(b, None))

src/librustc_hir/hir.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1371,7 +1371,7 @@ pub struct Expr<'hir> {
13711371

13721372
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
13731373
#[cfg(target_arch = "x86_64")]
1374-
rustc_data_structures::static_assert_size!(Expr<'static>, 64);
1374+
rustc_data_structures::static_assert_size!(Expr<'static>, 72);
13751375

13761376
impl Expr<'_> {
13771377
pub fn precedence(&self) -> ExprPrecedence {
@@ -1568,12 +1568,14 @@ pub enum ExprKind<'hir> {
15681568
/// and the remaining elements are the rest of the arguments.
15691569
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
15701570
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
1571+
/// The final `Span` represents the span of the function and arguments
1572+
/// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)`
15711573
///
15721574
/// To resolve the called method to a `DefId`, call [`type_dependent_def_id`] with
15731575
/// the `hir_id` of the `MethodCall` node itself.
15741576
///
15751577
/// [`type_dependent_def_id`]: ../ty/struct.TypeckTables.html#method.type_dependent_def_id
1576-
MethodCall(&'hir PathSegment<'hir>, Span, &'hir [Expr<'hir>]),
1578+
MethodCall(&'hir PathSegment<'hir>, Span, &'hir [Expr<'hir>], Span),
15771579
/// A tuple (e.g., `(a, b, c, d)`).
15781580
Tup(&'hir [Expr<'hir>]),
15791581
/// A binary operation (e.g., `a + b`, `a * b`).

src/librustc_hir/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
10901090
visitor.visit_expr(callee_expression);
10911091
walk_list!(visitor, visit_expr, arguments);
10921092
}
1093-
ExprKind::MethodCall(ref segment, _, arguments) => {
1093+
ExprKind::MethodCall(ref segment, _, arguments, _) => {
10941094
visitor.visit_path_segment(expression.span, segment);
10951095
walk_list!(visitor, visit_expr, arguments);
10961096
}

src/librustc_hir_pretty/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ impl<'a> State<'a> {
12861286
hir::ExprKind::Call(ref func, ref args) => {
12871287
self.print_expr_call(&func, args);
12881288
}
1289-
hir::ExprKind::MethodCall(ref segment, _, ref args) => {
1289+
hir::ExprKind::MethodCall(ref segment, _, ref args, _) => {
12901290
self.print_expr_method_call(segment, args);
12911291
}
12921292
hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
@@ -2469,7 +2469,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
24692469
contains_exterior_struct_lit(&x)
24702470
}
24712471

2472-
hir::ExprKind::MethodCall(.., ref exprs) => {
2472+
hir::ExprKind::MethodCall(.., ref exprs, _) => {
24732473
// `X { y: 1 }.bar(...)`
24742474
contains_exterior_struct_lit(&exprs[0])
24752475
}

src/librustc_infer/infer/error_reporting/need_type_info.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
107107
}
108108

109109
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
110-
if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind {
110+
if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
111111
if call_span == self.target_span
112112
&& Some(self.target)
113113
== self.infcx.in_progress_tables.and_then(|tables| {
@@ -294,7 +294,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
294294
// 3 | let _ = x.sum() as f64;
295295
// | ^^^ cannot infer type for `S`
296296
span
297-
} else if let Some(ExprKind::MethodCall(_, call_span, _)) =
297+
} else if let Some(ExprKind::MethodCall(_, call_span, _, _)) =
298298
local_visitor.found_method_call.map(|e| &e.kind)
299299
{
300300
// Point at the call instead of the whole expression:

src/librustc_lint/array_into_iter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ declare_lint_pass!(
2424
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIntoIter {
2525
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>) {
2626
// We only care about method call expressions.
27-
if let hir::ExprKind::MethodCall(call, span, args) = &expr.kind {
27+
if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
2828
if call.ident.name != sym::into_iter {
2929
return;
3030
}

src/librustc_lint/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1899,7 +1899,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
18991899
}
19001900
}
19011901
}
1902-
} else if let hir::ExprKind::MethodCall(_, _, ref args) = expr.kind {
1902+
} else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
19031903
// Find problematic calls to `MaybeUninit::assume_init`.
19041904
let def_id = cx.tables.type_dependent_def_id(expr.hir_id)?;
19051905
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {

src/librustc_lint/unused.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ trait UnusedDelimLint {
526526
let (args_to_check, ctx) = match *call_or_other {
527527
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
528528
// first "argument" is self (which sometimes needs delims)
529-
MethodCall(_, ref args) => (&args[1..], UnusedDelimsCtx::MethodArg),
529+
MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
530530
// actual catch-all arm
531531
_ => {
532532
return;

src/librustc_middle/mir/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,7 @@ pub enum TerminatorKind<'tcx> {
11311131
/// `true` if this is from a call in HIR rather than from an overloaded
11321132
/// operator. True for overloaded function call.
11331133
from_hir_call: bool,
1134+
fn_span: Span,
11341135
},
11351136

11361137
/// Jump to the target if the condition has the expected value,

src/librustc_middle/mir/type_foldable.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
4242
resume_arg: resume_arg.fold_with(folder),
4343
drop,
4444
},
45-
Call { ref func, ref args, ref destination, cleanup, from_hir_call } => {
45+
Call { ref func, ref args, ref destination, cleanup, from_hir_call, fn_span } => {
4646
let dest =
4747
destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest));
4848

@@ -52,6 +52,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
5252
destination: dest,
5353
cleanup,
5454
from_hir_call,
55+
fn_span,
5556
}
5657
}
5758
Assert { ref cond, expected, ref msg, target, cleanup } => {

src/librustc_middle/mir/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ macro_rules! make_mir_visitor {
492492
destination,
493493
cleanup: _,
494494
from_hir_call: _,
495+
fn_span: _
495496
} => {
496497
self.visit_operand(func, source_location);
497498
for arg in args {

src/librustc_mir/borrow_check/invalidation.rs

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
142142
destination,
143143
cleanup: _,
144144
from_hir_call: _,
145+
fn_span: _,
145146
} => {
146147
self.consume_operand(location, func);
147148
for arg in args {

src/librustc_mir/borrow_check/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
699699
ref destination,
700700
cleanup: _,
701701
from_hir_call: _,
702+
fn_span: _,
702703
} => {
703704
self.consume_operand(loc, (func, span), flow_state);
704705
for arg in args {

src/librustc_mir/dataflow/framework/direction.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ impl Direction for Forward {
467467
propagate(target, exit_state);
468468
}
469469

470-
Call { cleanup, destination, ref func, ref args, from_hir_call: _ } => {
470+
Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => {
471471
if let Some(unwind) = cleanup {
472472
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
473473
propagate(unwind, exit_state);

src/librustc_mir/dataflow/move_paths/builder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
401401
ref destination,
402402
cleanup: _,
403403
from_hir_call: _,
404+
fn_span: _,
404405
} => {
405406
self.gather_operand(func);
406407
for arg in args {

src/librustc_mir/interpret/intrinsics/caller_location.rs

+23-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::convert::TryFrom;
22

33
use rustc_hir::lang_items::PanicLocationLangItem;
4+
use rustc_middle::mir::TerminatorKind;
45
use rustc_middle::ty::subst::Subst;
56
use rustc_span::{Span, Symbol};
67
use rustc_target::abi::LayoutOf;
@@ -14,19 +15,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1415
/// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
1516
/// frame which is not `#[track_caller]`.
1617
crate fn find_closest_untracked_caller_location(&self) -> Span {
17-
self.stack()
18+
let frame = self
19+
.stack()
1820
.iter()
1921
.rev()
2022
// Find first non-`#[track_caller]` frame.
21-
.find(|frame| !frame.instance.def.requires_caller_location(*self.tcx))
23+
.find(|frame| {
24+
debug!(
25+
"find_closest_untracked_caller_location: checking frame {:?}",
26+
frame.instance
27+
);
28+
!frame.instance.def.requires_caller_location(*self.tcx)
29+
})
2230
// Assert that there is always such a frame.
23-
.unwrap()
24-
.current_source_info()
25-
// Assert that the frame we look at is actually executing code currently
26-
// (`current_source_info` is None when we are unwinding and the frame does
27-
// not require cleanup).
28-
.unwrap()
29-
.span
31+
.unwrap();
32+
let loc = frame.loc.unwrap();
33+
let block = &frame.body.basic_blocks()[loc.block];
34+
assert_eq!(block.statements.len(), loc.statement_index);
35+
debug!(
36+
"find_closest_untracked_caller_location:: got terminator {:?} ({:?})",
37+
block.terminator(),
38+
block.terminator().kind
39+
);
40+
if let TerminatorKind::Call { fn_span, .. } = block.terminator().kind {
41+
return fn_span;
42+
}
43+
unreachable!();
3044
}
3145

3246
/// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.

src/librustc_mir/interpret/terminator.rs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
5656
destination,
5757
ref cleanup,
5858
from_hir_call: _from_hir_call,
59+
fn_span: _,
5960
} => {
6061
let old_stack = self.frame_idx();
6162
let old_loc = self.frame().loc;

src/librustc_mir/shim.rs

+2
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ impl CloneShimBuilder<'tcx> {
460460
destination: Some((dest, next)),
461461
cleanup: Some(cleanup),
462462
from_hir_call: true,
463+
fn_span: self.span,
463464
},
464465
false,
465466
);
@@ -788,6 +789,7 @@ fn build_call_shim<'tcx>(
788789
None
789790
},
790791
from_hir_call: true,
792+
fn_span: span,
791793
},
792794
false,
793795
);

src/librustc_mir/transform/promote_consts.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
909909
};
910910

911911
match terminator.kind {
912-
TerminatorKind::Call { mut func, mut args, from_hir_call, .. } => {
912+
TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => {
913913
self.visit_operand(&mut func, loc);
914914
for arg in &mut args {
915915
self.visit_operand(arg, loc);
@@ -925,6 +925,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
925925
cleanup: None,
926926
destination: Some((Place::from(new_temp), new_target)),
927927
from_hir_call,
928+
fn_span,
928929
},
929930
..terminator
930931
};

src/librustc_mir/transform/qualify_min_const_fn.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,14 @@ fn check_terminator(
368368
Err((span, "const fn generators are unstable".into()))
369369
}
370370

371-
TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
371+
TerminatorKind::Call {
372+
func,
373+
args,
374+
from_hir_call: _,
375+
destination: _,
376+
cleanup: _,
377+
fn_span: _,
378+
} => {
372379
let fn_ty = func.ty(body, tcx);
373380
if let ty::FnDef(def_id, _) = fn_ty.kind {
374381
if !crate::const_eval::is_min_const_fn(tcx, def_id) {

0 commit comments

Comments
 (0)