From a5d9def321df76de6fb90ed836bf062b557636d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 22 Nov 2023 19:53:24 +0000 Subject: [PATCH] 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. --- .../rustc_parse/src/parser/diagnostics.rs | 19 +++++++++++-- ...r-from-trailing-outer-attribute-in-body.rs | 9 +++++++ ...om-trailing-outer-attribute-in-body.stderr | 27 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs create mode 100644 tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 720a610fdf5..1924d28d91c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -792,13 +792,28 @@ pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) { && let [segment] = &attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg && 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 Some(next_attr_args_span) = next_attr_kind.item.args.span() && let [next_segment] = &next_attr_kind.item.path.segments[..] && 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 // #[cfg(..)] // expr diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs new file mode 100644 index 00000000000..a7412f51782 --- /dev/null +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs @@ -0,0 +1,9 @@ +// Issue #118164: recovery path leaving unemitted error behind +fn bar() -> String { + #[cfg(feature = )] + [1, 2, 3].iter().map().collect::() //~ ERROR expected `;`, found `#` + #[attr] //~ ERROR expected statement after outer attribute +} +fn main() { + let _ = bar(); +} diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr new file mode 100644 index 00000000000..dd0081cc2df --- /dev/null +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr @@ -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::() + | ^ expected `;` here +LL | #[attr] + | - unexpected token + | +help: add `;` here + | +LL | [1, 2, 3].iter().map().collect::(); + | + +help: alternatively, consider surrounding the expression with a block + | +LL | { [1, 2, 3].iter().map().collect::() } + | + + + +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 +