From 5ff428c1ff81a635628a2b67c96999b6098f3fa8 Mon Sep 17 00:00:00 2001
From: yukang <moorekang@gmail.com>
Date: Sat, 2 Dec 2023 23:46:45 +0800
Subject: [PATCH] Fix parser ICE from attrs

---
 .../rustc_parse/src/parser/diagnostics.rs     | 16 ++-----
 tests/ui/parser/issues/issue-118530-ice.rs    | 15 +++++++
 .../ui/parser/issues/issue-118530-ice.stderr  | 43 +++++++++++++++++++
 tests/ui/parser/issues/issue-118531-ice.rs    | 10 +++++
 .../ui/parser/issues/issue-118531-ice.stderr  | 38 ++++++++++++++++
 5 files changed, 110 insertions(+), 12 deletions(-)
 create mode 100644 tests/ui/parser/issues/issue-118530-ice.rs
 create mode 100644 tests/ui/parser/issues/issue-118530-ice.stderr
 create mode 100644 tests/ui/parser/issues/issue-118531-ice.rs
 create mode 100644 tests/ui/parser/issues/issue-118531-ice.stderr

diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index ecb840f067e..634472eac45 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -18,7 +18,6 @@ use crate::errors::{
     TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
     UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
 };
-
 use crate::fluent_generated as fluent;
 use crate::parser;
 use crate::parser::attr::InnerAttrPolicy;
@@ -772,8 +771,10 @@ impl<'a> Parser<'a> {
                 && let ast::AttrKind::Normal(attr_kind) = &attr.kind
                 && 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 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()
@@ -787,23 +788,14 @@ impl<'a> Parser<'a> {
                 let margin = self.sess.source_map().span_to_margin(next_expr.span).unwrap_or(0);
                 let sugg = vec![
                     (attr.span.with_hi(segment.span().hi()), "if cfg!".to_string()),
-                    (
-                        attr_kind.item.args.span().unwrap().shrink_to_hi().with_hi(attr.span.hi()),
-                        " {".to_string(),
-                    ),
+                    (args_span.shrink_to_hi().with_hi(attr.span.hi()), " {".to_string()),
                     (expr.span.shrink_to_lo(), "    ".to_string()),
                     (
                         next_attr.span.with_hi(next_segment.span().hi()),
                         "} else if cfg!".to_string(),
                     ),
                     (
-                        next_attr_kind
-                            .item
-                            .args
-                            .span()
-                            .unwrap()
-                            .shrink_to_hi()
-                            .with_hi(next_attr.span.hi()),
+                        next_attr_args_span.shrink_to_hi().with_hi(next_attr.span.hi()),
                         " {".to_string(),
                     ),
                     (next_expr.span.shrink_to_lo(), "    ".to_string()),
diff --git a/tests/ui/parser/issues/issue-118530-ice.rs b/tests/ui/parser/issues/issue-118530-ice.rs
new file mode 100644
index 00000000000..e758e5af4d9
--- /dev/null
+++ b/tests/ui/parser/issues/issue-118530-ice.rs
@@ -0,0 +1,15 @@
+fn bar() -> String {
+    #[cfg]
+    [1, 2, 3].iter() //~ ERROR expected `;`, found `#`
+    #[feature]
+    attr::fn bar() -> String { //~ ERROR expected identifier, found keyword `fn`
+    //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `->`
+    //~| ERROR expected `;`, found `bar`
+    #[attr]
+    [1, 2, 3].iter().map().collect::<String>()
+    #[attr]
+
+}()
+}
+
+fn main() { }
diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr
new file mode 100644
index 00000000000..ef573fb7ba3
--- /dev/null
+++ b/tests/ui/parser/issues/issue-118530-ice.stderr
@@ -0,0 +1,43 @@
+error: expected `;`, found `#`
+  --> $DIR/issue-118530-ice.rs:3:21
+   |
+LL |     #[cfg]
+   |     ------ only `;` terminated statements or tail expressions are allowed after this attribute
+LL |     [1, 2, 3].iter()
+   |                     ^ expected `;` here
+LL |     #[feature]
+   |     - unexpected token
+   |
+help: add `;` here
+   |
+LL |     [1, 2, 3].iter();
+   |                     +
+help: alternatively, consider surrounding the expression with a block
+   |
+LL |     { [1, 2, 3].iter() }
+   |     +                  +
+
+error: expected identifier, found keyword `fn`
+  --> $DIR/issue-118530-ice.rs:5:11
+   |
+LL |     attr::fn bar() -> String {
+   |           ^^ expected identifier, found keyword
+
+error: expected `;`, found `bar`
+  --> $DIR/issue-118530-ice.rs:5:13
+   |
+LL |     #[feature]
+   |     ---------- only `;` terminated statements or tail expressions are allowed after this attribute
+LL |     attr::fn bar() -> String {
+   |             ^--- unexpected token
+   |             |
+   |             help: add `;` here
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `->`
+  --> $DIR/issue-118530-ice.rs:5:20
+   |
+LL |     attr::fn bar() -> String {
+   |                    ^^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/parser/issues/issue-118531-ice.rs b/tests/ui/parser/issues/issue-118531-ice.rs
new file mode 100644
index 00000000000..24794f06052
--- /dev/null
+++ b/tests/ui/parser/issues/issue-118531-ice.rs
@@ -0,0 +1,10 @@
+fn bar() -> String {
+    #[cfg(feature = )]
+    [1, 2, 3].iter().map().collect::<String>() //~ ERROR expected `;`, found `#`
+
+    #[attr] //~ ERROR attributes on expressions are experimental [E0658]
+    //~^ ERROR cannot find attribute `attr` in this scope
+    String::new()
+}
+
+fn main() { }
diff --git a/tests/ui/parser/issues/issue-118531-ice.stderr b/tests/ui/parser/issues/issue-118531-ice.stderr
new file mode 100644
index 00000000000..a32292dcb0d
--- /dev/null
+++ b/tests/ui/parser/issues/issue-118531-ice.stderr
@@ -0,0 +1,38 @@
+error: expected `;`, found `#`
+  --> $DIR/issue-118531-ice.rs:3: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 |
+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[E0658]: attributes on expressions are experimental
+  --> $DIR/issue-118531-ice.rs:5:5
+   |
+LL |     #[attr]
+   |     ^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error: cannot find attribute `attr` in this scope
+  --> $DIR/issue-118531-ice.rs:5:7
+   |
+LL |     #[attr]
+   |       ^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.