From bd00fe77d534c8eb90d2a865ec960e66fde9abb4 Mon Sep 17 00:00:00 2001 From: sjwang05 <63834813+sjwang05@users.noreply.github.com> Date: Sun, 3 Dec 2023 18:56:17 -0800 Subject: [PATCH] Fix ICE when handling malformed `cfg`d tail exprs --- .../rustc_parse/src/parser/diagnostics.rs | 87 +++++++++++-------- .../multiple-tail-expr-behind-cfg.rs | 17 ++++ .../multiple-tail-expr-behind-cfg.stderr | 28 +++++- 3 files changed, 97 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 98e68e682abb1..d8db7db2b288a 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -772,45 +772,64 @@ 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 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() { - // We have for sure - // #[cfg(..)] - // expr - // #[cfg(..)] - // other_expr - // So we suggest using `if cfg!(..) { expr } else if cfg!(..) { other_expr }`. - 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()), - (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_args_span.shrink_to_hi().with_hi(next_attr.span.hi()), - " {".to_string(), - ), - (next_expr.span.shrink_to_lo(), " ".to_string()), - (next_expr.span.shrink_to_hi(), format!("\n{}}}", " ".repeat(margin))), - ]; - err.multipart_suggestion( - "it seems like you are trying to provide different expressions depending on \ - `cfg`, consider using `if cfg!(..)`", - sugg, - Applicability::MachineApplicable, - ); + let next_attr = match snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) { + Ok(next_attr) => next_attr, + Err(mut perr) => { + // Handle cases like #118575, where the attribute is malformed + err.cancel(); + perr.emit(); + return; + } + }; + if 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 next_expr = match snapshot.parse_expr() { + Ok(next_expr) => next_expr, + Err(mut perr) => { + // Handle cases like #118575, where the expression is malformed + err.cancel(); + perr.emit(); + return; + } + }; + // We have for sure + // #[cfg(..)] + // expr + // #[cfg(..)] + // other_expr + // So we suggest using `if cfg!(..) { expr } else if cfg!(..) { other_expr }`. + 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()), + (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_args_span.shrink_to_hi().with_hi(next_attr.span.hi()), + " {".to_string(), + ), + (next_expr.span.shrink_to_lo(), " ".to_string()), + (next_expr.span.shrink_to_hi(), format!("\n{}}}", " ".repeat(margin))), + ]; + err.multipart_suggestion( + "it seems like you are trying to provide different expressions depending on \ + `cfg`, consider using `if cfg!(..)`", + sugg, + Applicability::MachineApplicable, + ); + } } } err.emit(); } + fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool { let sm = self.sess.source_map(); match (&self.prev_token.kind, &self.token.kind) { diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs index d97f24a3d2949..6e4fb1eea4d06 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs @@ -14,6 +14,23 @@ fn bar() -> String { String::new() } +fn baz() -> String { + // Issue #118575: Don't ICE when encountering malformed attributes + #[cfg(feature = "validation")] + "foo".into() + #[] + //~^ ERROR expected identifier, found `]` + //~| ERROR expected identifier, found `]` + "bar".into() +} + +fn qux() -> String { + // Issue #118575: Don't ICE when encountering malformed tail expressions + #[cfg(feature = "validation")] + "foo".into() + #[cfg(not(feature = "validation"))] //~ ERROR expected statement after outer attribute +} //~ ERROR expected expression, found `}` + fn main() { println!("{}", foo()); } diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr index a71253a5e428c..ce34ee32a5509 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr @@ -44,11 +44,37 @@ help: alternatively, consider surrounding the expression with a block LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::() } | + + +error: expected identifier, found `]` + --> $DIR/multiple-tail-expr-behind-cfg.rs:21:7 + | +LL | #[] + | ^ expected identifier + +error: expected identifier, found `]` + --> $DIR/multiple-tail-expr-behind-cfg.rs:21:7 + | +LL | #[] + | ^ expected identifier + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `}` + --> $DIR/multiple-tail-expr-behind-cfg.rs:32:1 + | +LL | } + | ^ expected expression + +error: expected statement after outer attribute + --> $DIR/multiple-tail-expr-behind-cfg.rs:31:5 + | +LL | #[cfg(not(feature = "validation"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: cannot find attribute `attr` in this scope --> $DIR/multiple-tail-expr-behind-cfg.rs:13:7 | LL | #[attr] | ^^^^ -error: aborting due to 3 previous errors +error: aborting due to 7 previous errors