about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-01-27 10:48:46 +0100
committerGitHub <noreply@github.com>2024-01-27 10:48:46 +0100
commit9a4417659e60a677f3dc0204c28cedfc6a6e4d91 (patch)
tree3e183cd47492d7ec85c5ac5e38ea18d81b9c3452
parent04521fd10e6eefb113ca1cefd02862599fd08640 (diff)
parenta5d9def321df76de6fb90ed836bf062b557636d6 (diff)
downloadrust-9a4417659e60a677f3dc0204c28cedfc6a6e4d91.tar.gz
rust-9a4417659e60a677f3dc0204c28cedfc6a6e4d91.zip
Rollup merge of #118182 - estebank:issue-118164, r=davidtwco
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, fix #118575.
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs19
-rw-r--r--tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs9
-rw-r--r--tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr27
3 files changed, 53 insertions, 2 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index dd9157564db..7a24b819b5f 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -791,13 +791,28 @@ impl<'a> Parser<'a> {
                 && 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::<String>() //~ 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::<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
+