Properly recover from trailing attr in body

When encountering an attribute in a body, we try to recover from an
attribute on an expression (as opposed to a statement). We need to
properly clean up when the attribute is at the end of the body where a
tail expression would be.

Fix #118164.
This commit is contained in:
Esteban Küber 2023-11-22 19:53:24 +00:00
parent e7bbe8ce93
commit a5d9def321
3 changed files with 53 additions and 2 deletions

View File

@ -792,13 +792,28 @@ pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) {
&& let [segment] = &attr_kind.item.path.segments[..] && let [segment] = &attr_kind.item.path.segments[..]
&& segment.ident.name == sym::cfg && segment.ident.name == sym::cfg
&& let Some(args_span) = attr_kind.item.args.span() && let Some(args_span) = attr_kind.item.args.span()
&& let Ok(next_attr) = snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) && let next_attr = match snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None))
{
Ok(next_attr) => next_attr,
Err(inner_err) => {
err.cancel();
inner_err.cancel();
return;
}
}
&& let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind
&& let Some(next_attr_args_span) = next_attr_kind.item.args.span() && let Some(next_attr_args_span) = next_attr_kind.item.args.span()
&& let [next_segment] = &next_attr_kind.item.path.segments[..] && let [next_segment] = &next_attr_kind.item.path.segments[..]
&& segment.ident.name == sym::cfg && segment.ident.name == sym::cfg
&& let Ok(next_expr) = snapshot.parse_expr()
{ {
let next_expr = match snapshot.parse_expr() {
Ok(next_expr) => next_expr,
Err(inner_err) => {
err.cancel();
inner_err.cancel();
return;
}
};
// We have for sure // We have for sure
// #[cfg(..)] // #[cfg(..)]
// expr // expr

View File

@ -0,0 +1,9 @@
// Issue #118164: recovery path leaving unemitted error behind
fn bar() -> String {
#[cfg(feature = )]
[1, 2, 3].iter().map().collect::<String>() //~ ERROR expected `;`, found `#`
#[attr] //~ ERROR expected statement after outer attribute
}
fn main() {
let _ = bar();
}

View File

@ -0,0 +1,27 @@
error: expected `;`, found `#`
--> $DIR/properly-recover-from-trailing-outer-attribute-in-body.rs:4:47
|
LL | #[cfg(feature = )]
| ------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map().collect::<String>()
| ^ expected `;` here
LL | #[attr]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map().collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map().collect::<String>() }
| + +
error: expected statement after outer attribute
--> $DIR/properly-recover-from-trailing-outer-attribute-in-body.rs:5:5
|
LL | #[attr]
| ^^^^^^^
error: aborting due to 2 previous errors