Skip to content

Commit 7d6e5b9

Browse files
committed
Auto merge of #47420 - davidtwco:issue-46885, r=estebank
Fix off-by-one spans in MIR borrowck errors Fixes #46885. r? @nikomatsakis
2 parents 6b99ade + 0bd9667 commit 7d6e5b9

24 files changed

+137
-48
lines changed

src/librustc/infer/error_reporting/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
958958
// `sp` only covers `T`, change it so that it covers
959959
// `T:` when appropriate
960960
let sp = if has_lifetimes {
961-
sp.to(sp.next_point().next_point())
961+
sp.to(self.tcx.sess.codemap().next_point(
962+
self.tcx.sess.codemap().next_point(sp)))
962963
} else {
963964
sp
964965
};

src/librustc_borrowck/borrowck/check_loans.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
591591
// 3. Where does old loan expire.
592592

593593
let previous_end_span =
594-
Some(old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree)
595-
.end_point());
594+
Some(self.tcx().sess.codemap().end_point(
595+
old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree)));
596596

597597
let mut err = match (new_loan.kind, old_loan.kind) {
598598
(ty::MutBorrow, ty::MutBorrow) =>

src/librustc_borrowck/borrowck/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
12761276
fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
12771277
match *region {
12781278
ty::ReScope(scope) => {
1279-
Some(scope.span(self.tcx, &self.region_scope_tree).end_point())
1279+
Some(self.tcx.sess.codemap().end_point(
1280+
scope.span(self.tcx, &self.region_scope_tree)))
12801281
}
12811282
_ => None
12821283
}

src/librustc_mir/borrow_check/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1112,10 +1112,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11121112
debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
11131113
// FIXME: should be talking about the region lifetime instead
11141114
// of just a span here.
1115+
let span = self.tcx.sess.codemap().end_point(span);
11151116
self.report_borrowed_value_does_not_live_long_enough(
11161117
context,
11171118
borrow,
1118-
span.end_point(),
1119+
span,
11191120
flow_state.borrows.operator(),
11201121
)
11211122
}

