Skip to content

Commit 4a0f8d5

Browse files
committed
improve diagnostics for unterminated nested block comment
1 parent 399dd80 commit 4a0f8d5

File tree

3 files changed

+78
-10
lines changed

3 files changed

+78
-10
lines changed

compiler/rustc_parse/src/lexer/mod.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,7 @@ impl<'a> StringReader<'a> {
182182
}
183183
rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => {
184184
if !terminated {
185-
let msg = match doc_style {
186-
Some(_) => "unterminated block doc-comment",
187-
None => "unterminated block comment",
188-
};
189-
let last_bpos = self.pos;
190-
self.sess.span_diagnostic.span_fatal_with_code(
191-
self.mk_sp(start, last_bpos),
192-
msg,
193-
error_code!(E0758),
194-
);
185+
self.report_unterminated_block_comment(start, doc_style);
195186
}
196187

197188
// Skip non-doc comments
@@ -553,6 +544,58 @@ impl<'a> StringReader<'a> {
553544
err.emit()
554545
}
555546

547+
fn report_unterminated_block_comment(&self, start: BytePos, doc_style: Option<DocStyle>) {
548+
let msg = match doc_style {
549+
Some(_) => "unterminated block doc-comment",
550+
None => "unterminated block comment",
551+
};
552+
let last_bpos = self.pos;
553+
let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code(
554+
self.mk_sp(start, last_bpos),
555+
msg,
556+
error_code!(E0758),
557+
);
558+
let mut nested_block_comment_open_idxs = vec![];
559+
let mut last_nested_block_comment_idxs = None;
560+
let mut content_chars = self.str_from(start).char_indices();
561+
562+
if let Some((_, mut last_char)) = content_chars.next() {
563+
while let Some((idx, c)) = content_chars.next() {
564+
match c {
565+
'*' if last_char == '/' => {
566+
nested_block_comment_open_idxs.push(idx);
567+
}
568+
'/' if last_char == '*' => {
569+
last_nested_block_comment_idxs =
570+
nested_block_comment_open_idxs.pop().map(|open_idx| (open_idx, idx));
571+
}
572+
_ => {}
573+
};
574+
last_char = c;
575+
}
576+
}
577+
578+
if let Some((nested_open_idx, nested_close_idx)) = last_nested_block_comment_idxs {
579+
err.span_label(self.mk_sp(start, start + BytePos(2)), msg)
580+
.span_label(
581+
self.mk_sp(
582+
start + BytePos(nested_open_idx as u32 - 1),
583+
start + BytePos(nested_open_idx as u32 + 1),
584+
),
585+
"...as last nested comment starts here, maybe you want to close this instead?",
586+
)
587+
.span_label(
588+
self.mk_sp(
589+
start + BytePos(nested_close_idx as u32 - 1),
590+
start + BytePos(nested_close_idx as u32 + 1),
591+
),
592+
"...and last nested comment terminates here",
593+
);
594+
}
595+
596+
err.emit();
597+
}
598+
556599
// RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021,
557600
// using a (unknown) prefix is an error. In earlier editions, however, they
558601
// only result in a (allowed by default) lint, and are treated as regular
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* //~ ERROR E0758
2+
/* */
3+
/*
4+
*/
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0758]: unterminated block comment
2+
--> $DIR/unterminated-nested-comment.rs:1:1
3+
|
4+
LL | /*
5+
| ^-
6+
| |
7+
| _unterminated block comment
8+
| |
9+
LL | | /* */
10+
LL | | /*
11+
| | --
12+
| | |
13+
| | ...as last nested comment starts here, maybe you want to close this instead?
14+
LL | | */
15+
| |_--^
16+
| |
17+
| ...and last nested comment terminates here
18+
19+
error: aborting due to previous error
20+
21+
For more information about this error, try `rustc --explain E0758`.

0 commit comments

Comments
 (0)