From 2b812b554d325485b9c6bb0a833e431d2c02e552 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 31 Aug 2020 22:39:21 -0400 Subject: [PATCH] Preserve leading vert when pretty-printing patterns Fixes #76182 Previously, we did not preserve the precense of a leading vert ('|') when parsing a pattern. This lead to an instance of #43081 when invoking a proc-macro, since the pretty-printed tokens would be missing the '|' present in the captured tokens. --- compiler/rustc_ast/src/ast.rs | 3 + compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast_pretty/src/pprust.rs | 5 ++ compiler/rustc_expand/src/base.rs | 9 ++- compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_expand/src/placeholders.rs | 12 +++- .../rustc_parse/src/parser/diagnostics.rs | 11 +++- compiler/rustc_parse/src/parser/pat.rs | 8 ++- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 1 + .../issue-76182-leading-vert-pat.rs | 16 +++++ .../issue-76182-leading-vert-pat.stdout | 62 +++++++++++++++++++ .../clippy_lints/src/unnested_or_patterns.rs | 1 + 12 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs create mode 100644 src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 127a53cad2b30..f1cbe178c393a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -550,6 +550,8 @@ pub struct Pat { pub id: NodeId, pub kind: PatKind, pub span: Span, + /// Whether or not this pattern starts with a leading `|` + pub leading_vert: bool, pub tokens: Option, } @@ -2140,6 +2142,7 @@ impl Param { id: DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), span, + leading_vert: false, tokens: None, }), span, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 965571aaa548e..f6d59d04ae83c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1054,7 +1054,7 @@ pub fn noop_flat_map_foreign_item( } pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { - let Pat { id, kind, span, tokens: _ } = pat.deref_mut(); + let Pat { id, kind, span, leading_vert: _, tokens: _ } = pat.deref_mut(); vis.visit_id(id); match kind { PatKind::Wild | PatKind::Rest => {} diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust.rs index cb48deb58863e..4c50c759f7e79 100644 --- a/compiler/rustc_ast_pretty/src/pprust.rs +++ b/compiler/rustc_ast_pretty/src/pprust.rs @@ -2302,6 +2302,11 @@ impl<'a> State<'a> { crate fn print_pat(&mut self, pat: &ast::Pat) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); + + if pat.leading_vert { + self.s.word_space("|"); + } + /* Pat isn't normalized, but the beauty of it is that it doesn't matter */ match pat.kind { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 4c01cb8159a30..83168b941096b 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -551,6 +551,7 @@ impl MacResult for MacEager { id: ast::DUMMY_NODE_ID, span: e.span, kind: PatKind::Lit(e), + leading_vert: false, tokens: None, })); } @@ -598,7 +599,13 @@ impl DummyResult { /// A plain dummy pattern. pub fn raw_pat(sp: Span) -> ast::Pat { - ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Wild, span: sp, tokens: None } + ast::Pat { + id: ast::DUMMY_NODE_ID, + kind: PatKind::Wild, + span: sp, + leading_vert: false, + tokens: None, + } } /// A plain dummy type. diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 9490b62aa1797..fc18197f67bae 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -392,7 +392,7 @@ impl<'a> ExtCtxt<'a> { } pub fn pat(&self, span: Span, kind: PatKind) -> P { - P(ast::Pat { id: ast::DUMMY_NODE_ID, kind, span, tokens: None }) + P(ast::Pat { id: ast::DUMMY_NODE_ID, kind, span, leading_vert: false, tokens: None }) } pub fn pat_wild(&self, span: Span) -> P { self.pat(span, PatKind::Wild) diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 29fb4c95ec69f..475c9f780ef09 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -38,8 +38,15 @@ pub fn placeholder( }) }; let ty = || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span }); - let pat = - || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None }); + let pat = || { + P(ast::Pat { + id, + kind: ast::PatKind::MacCall(mac_placeholder()), + span, + leading_vert: false, + tokens: None, + }) + }; match kind { AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), @@ -86,6 +93,7 @@ pub fn placeholder( id, span, kind: ast::PatKind::MacCall(mac_placeholder()), + leading_vert: false, tokens: None, })), AstFragmentKind::Ty => { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 12efe391fb964..31a3e06781932 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -26,6 +26,7 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None), span: ident.span, + leading_vert: false, tokens: None, }); let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID }; @@ -88,6 +89,7 @@ impl RecoverQPath for Pat { span: path.span, kind: PatKind::Path(qself, path), id: ast::DUMMY_NODE_ID, + leading_vert: false, tokens: None, } } @@ -1532,8 +1534,13 @@ impl<'a> Parser<'a> { .emit(); // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. - let pat = - P(Pat { kind: PatKind::Wild, span: pat.span, id: ast::DUMMY_NODE_ID, tokens: None }); + let pat = P(Pat { + kind: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID, + leading_vert: false, + tokens: None, + }); Ok((pat, ty)) } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 2c0133a24dcb1..3eb2e00b02df7 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -45,11 +45,12 @@ impl<'a> Parser<'a> { /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes; + let leading_vert = self.eat_or_separator(None); + let gated_leading_vert = leading_vert && gate_or == GateOr::Yes; let leading_vert_span = self.prev_token.span; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; + let mut pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, @@ -58,6 +59,7 @@ impl<'a> Parser<'a> { if gated_leading_vert && self.sess.gated_spans.is_ungated(sym::or_patterns) { self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span); } + pat.leading_vert = leading_vert; Ok(pat) } @@ -1007,6 +1009,6 @@ impl<'a> Parser<'a> { } fn mk_pat(&self, span: Span, kind: PatKind) -> P { - P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) + P(Pat { kind, span, id: ast::DUMMY_NODE_ID, leading_vert: false, tokens: None }) } } diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 633d153e391dd..7319b17d8e34e 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -164,6 +164,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, + leading_vert: false, tokens: None, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e))) diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs new file mode 100644 index 0000000000000..7d31de1d22df2 --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs @@ -0,0 +1,16 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// +// Regression test for issue #76182 +// Tests that we properly handle patterns with a leading vert + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn main() { + match () { | () => () } +} diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout new file mode 100644 index 0000000000000..5493f9c7b606b --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout @@ -0,0 +1,62 @@ +PRINT-ATTR INPUT (DISPLAY): fn main() { match() { | () => () } } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/issue-76182-leading-vert-pat.rs:14:1: 14:3 (#0), + }, + Ident { + ident: "main", + span: $DIR/issue-76182-leading-vert-pat.rs:14:4: 14:8 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:14:8: 14:10 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "match", + span: $DIR/issue-76182-leading-vert-pat.rs:15:5: 15:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:11: 15:13 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:16: 15:17 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:18: 15:20 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:24: 15:26 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:15:14: 15:28 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:14:11: 16:2 (#0), + }, +] diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 7f4f16f8faf96..22af8577c2249 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -340,6 +340,7 @@ fn take_pat(from: &mut Pat) -> Pat { id: DUMMY_NODE_ID, kind: Wild, span: DUMMY_SP, + leading_vert: false, tokens: None, }; mem::replace(from, dummy)