src/librustc_mir/build/scope.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -695,10 +695,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
695695
if let DropKind::Value { .. } = drop_kind {
696696
scope.needs_cleanup = true;
697697
}
698+
698699
let region_scope_span = region_scope.span(self.hir.tcx(),
699700
&self.hir.region_scope_tree);
700-
// Attribute scope exit drops to scope's closing brace
701-
let scope_end = region_scope_span.with_lo(region_scope_span.hi());
701+
// Attribute scope exit drops to scope's closing brace.
702+
let scope_end = self.hir.tcx().sess.codemap().end_point(region_scope_span);
703+
702704
scope.drops.push(DropData {
703705
span: scope_end,
704706
location: place.clone(),

src/librustc_mir/dataflow/impls/borrows.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,8 @@ impl<'a, 'gcx, 'tcx> ActiveBorrows<'a, 'gcx, 'tcx> {
537537
Some(_) => None,
538538
None => {
539539
match self.0.region_span_map.get(region) {
540-
Some(span) => Some(span.end_point()),
541-
None => Some(self.0.mir.span.end_point())
540+
Some(span) => Some(self.0.tcx.sess.codemap().end_point(*span)),
541+
None => Some(self.0.tcx.sess.codemap().end_point(self.0.mir.span))
542542
}
543543
}
544544
}

src/librustc_resolve/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2871,8 +2871,8 @@ impl<'a> Resolver<'a> {
28712871
if let Some(sp) = self.current_type_ascription.last() {
28722872
let mut sp = *sp;
28732873
loop { // try to find the `:`, bail on first non-':'/non-whitespace
2874-
sp = sp.next_point();
2875-
if let Ok(snippet) = cm.span_to_snippet(sp.to(sp.next_point())) {
2874+
sp = cm.next_point(sp);
2875+
if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) {
28762876
debug!("snippet {:?}", snippet);
28772877
let line_sp = cm.lookup_char_pos(sp.hi()).line;
28782878
let line_base_sp = cm.lookup_char_pos(base_span.lo()).line;

src/librustc_typeck/check/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -2457,7 +2457,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
24572457
err.span_label(def_s, "defined here");
24582458
}
24592459
if sugg_unit {
2460-
let sugg_span = expr_sp.end_point();
2460+
let sugg_span = sess.codemap().end_point(expr_sp);
24612461
// remove closing `)` from the span
24622462
let sugg_span = sugg_span.with_hi(sugg_span.lo());
24632463
err.span_suggestion(
@@ -4446,10 +4446,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
44464446
/// statement and the return type has been left as default or has been specified as `()`. If so,
44474447
/// it suggests adding a semicolon.
44484448
fn suggest_missing_semicolon(&self,
4449-
err: &mut DiagnosticBuilder<'tcx>,
4450-
expression: &'gcx hir::Expr,
4451-
expected: Ty<'tcx>,
4452-
cause_span: Span) {
4449+
err: &mut DiagnosticBuilder<'tcx>,
4450+
expression: &'gcx hir::Expr,
4451+
expected: Ty<'tcx>,
4452+
cause_span: Span) {
44534453
if expected.is_nil() {
44544454
// `BlockTailExpression` only relevant if the tail expr would be
44554455
// useful on its own.
@@ -4461,7 +4461,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
44614461
hir::ExprLoop(..) |
44624462
hir::ExprMatch(..) |
44634463
hir::ExprBlock(..) => {
4464-
let sp = cause_span.next_point();
4464+
let sp = self.tcx.sess.codemap().next_point(cause_span);
44654465
err.span_suggestion(sp,
44664466
"try adding a semicolon",
44674467
";".to_string());

src/libsyntax/codemap.rs

+96
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub use self::ExpnFormat::*;
2525
use rustc_data_structures::fx::FxHashMap;
2626
use rustc_data_structures::stable_hasher::StableHasher;
2727
use std::cell::{RefCell, Ref};
28+
use std::cmp;
2829
use std::hash::Hash;
2930
use std::path::{Path, PathBuf};
3031
use std::rc::Rc;
@@ -607,6 +608,101 @@ impl CodeMap {
607608
self.span_until_char(sp, '{')
608609
}
609610

611+
/// Returns a new span representing just the end-point of this span
612+
pub fn end_point(&self, sp: Span) -> Span {
613+
let pos = sp.hi().0;
614+
615+
let width = self.find_width_of_character_at_span(sp, false);
616+
let corrected_end_position = pos.checked_sub(width).unwrap_or(pos);
617+
618+
let end_point = BytePos(cmp::max(corrected_end_position, sp.lo().0));
619+
sp.with_lo(end_point)
620+
}
621+
622+
/// Returns a new span representing the next character after the end-point of this span
623+
pub fn next_point(&self, sp: Span) -> Span {
624+
let start_of_next_point = sp.hi().0;
625+
626+
let width = self.find_width_of_character_at_span(sp, true);
627+
// If the width is 1, then the next span should point to the same `lo` and `hi`. However,
628+
// in the case of a multibyte character, where the width != 1, the next span should
629+
// span multiple bytes to include the whole character.
630+
let end_of_next_point = start_of_next_point.checked_add(
631+
width - 1).unwrap_or(start_of_next_point);
632+
633+
let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point));
634+
Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt())
635+
}
636+
637+
/// Finds the width of a character, either before or after the provided span.
638+
fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
639+
// Disregard malformed spans and assume a one-byte wide character.
640+
if sp.lo() >= sp.hi() {
641+
debug!("find_width_of_character_at_span: early return malformed span");
642+
return 1;
643+
}
644+
645+
let local_begin = self.lookup_byte_offset(sp.lo());
646+
let local_end = self.lookup_byte_offset(sp.hi());
647+
debug!("find_width_of_character_at_span: local_begin=`{:?}`, local_end=`{:?}`",
648+
local_begin, local_end);
649+
650+
let start_index = local_begin.pos.to_usize();
651+
let end_index = local_end.pos.to_usize();
652+
debug!("find_width_of_character_at_span: start_index=`{:?}`, end_index=`{:?}`",
653+
start_index, end_index);
654+
655+
// Disregard indexes that are at the start or end of their spans, they can't fit bigger
656+
// characters.
657+
if (!forwards && end_index == usize::min_value()) ||
658+
(forwards && start_index == usize::max_value()) {
659+
debug!("find_width_of_character_at_span: start or end of span, cannot be multibyte");
660+
return 1;
661+
}
662+
663+
let source_len = (local_begin.fm.end_pos - local_begin.fm.start_pos).to_usize();
664+
debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len);
665+
// Ensure indexes are also not malformed.
666+
if start_index > end_index || end_index > source_len {
667+
debug!("find_width_of_character_at_span: source indexes are malformed");
668+
return 1;
669+
}
670+
671+
// We need to extend the snippet to the end of the src rather than to end_index so when
672+
// searching forwards for boundaries we've got somewhere to search.
673+
let snippet = if let Some(ref src) = local_begin.fm.src {
674+
let len = src.len();
675+
(&src[start_index..len]).to_string()
676+
} else if let Some(src) = local_begin.fm.external_src.borrow().get_source() {
677+
let len = src.len();
678+
(&src[start_index..len]).to_string()
679+
} else {
680+
return 1;
681+
};
682+
debug!("find_width_of_character_at_span: snippet=`{:?}`", snippet);
683+
684+
let file_start_pos = local_begin.fm.start_pos.to_usize();
685+
let file_end_pos = local_begin.fm.end_pos.to_usize();
686+
debug!("find_width_of_character_at_span: file_start_pos=`{:?}` file_end_pos=`{:?}`",
687+
file_start_pos, file_end_pos);
688+
689+
let mut target = if forwards { end_index + 1 } else { end_index - 1 };
690+
debug!("find_width_of_character_at_span: initial target=`{:?}`", target);
691+
692+
while !snippet.is_char_boundary(target - start_index)
693+
&& target >= file_start_pos && target <= file_end_pos {
694+
target = if forwards { target + 1 } else { target - 1 };
695+
debug!("find_width_of_character_at_span: target=`{:?}`", target);
696+
}
697+
debug!("find_width_of_character_at_span: final target=`{:?}`", target);
698+
699+
if forwards {
700+
(target - end_index) as u32
701+
} else {
702+
(end_index - target) as u32
703+
}
704+
}
705+
610706
pub fn get_filemap(&self, filename: &FileName) -> Option<Rc<FileMap>> {
611707
for fm in self.files.borrow().iter() {
612708
if *filename == fm.name {

src/libsyntax/parse/parser.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -704,13 +704,15 @@ impl<'a> Parser<'a> {
704704
expect.clone()
705705
};
706706
(format!("expected one of {}, found `{}`", expect, actual),
707-
(self.prev_span.next_point(), format!("expected one of {} here", short_expect)))
707+
(self.sess.codemap().next_point(self.prev_span),
708+
format!("expected one of {} here", short_expect)))
708709
} else if expected.is_empty() {
709710
(format!("unexpected token: `{}`", actual),
710711
(self.prev_span, "unexpected token after this".to_string()))
711712
} else {
712713
(format!("expected {}, found `{}`", expect, actual),
713-
(self.prev_span.next_point(), format!("expected {} here", expect)))
714+
(self.sess.codemap().next_point(self.prev_span),
715+
format!("expected {} here", expect)))
714716
};
715717
let mut err = self.fatal(&msg_exp);
716718
let sp = if self.token == token::Token::Eof {
@@ -3190,7 +3192,7 @@ impl<'a> Parser<'a> {
31903192
// return. This won't catch blocks with an explicit `return`, but that would be caught by
31913193
// the dead code lint.
31923194
if self.eat_keyword(keywords::Else) || !cond.returns() {
3193-
let sp = lo.next_point();
3195+
let sp = self.sess.codemap().next_point(lo);
31943196
let mut err = self.diagnostic()
31953197
.struct_span_err(sp, "missing condition for `if` statemement");
31963198
err.span_label(sp, "expected if condition here");

src/libsyntax_pos/lib.rs

-14
Original file line numberDiff line numberDiff line change
@@ -216,20 +216,6 @@ impl Span {
216216
self.data().with_ctxt(ctxt)
217217
}
218218

219-
/// Returns a new span representing just the end-point of this span
220-
pub fn end_point(self) -> Span {
221-
let span = self.data();
222-
let lo = cmp::max(span.hi.0 - 1, span.lo.0);
223-
span.with_lo(BytePos(lo))
224-
}
225-
226-
/// Returns a new span representing the next character after the end-point of this span
227-
pub fn next_point(self) -> Span {
228-
let span = self.data();
229-
let lo = cmp::max(span.hi.0, span.lo.0 + 1);
230-
Span::new(BytePos(lo), BytePos(lo), span.ctxt)
231-
}
232-
233219
/// Returns `self` if `self` is not the dummy span, and `other` otherwise.
234220
pub fn substitute_dummy(self, other: Span) -> Span {
235221
if self.source_equal(&DUMMY_SP) { other } else { self }

src/test/ui/issue-46471-1.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ error[E0597]: `z` does not live long enough (Mir)
1515
16 | &mut z
1616
| ^^^^^^ borrowed value does not live long enough
1717
17 | };
18-
| - `z` dropped here while still borrowed
18+
| - `z` dropped here while still borrowed
1919
...
2020
21 | }
2121
| - borrowed value needs to live until here

src/test/ui/issue-46471.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ error[E0597]: `x` does not live long enough (Mir)
1616
| ^^ borrowed value does not live long enough
1717
...
1818
18 | }
19-
| - borrowed value only lives until here
19+
| - borrowed value only lives until here
2020
|
2121
= note: borrowed value must be valid for the static lifetime...
2222

src/test/ui/issue-46472.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ error[E0597]: borrowed value does not live long enough (Mir)
2424
| ^ temporary value does not live long enough
2525
...
2626
17 | }
27-
| - temporary value only lives until here
27+
| - temporary value only lives until here
2828
|
2929
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
3030
--> $DIR/issue-46472.rs:13:1

src/test/ui/nll/capture-ref-in-struct.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ error[E0597]: `y` does not live long enough
55
| ^^ borrowed value does not live long enough
66
...
77
38 | }
8-
| - borrowed value only lives until here
8+
| - borrowed value only lives until here
99
39 |
1010
40 | deref(p);
1111
| - borrow later used here

src/test/ui/nll/closure-requirements/escape-argument.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ error[E0597]: `y` does not live long enough
3030
| ^^ borrowed value does not live long enough
3131
38 | //~^ ERROR `y` does not live long enough [E0597]
3232
39 | }
33-
| - borrowed value only lives until here
33+
| - borrowed value only lives until here
3434
40 |
3535
41 | deref(p);
3636
| - borrow later used here

src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ error[E0597]: `y` does not live long enough
5757
| |_________^ borrowed value does not live long enough
5858
...
5959
36 | }
60-
| - borrowed value only lives until here
60+
| - borrowed value only lives until here
6161
37 |
6262
38 | deref(p);
6363
| - borrow later used here

src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ error[E0597]: `y` does not live long enough
3434
| ^^^^^^^^^ borrowed value does not live long enough
3535
...
3636
36 | }
37-
| - borrowed value only lives until here
37+
| - borrowed value only lives until here
3838
37 |
3939
38 | deref(p);
4040
| - borrow later used here

src/test/ui/nll/drop-no-may-dangle.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ error[E0506]: cannot assign to `v[..]` because it is borrowed
88
| ^^^^^^^^^ assignment to borrowed `v[..]` occurs here
99
...
1010
35 | }
11-
| - borrow later used here, when `p` is dropped
11+
| - borrow later used here, when `p` is dropped
1212

