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:
Aaron Hill 2020-06-09 15:34:23 -04:00
parent bb8674837a
commit 28946b3486
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
42 changed files with 141 additions and 50 deletions

View File

@ -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`).

View File

@ -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);

View File

@ -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])
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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) => {

View File

@ -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 { .. } => {

View File

@ -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))

View File

@ -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`).

View File

@ -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);
}

View File

@ -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])
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;

View File

@ -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,

View File

@ -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 } => {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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);

View File

@ -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 {

View File

@ -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.

View File

@ -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;

View File

@ -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,
);

View File

@ -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
};

View File

@ -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) {

View File

@ -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);

View File

@ -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()

View File

@ -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
},
);

View File

@ -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()`

View File

@ -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>,

View File

@ -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 {

View File

@ -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,

View File

@ -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) {

View File

@ -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 {

View File

@ -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);

View File

@ -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[..],

View File

@ -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),

View File

@ -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

View File

@ -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);
}

View 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);
}