Skip to content

Commit f005e9f

Browse files
committed
Guess semicolon span for macro statements
1 parent 1333ae6 commit f005e9f

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

compiler/rustc_span/src/source_map.rs

+38
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,18 @@ impl SourceMap {
653653
})
654654
}
655655

656+
/// Extends the given `Span` while the next character matches the predicate
657+
pub fn span_extend_while(
658+
&self,
659+
span: Span,
660+
f: impl Fn(char) -> bool,
661+
) -> Result<Span, SpanSnippetError> {
662+
self.span_to_source(span, |s, _start, end| {
663+
let n = s[end..].char_indices().find(|&(_, c)| !f(c)).map_or(s.len() - end, |(i, _)| i);
664+
Ok(span.with_hi(span.hi() + BytePos(n as u32)))
665+
})
666+
}
667+
656668
/// Extends the given `Span` to just after the next occurrence of `c`.
657669
pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
658670
if let Ok(next_source) = self.span_to_next_source(sp) {
@@ -1013,6 +1025,32 @@ impl SourceMap {
10131025
let source_file = &self.files()[source_file_index];
10141026
source_file.is_imported()
10151027
}
1028+
1029+
/// Gets the span of a statement. If the statement is a macro expansion, the
1030+
/// span in the context of the block span is found. The trailing semicolon is included
1031+
/// on a best-effort basis.
1032+
pub fn stmt_span(&self, stmt_span: Span, block_span: Span) -> Span {
1033+
if !stmt_span.from_expansion() {
1034+
return stmt_span;
1035+
}
1036+
let mac_call = original_sp(stmt_span, block_span);
1037+
self.mac_call_stmt_semi_span(mac_call).map_or(mac_call, |s| mac_call.with_hi(s.hi()))
1038+
}
1039+
1040+
/// Tries to find the span of the semicolon of a macro call statement.
1041+
/// The input must be the *call site* span of a statement from macro expansion.
1042+
///
1043+
/// v output
1044+
/// mac!();
1045+
/// ^^^^^^ input
1046+
pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> {
1047+
let span = self.span_extend_while(mac_call, char::is_whitespace).ok()?;
1048+
let span = span.shrink_to_hi().with_hi(BytePos(span.hi().0.checked_add(1)?));
1049+
if self.span_to_snippet(span).as_deref() != Ok(";") {
1050+
return None;
1051+
}
1052+
Some(span)
1053+
}
10161054
}
10171055

10181056
#[derive(Clone)]

compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1171,8 +1171,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11711171
{
11721172
return None;
11731173
}
1174-
let original_span = original_sp(last_stmt.span, blk.span);
1175-
Some((original_span.with_lo(original_span.hi() - BytePos(1)), needs_box))
1174+
let span = if last_stmt.span.from_expansion() {
1175+
let mac_call = original_sp(last_stmt.span, blk.span);
1176+
self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)?
1177+
} else {
1178+
last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1))
1179+
};
1180+
Some((span, needs_box))
11761181
}
11771182

11781183
// Instantiates the given path, which must refer to an item with the given

0 commit comments

Comments
 (0)