1313
error[E0506]: cannot assign to `v[..]` because it is borrowed
1414
--> $DIR/drop-no-may-dangle.rs:34:5
@@ -19,7 +19,7 @@ error[E0506]: cannot assign to `v[..]` because it is borrowed
1919
34 | v[0] += 1; //~ ERROR cannot assign to `v[..]` because it is borrowed
2020
| ^^^^^^^^^ assignment to borrowed `v[..]` occurs here
2121
35 | }
22-
| - borrow later used here, when `p` is dropped
22+
| - borrow later used here, when `p` is dropped
2323

2424
error: aborting due to 2 previous errors
2525

src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ error[E0506]: cannot assign to `x` because it is borrowed
88
| ^^^^^ assignment to borrowed `x` occurs here
99
33 | // FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones
1010
34 | }
11-
| - borrow later used here, when `foo` is dropped
11+
| - borrow later used here, when `foo` is dropped
1212

1313
error: aborting due to previous error
1414

src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ error[E0506]: cannot assign to `x` because it is borrowed
77
31 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
88
| ^^^^^ assignment to borrowed `x` occurs here
99
32 | }
10-
| - borrow later used here, when `foo` is dropped
10+
| - borrow later used here, when `foo` is dropped
1111

1212
error: aborting due to previous error
1313

src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ error[E0506]: cannot assign to `x` because it is borrowed
88
| ^^^^^ assignment to borrowed `x` occurs here
99
33 | // FIXME ^ This currently errors and it should not.
1010
34 | }
11-
| - borrow later used here, when `foo` is dropped
11+
| - borrow later used here, when `foo` is dropped
1212

1313
error: aborting due to previous error
1414

src/test/ui/nll/maybe-initialized-drop.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ error[E0506]: cannot assign to `x` because it is borrowed
66
26 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
77
| ^^^^^ assignment to borrowed `x` occurs here
88
27 | }
9-
| - borrow later used here, when `wrap` is dropped
9+
| - borrow later used here, when `wrap` is dropped
1010

1111
error: aborting due to previous error
1212

src/test/ui/nll/return-ref-mut-issue-46557.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ error[E0597]: borrowed value does not live long enough
55
| ^^^^^^^ temporary value does not live long enough
66
18 | x
77
19 | }
8-
| - temporary value only lives until here
8+
| - temporary value only lives until here
99
|
1010
= note: borrowed value must be valid for lifetime '_#2r...
1111

0 commit comments

Comments
 (0)