about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2020-06-09 15:34:23 -0400
committerAaron Hill <aa1ronham@gmail.com>2020-06-10 17:30:11 -0400
commit28946b3486d507418b8a4acb92d5e2baae193d65 (patch)
treecdbadae12d6f219305db1970a86feda27bf92c33
parentbb8674837a9cc5225020e07fc3f164762bb4c11c (diff)
downloadrust-28946b3486d507418b8a4acb92d5e2baae193d65.tar.gz
rust-28946b3486d507418b8a4acb92d5e2baae193d65.zip
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
-rw-r--r--src/librustc_ast/ast.rs4
-rw-r--r--src/librustc_ast/mut_visit.rs3
-rw-r--r--src/librustc_ast/util/parser.rs2
-rw-r--r--src/librustc_ast/visit.rs2
-rw-r--r--src/librustc_ast_lowering/expr.rs4
-rw-r--r--src/librustc_ast_pretty/pprust.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs12
-rw-r--r--src/librustc_expand/build.rs2
-rw-r--r--src/librustc_hir/hir.rs6
-rw-r--r--src/librustc_hir/intravisit.rs2
-rw-r--r--src/librustc_hir_pretty/lib.rs4
-rw-r--r--src/librustc_infer/infer/error_reporting/need_type_info.rs4
-rw-r--r--src/librustc_lint/array_into_iter.rs2
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_middle/mir/mod.rs1
-rw-r--r--src/librustc_middle/mir/type_foldable.rs3
-rw-r--r--src/librustc_middle/mir/visit.rs1
-rw-r--r--src/librustc_mir/borrow_check/invalidation.rs1
-rw-r--r--src/librustc_mir/borrow_check/mod.rs1
-rw-r--r--src/librustc_mir/dataflow/framework/direction.rs2
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs1
-rw-r--r--src/librustc_mir/interpret/intrinsics/caller_location.rs32
-rw-r--r--src/librustc_mir/interpret/terminator.rs1
-rw-r--r--src/librustc_mir/shim.rs2
-rw-r--r--src/librustc_mir/transform/promote_consts.rs3
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs9
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs2
-rw-r--r--src/librustc_mir_build/build/expr/into.rs5
-rw-r--r--src/librustc_mir_build/build/matches/test.rs1
-rw-r--r--src/librustc_mir_build/hair/cx/expr.rs16
-rw-r--r--src/librustc_mir_build/hair/mod.rs1
-rw-r--r--src/librustc_parse/parser/expr.rs6
-rw-r--r--src/librustc_passes/liveness.rs2
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_resolve/late.rs2
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs4
-rw-r--r--src/librustc_typeck/check/demand.rs4
-rw-r--r--src/librustc_typeck/check/expr.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/expr_use_visitor.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/call-chain.rs28
42 files changed, 141 insertions, 50 deletions
diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs
index efcf95ec706..5012fbb30b0 100644
--- a/src/librustc_ast/ast.rs
+++ b/src/librustc_ast/ast.rs
@@ -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`).
diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs
index 7ececb814a6..f0441c6b885 100644
--- a/src/librustc_ast/mut_visit.rs
+++ b/src/librustc_ast/mut_visit.rs
@@ -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);
diff --git a/src/librustc_ast/util/parser.rs b/src/librustc_ast/util/parser.rs
index b98cc96b3c6..d8b44a22f2c 100644
--- a/src/librustc_ast/util/parser.rs
+++ b/src/librustc_ast/util/parser.rs
@@ -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])
         }
diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs
index 41c02734442..ccab46703df 100644
--- a/src/librustc_ast/visit.rs
+++ b/src/librustc_ast/visit.rs
@@ -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);
         }
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index c9037da377e..af7b851954a 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -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);
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 872126646f3..ca37bd6cf81 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -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) => {
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 30a84c4e47b..74d7fc16215 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -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 { .. } => {
diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs
index 6185e014d3c..20d2ea0a215 100644
--- a/src/librustc_expand/build.rs
+++ b/src/librustc_expand/build.rs
@@ -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))
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 1e305c6d32d..6b751456618 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -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`).
diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs
index 97601a3e1ac..6bc899622a3 100644
--- a/src/librustc_hir/intravisit.rs
+++ b/src/librustc_hir/intravisit.rs
@@ -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);
         }
diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs
index e642915b86a..f30f9944e58 100644
--- a/src/librustc_hir_pretty/lib.rs
+++ b/src/librustc_hir_pretty/lib.rs
@@ -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])
         }
diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs
index dfc7177921d..c72ea699f90 100644
--- a/src/librustc_infer/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -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:
diff --git a/src/librustc_lint/array_into_iter.rs b/src/librustc_lint/array_into_iter.rs
index 3eb587c016a..5b282c42034 100644
--- a/src/librustc_lint/array_into_iter.rs
+++ b/src/librustc_lint/array_into_iter.rs
@@ -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;
             }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index e17e8b7b964..aa0dd9c8311 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -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) {
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index dea82934313..8196b37391b 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -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;
diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs
index 98973f1b6fb..6ffed524400 100644
--- a/src/librustc_middle/mir/mod.rs
+++ b/src/librustc_middle/mir/mod.rs
@@ -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,
diff --git a/src/librustc_middle/mir/type_foldable.rs b/src/librustc_middle/mir/type_foldable.rs
index 97c6d6bf5f4..3f5d528d9e7 100644
--- a/src/librustc_middle/mir/type_foldable.rs
+++ b/src/librustc_middle/mir/type_foldable.rs
@@ -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 } => {
diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs
index 9f886cbc9fb..966a709c8a2 100644
--- a/src/librustc_middle/mir/visit.rs
+++ b/src/librustc_middle/mir/visit.rs
@@ -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 {
diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs
index 77d16458383..18a61895070 100644
--- a/src/librustc_mir/borrow_check/invalidation.rs
+++ b/src/librustc_mir/borrow_check/invalidation.rs
@@ -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 {
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 736cda83ca5..786424e870f 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -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 {
diff --git a/src/librustc_mir/dataflow/framework/direction.rs b/src/librustc_mir/dataflow/framework/direction.rs
index da4ad9b6168..6c9cb529dc2 100644
--- a/src/librustc_mir/dataflow/framework/direction.rs
+++ b/src/librustc_mir/dataflow/framework/direction.rs
@@ -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);
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index c0ab356756a..4f6ccdafdda 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -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 {
diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
index 91b046d7bb2..ddeed92f851 100644
--- a/src/librustc_mir/interpret/intrinsics/caller_location.rs
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -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.
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 4a63884be4c..cd7621ea975 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -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;
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index b439e919050..f95fd9b9e90 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -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,
     );
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 2c8ad00fd06..e1311ccd374 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -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
                     };
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 5c78307d882..4c8fc49099b 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -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) {
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 8f27247bfb4..a1345452ca9 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -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);
 
diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs
index e402b2d1596..76096fc2299 100644
--- a/src/librustc_mir_build/build/expr/into.rs
+++ b/src/librustc_mir_build/build/expr/into.rs
@@ -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()
diff --git a/src/librustc_mir_build/build/matches/test.rs b/src/librustc_mir_build/build/matches/test.rs
index 74398ca8a40..3e7bfc7d59b 100644
--- a/src/librustc_mir_build/build/matches/test.rs
+++ b/src/librustc_mir_build/build/matches/test.rs
@@ -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
             },
         );
 
diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs
index d0b35f32122..971a89796e2 100644
--- a/src/librustc_mir_build/hair/cx/expr.rs
+++ b/src/librustc_mir_build/hair/cx/expr.rs
@@ -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()`
diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs
index c869699bb20..140b8bbe15e 100644
--- a/src/librustc_mir_build/hair/mod.rs
+++ b/src/librustc_mir_build/hair/mod.rs
@@ -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>,
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index e0c37284839..49a5c880176 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -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 {
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
index 55978afc594..ff5dabd5418 100644
--- a/src/librustc_passes/liveness.rs
+++ b/src/librustc_passes/liveness.rs
@@ -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,
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index cb896810951..d54ec2eca8c 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -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) {
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 49177906647..7166fef2d13 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -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 {
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 489d38b00df..39cb39ba619 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -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);
 
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 700b9359d06..c097787e472 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -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[..],
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 266e9b21d69..c6a9a37e440 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -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),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f2aeed4f1e4..b2aeed09469 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -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
diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs
index 53973eba229..6baadb8febd 100644
--- a/src/librustc_typeck/expr_use_visitor.rs
+++ b/src/librustc_typeck/expr_use_visitor.rs
@@ -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);
             }
diff --git a/src/test/ui/rfc-2091-track-caller/call-chain.rs b/src/test/ui/rfc-2091-track-caller/call-chain.rs
new file mode 100644
index 00000000000..3f1c8f7abe8
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/call-chain.rs
@@ -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);
+}