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 https://github.com/rust-lang/rust/pull/72389#discussion_r436035990
This commit is contained in:
parent
bb8674837a
commit
28946b3486
@ -1165,7 +1165,9 @@ pub enum ExprKind {
|
||||
/// and the remaining elements are the rest of the arguments.
|
||||
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
||||
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
|
||||
MethodCall(PathSegment, Vec<P<Expr>>),
|
||||
/// The `Span` is the span of the function, without the dot and receiver
|
||||
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
|
||||
MethodCall(PathSegment, Vec<P<Expr>>, Span),
|
||||
/// A tuple (e.g., `(a, b, c, d)`).
|
||||
Tup(Vec<P<Expr>>),
|
||||
/// A binary operation (e.g., `a + b`, `a * b`).
|
||||
|
@ -1111,11 +1111,12 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
vis.visit_expr(f);
|
||||
visit_exprs(args, vis);
|
||||
}
|
||||
ExprKind::MethodCall(PathSegment { ident, id, args }, exprs) => {
|
||||
ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => {
|
||||
vis.visit_ident(ident);
|
||||
vis.visit_id(id);
|
||||
visit_opt(args, |args| vis.visit_generic_args(args));
|
||||
visit_exprs(exprs, vis);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::Binary(_binop, lhs, rhs) => {
|
||||
vis.visit_expr(lhs);
|
||||
|
@ -394,7 +394,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
|
||||
contains_exterior_struct_lit(&x)
|
||||
}
|
||||
|
||||
ast::ExprKind::MethodCall(.., ref exprs) => {
|
||||
ast::ExprKind::MethodCall(.., ref exprs, _) => {
|
||||
// X { y: 1 }.bar(...)
|
||||
contains_exterior_struct_lit(&exprs[0])
|
||||
}
|
||||
|
@ -726,7 +726,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
visitor.visit_expr(callee_expression);
|
||||
walk_list!(visitor, visit_expr, arguments);
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ref arguments) => {
|
||||
ExprKind::MethodCall(ref segment, ref arguments, _span) => {
|
||||
visitor.visit_path_segment(expression.span, segment);
|
||||
walk_list!(visitor, visit_expr, arguments);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let f = self.lower_expr(f);
|
||||
hir::ExprKind::Call(f, self.lower_exprs(args))
|
||||
}
|
||||
ExprKind::MethodCall(ref seg, ref args) => {
|
||||
ExprKind::MethodCall(ref seg, ref args, span) => {
|
||||
let hir_seg = self.arena.alloc(self.lower_path_segment(
|
||||
e.span,
|
||||
seg,
|
||||
@ -50,7 +50,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
None,
|
||||
));
|
||||
let args = self.lower_exprs(args);
|
||||
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
|
||||
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span)
|
||||
}
|
||||
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
||||
let binop = self.lower_binop(binop);
|
||||
|
@ -1818,7 +1818,7 @@ impl<'a> State<'a> {
|
||||
ast::ExprKind::Call(ref func, ref args) => {
|
||||
self.print_expr_call(func, &args[..]);
|
||||
}
|
||||
ast::ExprKind::MethodCall(ref segment, ref args) => {
|
||||
ast::ExprKind::MethodCall(ref segment, ref args, _) => {
|
||||
self.print_expr_method_call(segment, &args[..]);
|
||||
}
|
||||
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
|
||||
|
@ -530,6 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
args: &Vec<mir::Operand<'tcx>>,
|
||||
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
|
||||
cleanup: Option<mir::BasicBlock>,
|
||||
fn_span: Span,
|
||||
) {
|
||||
let span = terminator.source_info.span;
|
||||
// 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> {
|
||||
|
||||
if intrinsic == Some("caller_location") {
|
||||
if let Some((_, target)) = destination.as_ref() {
|
||||
let location = self.get_caller_location(&mut bx, span);
|
||||
let location = self.get_caller_location(&mut bx, fn_span);
|
||||
|
||||
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
|
||||
location.val.store(&mut bx, tmp);
|
||||
@ -798,7 +799,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
args.len() + 1,
|
||||
"#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
|
||||
);
|
||||
let location = self.get_caller_location(&mut bx, span);
|
||||
let location = self.get_caller_location(&mut bx, fn_span);
|
||||
debug!(
|
||||
"codegen_call_terminator({:?}): location={:?} (fn_span {:?})",
|
||||
terminator, location, fn_span
|
||||
);
|
||||
|
||||
let last_arg = fn_abi.args.last().unwrap();
|
||||
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
|
||||
}
|
||||
@ -1016,6 +1022,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
ref destination,
|
||||
cleanup,
|
||||
from_hir_call: _,
|
||||
fn_span,
|
||||
} => {
|
||||
self.codegen_call_terminator(
|
||||
helper,
|
||||
@ -1025,6 +1032,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
args,
|
||||
destination,
|
||||
cleanup,
|
||||
fn_span,
|
||||
);
|
||||
}
|
||||
mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Yield { .. } => {
|
||||
|
@ -272,7 +272,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
) -> P<ast::Expr> {
|
||||
args.insert(0, expr);
|
||||
let segment = ast::PathSegment::from_ident(ident.with_span_pos(span));
|
||||
self.expr(span, ast::ExprKind::MethodCall(segment, args))
|
||||
self.expr(span, ast::ExprKind::MethodCall(segment, args, span))
|
||||
}
|
||||
pub fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> {
|
||||
self.expr(b.span, ast::ExprKind::Block(b, None))
|
||||
|
@ -1371,7 +1371,7 @@ pub struct Expr<'hir> {
|
||||
|
||||
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
rustc_data_structures::static_assert_size!(Expr<'static>, 64);
|
||||
rustc_data_structures::static_assert_size!(Expr<'static>, 72);
|
||||
|
||||
impl Expr<'_> {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
@ -1568,12 +1568,14 @@ pub enum ExprKind<'hir> {
|
||||
/// and the remaining elements are the rest of the arguments.
|
||||
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
||||
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
|
||||
/// The final `Span` represents the span of the function and arguments
|
||||
/// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)`
|
||||
///
|
||||
/// To resolve the called method to a `DefId`, call [`type_dependent_def_id`] with
|
||||
/// the `hir_id` of the `MethodCall` node itself.
|
||||
///
|
||||
/// [`type_dependent_def_id`]: ../ty/struct.TypeckTables.html#method.type_dependent_def_id
|
||||
MethodCall(&'hir PathSegment<'hir>, Span, &'hir [Expr<'hir>]),
|
||||
MethodCall(&'hir PathSegment<'hir>, Span, &'hir [Expr<'hir>], Span),
|
||||
/// A tuple (e.g., `(a, b, c, d)`).
|
||||
Tup(&'hir [Expr<'hir>]),
|
||||
/// A binary operation (e.g., `a + b`, `a * b`).
|
||||
|
@ -1090,7 +1090,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||
visitor.visit_expr(callee_expression);
|
||||
walk_list!(visitor, visit_expr, arguments);
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, _, arguments) => {
|
||||
ExprKind::MethodCall(ref segment, _, arguments, _) => {
|
||||
visitor.visit_path_segment(expression.span, segment);
|
||||
walk_list!(visitor, visit_expr, arguments);
|
||||
}
|
||||
|
@ -1286,7 +1286,7 @@ impl<'a> State<'a> {
|
||||
hir::ExprKind::Call(ref func, ref args) => {
|
||||
self.print_expr_call(&func, args);
|
||||
}
|
||||
hir::ExprKind::MethodCall(ref segment, _, ref args) => {
|
||||
hir::ExprKind::MethodCall(ref segment, _, ref args, _) => {
|
||||
self.print_expr_method_call(segment, args);
|
||||
}
|
||||
hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
|
||||
@ -2469,7 +2469,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
|
||||
contains_exterior_struct_lit(&x)
|
||||
}
|
||||
|
||||
hir::ExprKind::MethodCall(.., ref exprs) => {
|
||||
hir::ExprKind::MethodCall(.., ref exprs, _) => {
|
||||
// `X { y: 1 }.bar(...)`
|
||||
contains_exterior_struct_lit(&exprs[0])
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind {
|
||||
if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
|
||||
if call_span == self.target_span
|
||||
&& Some(self.target)
|
||||
== self.infcx.in_progress_tables.and_then(|tables| {
|
||||
@ -294,7 +294,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// 3 | let _ = x.sum() as f64;
|
||||
// | ^^^ cannot infer type for `S`
|
||||
span
|
||||
} else if let Some(ExprKind::MethodCall(_, call_span, _)) =
|
||||
} else if let Some(ExprKind::MethodCall(_, call_span, _, _)) =
|
||||
local_visitor.found_method_call.map(|e| &e.kind)
|
||||
{
|
||||
// Point at the call instead of the whole expression:
|
||||
|
@ -24,7 +24,7 @@ declare_lint_pass!(
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIntoIter {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
// We only care about method call expressions.
|
||||
if let hir::ExprKind::MethodCall(call, span, args) = &expr.kind {
|
||||
if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
|
||||
if call.ident.name != sym::into_iter {
|
||||
return;
|
||||
}
|
||||
|
@ -1899,7 +1899,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let hir::ExprKind::MethodCall(_, _, ref args) = expr.kind {
|
||||
} else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
|
||||
// Find problematic calls to `MaybeUninit::assume_init`.
|
||||
let def_id = cx.tables.type_dependent_def_id(expr.hir_id)?;
|
||||
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
|
||||
|
@ -526,7 +526,7 @@ trait UnusedDelimLint {
|
||||
let (args_to_check, ctx) = match *call_or_other {
|
||||
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
|
||||
// first "argument" is self (which sometimes needs delims)
|
||||
MethodCall(_, ref args) => (&args[1..], UnusedDelimsCtx::MethodArg),
|
||||
MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
|
||||
// actual catch-all arm
|
||||
_ => {
|
||||
return;
|
||||
|
@ -1131,6 +1131,7 @@ pub enum TerminatorKind<'tcx> {
|
||||
/// `true` if this is from a call in HIR rather than from an overloaded
|
||||
/// operator. True for overloaded function call.
|
||||
from_hir_call: bool,
|
||||
fn_span: Span,
|
||||
},
|
||||
|
||||
/// Jump to the target if the condition has the expected value,
|
||||
|
@ -42,7 +42,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
||||
resume_arg: resume_arg.fold_with(folder),
|
||||
drop,
|
||||
},
|
||||
Call { ref func, ref args, ref destination, cleanup, from_hir_call } => {
|
||||
Call { ref func, ref args, ref destination, cleanup, from_hir_call, fn_span } => {
|
||||
let dest =
|
||||
destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest));
|
||||
|
||||
@ -52,6 +52,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
||||
destination: dest,
|
||||
cleanup,
|
||||
from_hir_call,
|
||||
fn_span,
|
||||
}
|
||||
}
|
||||
Assert { ref cond, expected, ref msg, target, cleanup } => {
|
||||
|
@ -492,6 +492,7 @@ macro_rules! make_mir_visitor {
|
||||
destination,
|
||||
cleanup: _,
|
||||
from_hir_call: _,
|
||||
fn_span: _
|
||||
} => {
|
||||
self.visit_operand(func, source_location);
|
||||
for arg in args {
|
||||
|
@ -142,6 +142,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
destination,
|
||||
cleanup: _,
|
||||
from_hir_call: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
self.consume_operand(location, func);
|
||||
for arg in args {
|
||||
|
@ -699,6 +699,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
|
||||
ref destination,
|
||||
cleanup: _,
|
||||
from_hir_call: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
self.consume_operand(loc, (func, span), flow_state);
|
||||
for arg in args {
|
||||
|
@ -467,7 +467,7 @@ impl Direction for Forward {
|
||||
propagate(target, exit_state);
|
||||
}
|
||||
|
||||
Call { cleanup, destination, ref func, ref args, from_hir_call: _ } => {
|
||||
Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => {
|
||||
if let Some(unwind) = cleanup {
|
||||
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
|
||||
propagate(unwind, exit_state);
|
||||
|
@ -401,6 +401,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
ref destination,
|
||||
cleanup: _,
|
||||
from_hir_call: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
self.gather_operand(func);
|
||||
for arg in args {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use rustc_hir::lang_items::PanicLocationLangItem;
|
||||
use rustc_middle::mir::TerminatorKind;
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::abi::LayoutOf;
|
||||
@ -14,19 +15,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
|
||||
/// frame which is not `#[track_caller]`.
|
||||
crate fn find_closest_untracked_caller_location(&self) -> Span {
|
||||
self.stack()
|
||||
let frame = self
|
||||
.stack()
|
||||
.iter()
|
||||
.rev()
|
||||
// Find first non-`#[track_caller]` frame.
|
||||
.find(|frame| !frame.instance.def.requires_caller_location(*self.tcx))
|
||||
.find(|frame| {
|
||||
debug!(
|
||||
"find_closest_untracked_caller_location: checking frame {:?}",
|
||||
frame.instance
|
||||
);
|
||||
!frame.instance.def.requires_caller_location(*self.tcx)
|
||||
})
|
||||
// Assert that there is always such a frame.
|
||||
.unwrap()
|
||||
.current_source_info()
|
||||
// Assert that the frame we look at is actually executing code currently
|
||||
// (`current_source_info` is None when we are unwinding and the frame does
|
||||
// not require cleanup).
|
||||
.unwrap()
|
||||
.span
|
||||
.unwrap();
|
||||
let loc = frame.loc.unwrap();
|
||||
let block = &frame.body.basic_blocks()[loc.block];
|
||||
assert_eq!(block.statements.len(), loc.statement_index);
|
||||
debug!(
|
||||
"find_closest_untracked_caller_location:: got terminator {:?} ({:?})",
|
||||
block.terminator(),
|
||||
block.terminator().kind
|
||||
);
|
||||
if let TerminatorKind::Call { fn_span, .. } = block.terminator().kind {
|
||||
return fn_span;
|
||||
}
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
/// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
|
||||
|
@ -56,6 +56,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
destination,
|
||||
ref cleanup,
|
||||
from_hir_call: _from_hir_call,
|
||||
fn_span: _,
|
||||
} => {
|
||||
let old_stack = self.frame_idx();
|
||||
let old_loc = self.frame().loc;
|
||||
|
@ -460,6 +460,7 @@ impl CloneShimBuilder<'tcx> {
|
||||
destination: Some((dest, next)),
|
||||
cleanup: Some(cleanup),
|
||||
from_hir_call: true,
|
||||
fn_span: self.span,
|
||||
},
|
||||
false,
|
||||
);
|
||||
@ -788,6 +789,7 @@ fn build_call_shim<'tcx>(
|
||||
None
|
||||
},
|
||||
from_hir_call: true,
|
||||
fn_span: span,
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
@ -909,7 +909,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
};
|
||||
|
||||
match terminator.kind {
|
||||
TerminatorKind::Call { mut func, mut args, from_hir_call, .. } => {
|
||||
TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => {
|
||||
self.visit_operand(&mut func, loc);
|
||||
for arg in &mut args {
|
||||
self.visit_operand(arg, loc);
|
||||
@ -925,6 +925,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
cleanup: None,
|
||||
destination: Some((Place::from(new_temp), new_target)),
|
||||
from_hir_call,
|
||||
fn_span,
|
||||
},
|
||||
..terminator
|
||||
};
|
||||
|
@ -368,7 +368,14 @@ fn check_terminator(
|
||||
Err((span, "const fn generators are unstable".into()))
|
||||
}
|
||||
|
||||
TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
|
||||
TerminatorKind::Call {
|
||||
func,
|
||||
args,
|
||||
from_hir_call: _,
|
||||
destination: _,
|
||||
cleanup: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
let fn_ty = func.ty(body, tcx);
|
||||
if let ty::FnDef(def_id, _) = fn_ty.kind {
|
||||
if !crate::const_eval::is_min_const_fn(tcx, def_id) {
|
||||
|
@ -644,6 +644,7 @@ where
|
||||
destination: Some((unit_temp, succ)),
|
||||
cleanup: unwind.into_option(),
|
||||
from_hir_call: true,
|
||||
fn_span: self.source_info.span,
|
||||
},
|
||||
source_info: self.source_info,
|
||||
}),
|
||||
@ -988,6 +989,7 @@ where
|
||||
destination: Some((unit_temp, target)),
|
||||
cleanup: None,
|
||||
from_hir_call: false,
|
||||
fn_span: self.source_info.span,
|
||||
}; // FIXME(#43234)
|
||||
let free_block = self.new_block(unwind, call);
|
||||
|
||||
|
@ -162,7 +162,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
});
|
||||
exit_block.unit()
|
||||
}
|
||||
ExprKind::Call { ty, fun, args, from_hir_call } => {
|
||||
ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => {
|
||||
let intrinsic = match ty.kind {
|
||||
ty::FnDef(def_id, _) => {
|
||||
let f = ty.fn_sig(this.hir.tcx());
|
||||
@ -206,6 +206,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
this.record_operands_moved(&args);
|
||||
|
||||
debug!("into_expr: fn_span={:?}", fn_span);
|
||||
|
||||
this.cfg.terminate(
|
||||
block,
|
||||
source_info,
|
||||
@ -222,6 +224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
Some((destination, success))
|
||||
},
|
||||
from_hir_call,
|
||||
fn_span
|
||||
},
|
||||
);
|
||||
success.unit()
|
||||
|
@ -443,6 +443,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
destination: Some((eq_result, eq_block)),
|
||||
cleanup: Some(cleanup),
|
||||
from_hir_call: false,
|
||||
fn_span: source_info.span
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -139,11 +139,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||
|
||||
let kind = match expr.kind {
|
||||
// Here comes the interesting stuff:
|
||||
hir::ExprKind::MethodCall(_, method_span, ref args) => {
|
||||
hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => {
|
||||
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
|
||||
let expr = method_callee(cx, expr, method_span, None);
|
||||
let args = args.iter().map(|e| e.to_ref()).collect();
|
||||
ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args, from_hir_call: true }
|
||||
ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args, from_hir_call: true, fn_span }
|
||||
}
|
||||
|
||||
hir::ExprKind::Call(ref fun, ref args) => {
|
||||
@ -170,6 +170,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||
fun: method.to_ref(),
|
||||
args: vec![fun.to_ref(), tupled_args.to_ref()],
|
||||
from_hir_call: true,
|
||||
fn_span: expr.span,
|
||||
}
|
||||
} else {
|
||||
let adt_data =
|
||||
@ -215,6 +216,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||
fun: fun.to_ref(),
|
||||
args: args.to_ref(),
|
||||
from_hir_call: true,
|
||||
fn_span: expr.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1024,7 +1026,7 @@ fn overloaded_operator<'a, 'tcx>(
|
||||
args: Vec<ExprRef<'tcx>>,
|
||||
) -> ExprKind<'tcx> {
|
||||
let fun = method_callee(cx, expr, expr.span, None);
|
||||
ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false }
|
||||
ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false, fn_span: expr.span }
|
||||
}
|
||||
|
||||
fn overloaded_place<'a, 'tcx>(
|
||||
@ -1060,7 +1062,13 @@ fn overloaded_place<'a, 'tcx>(
|
||||
temp_lifetime,
|
||||
ty: ref_ty,
|
||||
span: expr.span,
|
||||
kind: ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false },
|
||||
kind: ExprKind::Call {
|
||||
ty: fun.ty,
|
||||
fun: fun.to_ref(),
|
||||
args,
|
||||
from_hir_call: false,
|
||||
fn_span: expr.span,
|
||||
},
|
||||
};
|
||||
|
||||
// construct and return a deref wrapper `*foo()`
|
||||
|
@ -146,6 +146,7 @@ crate enum ExprKind<'tcx> {
|
||||
// Whether this is from a call in HIR, rather than from an overloaded
|
||||
// operator. True for overloaded function call.
|
||||
from_hir_call: bool,
|
||||
fn_span: Span,
|
||||
},
|
||||
Deref {
|
||||
arg: ExprRef<'tcx>,
|
||||
|
@ -639,7 +639,7 @@ impl<'a> Parser<'a> {
|
||||
ExprKind::Index(_, _) => "indexing",
|
||||
ExprKind::Try(_) => "?",
|
||||
ExprKind::Field(_, _) => "a field access",
|
||||
ExprKind::MethodCall(_, _) => "a method call",
|
||||
ExprKind::MethodCall(_, _, _) => "a method call",
|
||||
ExprKind::Call(_, _) => "a function call",
|
||||
ExprKind::Await(_) => "`.await`",
|
||||
ExprKind::Err => return Ok(with_postfix),
|
||||
@ -865,6 +865,7 @@ impl<'a> Parser<'a> {
|
||||
return self.mk_await_expr(self_arg, lo);
|
||||
}
|
||||
|
||||
let fn_span_lo = self.token.span;
|
||||
let segment = self.parse_path_segment(PathStyle::Expr)?;
|
||||
self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
|
||||
|
||||
@ -873,8 +874,9 @@ impl<'a> Parser<'a> {
|
||||
let mut args = self.parse_paren_expr_seq()?;
|
||||
args.insert(0, self_arg);
|
||||
|
||||
let fn_span = fn_span_lo.to(self.prev_token.span);
|
||||
let span = lo.to(self.prev_token.span);
|
||||
Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new()))
|
||||
Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new()))
|
||||
} else {
|
||||
// Field access `expr.f`
|
||||
if let Some(args) = segment.args {
|
||||
|
@ -1198,7 +1198,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
self.propagate_through_expr(&f, succ)
|
||||
}
|
||||
|
||||
hir::ExprKind::MethodCall(.., ref args) => {
|
||||
hir::ExprKind::MethodCall(.., ref args, _) => {
|
||||
let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
|
||||
let succ = if self.ir.tcx.is_ty_uninhabited_from(
|
||||
m,
|
||||
|
@ -1302,7 +1302,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
hir::ExprKind::MethodCall(_, span, _) => {
|
||||
hir::ExprKind::MethodCall(_, span, _, _) => {
|
||||
// Method calls have to be checked specially.
|
||||
self.span = span;
|
||||
if let Some(def_id) = self.tables.type_dependent_def_id(expr.hir_id) {
|
||||
|
@ -2117,7 +2117,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
ExprKind::Field(ref subexpression, _) => {
|
||||
self.resolve_expr(subexpression, Some(expr));
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ref arguments) => {
|
||||
ExprKind::MethodCall(ref segment, ref arguments, _) => {
|
||||
let mut arguments = arguments.iter();
|
||||
self.resolve_expr(arguments.next().unwrap(), Some(expr));
|
||||
for argument in arguments {
|
||||
|
@ -1375,7 +1375,9 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> {
|
||||
let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
|
||||
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *base)
|
||||
}
|
||||
hir::ExprKind::MethodCall(ref seg, _, args) => self.process_method_call(ex, seg, args),
|
||||
hir::ExprKind::MethodCall(ref seg, _, args, _) => {
|
||||
self.process_method_call(ex, seg, args)
|
||||
}
|
||||
hir::ExprKind::Field(ref sub_ex, _) => {
|
||||
self.visit_expr(&sub_ex);
|
||||
|
||||
|
@ -305,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let (method_path, method_span, method_expr) = match (hir, closure_params_len) {
|
||||
(
|
||||
Some(Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::MethodCall(path, span, expr),
|
||||
kind: hir::ExprKind::MethodCall(path, span, expr, _),
|
||||
..
|
||||
})),
|
||||
1,
|
||||
@ -455,7 +455,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
if self.can_coerce(ref_ty, expected) {
|
||||
let mut sugg_sp = sp;
|
||||
if let hir::ExprKind::MethodCall(ref segment, sp, ref args) = expr.kind {
|
||||
if let hir::ExprKind::MethodCall(ref segment, sp, ref args, _) = expr.kind {
|
||||
let clone_trait = self.tcx.require_lang_item(CloneTraitLangItem, Some(sp));
|
||||
if let ([arg], Some(true), sym::clone) = (
|
||||
&args[..],
|
||||
|
@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ExprKind::Call(ref callee, _) => {
|
||||
self.warn_if_unreachable(expr.hir_id, callee.span, "call")
|
||||
}
|
||||
ExprKind::MethodCall(_, ref span, _) => {
|
||||
ExprKind::MethodCall(_, ref span, _, _) => {
|
||||
self.warn_if_unreachable(expr.hir_id, *span, "call")
|
||||
}
|
||||
_ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"),
|
||||
@ -262,7 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
ExprKind::Block(ref body, _) => self.check_block_with_expected(&body, expected),
|
||||
ExprKind::Call(ref callee, ref args) => self.check_call(expr, &callee, args, expected),
|
||||
ExprKind::MethodCall(ref segment, span, ref args) => {
|
||||
ExprKind::MethodCall(ref segment, span, ref args, _) => {
|
||||
self.check_method_call(expr, segment, span, args, expected, needs)
|
||||
}
|
||||
ExprKind::Cast(ref e, ref t) => self.check_expr_cast(e, t, expr),
|
||||
|
@ -3912,7 +3912,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
sugg_unit: bool| {
|
||||
let (span, start_span, args) = match &expr.kind {
|
||||
hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]),
|
||||
hir::ExprKind::MethodCall(path_segment, span, args) => (
|
||||
hir::ExprKind::MethodCall(path_segment, span, args, _) => (
|
||||
*span,
|
||||
// `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
|
||||
path_segment
|
||||
|
@ -185,7 +185,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
self.consume_exprs(args);
|
||||
}
|
||||
|
||||
hir::ExprKind::MethodCall(.., ref args) => {
|
||||
hir::ExprKind::MethodCall(.., ref args, _) => {
|
||||
// callee.m(args)
|
||||
self.consume_exprs(args);
|
||||
}
|
||||
|
28
src/test/ui/rfc-2091-track-caller/call-chain.rs
Normal file
28
src/test/ui/rfc-2091-track-caller/call-chain.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(track_caller)]
|
||||
|
||||
use std::panic::Location;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
#[track_caller]
|
||||
fn check_loc(&self, line: u32, col: u32) -> &Self {
|
||||
let loc = Location::caller();
|
||||
assert_eq!(loc.file(), file!(), "file mismatch");
|
||||
assert_eq!(loc.line(), line, "line mismatch");
|
||||
assert_eq!(loc.column(), col, "column mismatch");
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Tests that when `Location::caller` is used in a method chain,
|
||||
// it points to the start of the correct call (the first character after the dot)
|
||||
// instead of to the very first expression in the chain
|
||||
let foo = Foo;
|
||||
foo.
|
||||
check_loc(line!(), 9).check_loc(line!(), 31)
|
||||
.check_loc(line!(), 10);
|
||||
}
|
Loading…
Reference in New Issue
Block a user