Improve handling of spans around macro result parse errors

Fixes #81543

After we expand a macro, we try to parse the resulting tokens as a AST
node. This commit makes several improvements to how we handle spans when
an error occurs:

* Only ovewrite the original `Span` if it's a dummy span. This preserves
  a more-specific span if one is available.
* Use `self.prev_token` instead of `self.token` when emitting an error
  message after encountering EOF, since an EOF token always has a dummy
  span
* Make `SourceMap::next_point` leave dummy spans unused. A dummy span
  does not have a logical 'next point', since it's a zero-length span.
  Re-using the span span preserves its 'dummy-ness' for other checks
This commit is contained in:
Aaron Hill 2021-01-31 15:21:28 -05:00
parent 04caa632dd
commit 6c14aad58e
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
6 changed files with 36 additions and 4 deletions

View File

@ -896,7 +896,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
fragment
}
Err(mut err) => {
err.set_span(span);
if err.span.is_dummy() {
err.set_span(span);
}
annotate_err_with_kind(&mut err, kind, span);
err.emit();
self.cx.trace_macros_diag();

View File

@ -1104,7 +1104,7 @@ impl<'a> Parser<'a> {
let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
// Point at the end of the macro call when reaching end of macro arguments.
(token::Eof, Some(_)) => {
let sp = self.sess.source_map().next_point(self.token.span);
let sp = self.sess.source_map().next_point(self.prev_token.span);
(sp, sp)
}
// We don't want to point at the following span after DUMMY_SP.
@ -1721,7 +1721,7 @@ impl<'a> Parser<'a> {
pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
let (span, msg) = match (&self.token.kind, self.subparser_name) {
(&token::Eof, Some(origin)) => {
let sp = self.sess.source_map().next_point(self.token.span);
let sp = self.sess.source_map().next_point(self.prev_token.span);
(sp, format!("expected expression, found end of {}", origin))
}
_ => (

View File

@ -799,6 +799,9 @@ impl SourceMap {
/// Returns a new span representing the next character after the end-point of this span.
pub fn next_point(&self, sp: Span) -> Span {
if sp.is_dummy() {
return sp;
}
let start_of_next_point = sp.hi().0;
let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true);

View File

@ -0,0 +1,14 @@
// aux-build:test-macros.rs
// Regression test for issue #81543
// Tests that we emit a properly spanned error
// when the output of a proc-macro cannot be parsed
// as the expected AST node kind
extern crate test_macros;
test_macros::identity! {
fn 32() {} //~ ERROR expected identifier
}
fn main() {}

View File

@ -0,0 +1,8 @@
error: expected identifier, found `32`
--> $DIR/issue-81543-item-parse-err.rs:11:8
|
LL | fn 32() {}
| ^^ expected identifier
error: aborting due to previous error

View File

@ -2,7 +2,12 @@ error: expected type, found `'`
--> $DIR/lifetimes.rs:7:10
|
LL | type A = single_quote_alone!();
| ^^^^^^^^^^^^^^^^^^^^^ this macro call doesn't expand to a type
| ^^^^^^^^^^^^^^^^^^^^^
| |
| expected type
| this macro call doesn't expand to a type
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error