From 5404deeb64f4449079f5165ace6bfa1e52ca4b33 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Wed, 14 Oct 2020 22:27:48 +0200 Subject: Gracefully handle mistyping -> as => in function return type --- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- compiler/rustc_parse/src/parser/item.rs | 4 ++-- compiler/rustc_parse/src/parser/path.rs | 5 +++-- compiler/rustc_parse/src/parser/ty.rs | 21 +++++++++++++++++++++ 4 files changed, 28 insertions(+), 6 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93be478fc8c..790a0c867af 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,5 +1,5 @@ use super::pat::{GateOr, PARAM_EXPECTED}; -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; @@ -1647,7 +1647,7 @@ impl<'a> Parser<'a> { self.expect_or()?; args }; - let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?; + let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverFatArrow::Yes)?; Ok(P(FnDecl { inputs, output })) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5954b370e6d..9e342a0d681 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,5 +1,5 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; @@ -1648,7 +1648,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { Ok(P(FnDecl { inputs: self.parse_fn_params(req_name)?, - output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?, + output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, RecoverFatArrow::Yes)?, })) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 17e5bcf7605..311a4829fcf 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,4 +1,4 @@ -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_ast::ptr::P; @@ -231,7 +231,8 @@ impl<'a> Parser<'a> { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = ident.span.to(self.prev_token.span); - let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?; + let output = + self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverFatArrow::No)?; ParenthesizedArgs { inputs, output, span }.into() }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 7a6ebca4e15..ff19c5cfa85 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,6 +43,12 @@ pub(super) enum RecoverQPath { No, } +#[derive(PartialEq)] +pub(super) enum RecoverFatArrow { + Yes, + No, +} + // Is `...` (`CVarArgs`) legal at this level of type parsing? #[derive(PartialEq)] enum AllowCVariadic { @@ -87,11 +93,26 @@ impl<'a> Parser<'a> { &mut self, allow_plus: AllowPlus, recover_qpath: RecoverQPath, + recover_fat_arrow: RecoverFatArrow, ) -> PResult<'a, FnRetTy> { Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; FnRetTy::Ty(ty) + } else if recover_fat_arrow == RecoverFatArrow::Yes && self.token == token::FatArrow { + // Don't `eat` to prevent `=>` from being added as an expected token which isn't + // actually expected and could only confuse users + self.bump(); + self.struct_span_err(self.prev_token.span, "return types are denoted using `->`") + .span_suggestion_short( + self.prev_token.span, + "use `->` instead", + "->".to_string(), + Applicability::MachineApplicable, + ) + .emit(); + let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + FnRetTy::Ty(ty) } else { FnRetTy::Default(self.token.span.shrink_to_lo()) }) -- cgit 1.4.1-3-g733a5 From 3548be94c03fd6d1c11afd6af9c884f398a6489e Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Thu, 15 Oct 2020 21:21:45 +0200 Subject: Gracefully handle confusing -> with : in function return type --- compiler/rustc_parse/src/parser/expr.rs | 5 +- compiler/rustc_parse/src/parser/generics.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 7 ++- compiler/rustc_parse/src/parser/path.rs | 4 +- compiler/rustc_parse/src/parser/ty.rs | 78 +++++++++++++++++++++----- src/test/ui/fn/fn-fat-arrow-return.fixed | 18 ------ src/test/ui/fn/fn-fat-arrow-return.rs | 18 ------ src/test/ui/fn/fn-fat-arrow-return.stderr | 8 --- src/test/ui/fn/fn-fat-arrow-return2.rs | 10 ---- src/test/ui/fn/fn-fat-arrow-return2.stderr | 14 ----- src/test/ui/fn/fn-recover-return-sign.fixed | 28 +++++++++ src/test/ui/fn/fn-recover-return-sign.rs | 28 +++++++++ src/test/ui/fn/fn-recover-return-sign.stderr | 26 +++++++++ src/test/ui/fn/fn-recover-return-sign2.rs | 8 +++ src/test/ui/fn/fn-recover-return-sign2.stderr | 14 +++++ src/test/ui/parser/fn-colon-return-type.rs | 3 +- src/test/ui/parser/fn-colon-return-type.stderr | 4 +- src/test/ui/parser/not-a-pred.rs | 13 ++++- src/test/ui/parser/not-a-pred.stderr | 32 ++++++++++- 19 files changed, 223 insertions(+), 97 deletions(-) delete mode 100644 src/test/ui/fn/fn-fat-arrow-return.fixed delete mode 100644 src/test/ui/fn/fn-fat-arrow-return.rs delete mode 100644 src/test/ui/fn/fn-fat-arrow-return.stderr delete mode 100644 src/test/ui/fn/fn-fat-arrow-return2.rs delete mode 100644 src/test/ui/fn/fn-fat-arrow-return2.stderr create mode 100644 src/test/ui/fn/fn-recover-return-sign.fixed create mode 100644 src/test/ui/fn/fn-recover-return-sign.rs create mode 100644 src/test/ui/fn/fn-recover-return-sign.stderr create mode 100644 src/test/ui/fn/fn-recover-return-sign2.rs create mode 100644 src/test/ui/fn/fn-recover-return-sign2.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 790a0c867af..4d2167442be 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,5 +1,5 @@ use super::pat::{GateOr, PARAM_EXPECTED}; -use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; @@ -1647,7 +1647,8 @@ impl<'a> Parser<'a> { self.expect_or()?; args }; - let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverFatArrow::Yes)?; + let output = + self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?; Ok(P(FnDecl { inputs, output })) } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index dd99a7587dd..ed8d4f78426 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -240,7 +240,7 @@ impl<'a> Parser<'a> { // Parse type with mandatory colon and (possibly empty) bounds, // or with mandatory equality sign and the second type. - let ty = self.parse_ty()?; + let ty = self.parse_ty_for_where_clause()?; if self.eat(&token::Colon) { let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9e342a0d681..ff0323a107a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,5 +1,5 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; -use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; @@ -1514,7 +1514,7 @@ impl<'a> Parser<'a> { let header = self.parse_fn_front_matter()?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` - let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)` + let decl = self.parse_fn_decl(req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)` generics.where_clause = self.parse_where_clause()?; // `where T: Ord` let mut sig_hi = self.prev_token.span; @@ -1645,10 +1645,11 @@ impl<'a> Parser<'a> { &mut self, req_name: ReqName, ret_allow_plus: AllowPlus, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { Ok(P(FnDecl { inputs: self.parse_fn_params(req_name)?, - output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, RecoverFatArrow::Yes)?, + output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?, })) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 311a4829fcf..4510e86e034 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,4 +1,4 @@ -use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_ast::ptr::P; @@ -232,7 +232,7 @@ impl<'a> Parser<'a> { let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = ident.span.to(self.prev_token.span); let output = - self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverFatArrow::No)?; + self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; ParenthesizedArgs { inputs, output, span }.into() }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index ff19c5cfa85..ee0dc8f6304 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,12 +43,23 @@ pub(super) enum RecoverQPath { No, } -#[derive(PartialEq)] -pub(super) enum RecoverFatArrow { +#[derive(Copy, Clone, PartialEq)] +pub(super) enum RecoverReturnSign { Yes, + OnlyFatArrow, No, } +impl RecoverReturnSign { + fn can_recover(self, token: &TokenKind) -> bool { + match self { + Self::Yes => matches!(token, token::FatArrow | token::Colon), + Self::OnlyFatArrow => matches!(token, token::FatArrow), + Self::No => false, + } + } +} + // Is `...` (`CVarArgs`) legal at this level of type parsing? #[derive(PartialEq)] enum AllowCVariadic { @@ -68,14 +79,24 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::No) + self.parse_ty_common( + AllowPlus::Yes, + RecoverQPath::Yes, + AllowCVariadic::No, + RecoverReturnSign::Yes, + ) } /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes) + self.parse_ty_common( + AllowPlus::Yes, + RecoverQPath::Yes, + AllowCVariadic::Yes, + RecoverReturnSign::Yes, + ) } /// Parses a type in restricted contexts where `+` is not permitted. @@ -85,7 +106,22 @@ impl<'a> Parser<'a> { /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::No, RecoverQPath::Yes, AllowCVariadic::No) + self.parse_ty_common( + AllowPlus::No, + RecoverQPath::Yes, + AllowCVariadic::No, + RecoverReturnSign::Yes, + ) + } + + /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>` + pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P> { + self.parse_ty_common( + AllowPlus::Yes, + RecoverQPath::Yes, + AllowCVariadic::Yes, + RecoverReturnSign::OnlyFatArrow, + ) } /// Parses an optional return type `[ -> TY ]` in a function declaration. @@ -93,13 +129,18 @@ impl<'a> Parser<'a> { &mut self, allow_plus: AllowPlus, recover_qpath: RecoverQPath, - recover_fat_arrow: RecoverFatArrow, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, FnRetTy> { Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? - let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + let ty = self.parse_ty_common( + allow_plus, + recover_qpath, + AllowCVariadic::No, + recover_return_sign, + )?; FnRetTy::Ty(ty) - } else if recover_fat_arrow == RecoverFatArrow::Yes && self.token == token::FatArrow { + } else if recover_return_sign.can_recover(&self.token.kind) { // Don't `eat` to prevent `=>` from being added as an expected token which isn't // actually expected and could only confuse users self.bump(); @@ -111,7 +152,12 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ) .emit(); - let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + let ty = self.parse_ty_common( + allow_plus, + recover_qpath, + AllowCVariadic::No, + recover_return_sign, + )?; FnRetTy::Ty(ty) } else { FnRetTy::Default(self.token.span.shrink_to_lo()) @@ -123,6 +169,7 @@ impl<'a> Parser<'a> { allow_plus: AllowPlus, recover_qpath: RecoverQPath, allow_c_variadic: AllowCVariadic, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); @@ -150,14 +197,14 @@ impl<'a> Parser<'a> { TyKind::Infer } else if self.check_fn_front_matter() { // Function pointer type - self.parse_ty_bare_fn(lo, Vec::new())? + self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)? } else if self.check_keyword(kw::For) { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` let lifetime_defs = self.parse_late_bound_lifetime_defs()?; if self.check_fn_front_matter() { - self.parse_ty_bare_fn(lo, lifetime_defs)? + self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)? } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); @@ -359,9 +406,14 @@ impl<'a> Parser<'a> { /// Function Style ABI Parameter types /// ``` /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers. - fn parse_ty_bare_fn(&mut self, lo: Span, params: Vec) -> PResult<'a, TyKind> { + fn parse_ty_bare_fn( + &mut self, + lo: Span, + params: Vec, + recover_return_sign: RecoverReturnSign, + ) -> PResult<'a, TyKind> { let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?; - let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?; + let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; let whole_span = lo.to(self.prev_token.span); if let ast::Const::Yes(span) = constness { self.error_fn_ptr_bad_qualifier(whole_span, span, "const"); diff --git a/src/test/ui/fn/fn-fat-arrow-return.fixed b/src/test/ui/fn/fn-fat-arrow-return.fixed deleted file mode 100644 index 0acca85aa67..00000000000 --- a/src/test/ui/fn/fn-fat-arrow-return.fixed +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix -#![allow(unused)] -fn a() -> usize { 0 } -//~^ ERROR return types are denoted using `->` - -fn bar(_: u32) {} - -fn baz() -> *const dyn Fn(u32) { unimplemented!() } - -fn foo() { - match () { - _ if baz() == &bar as &dyn Fn(u32) => (), - () => (), - } -} - -fn main() { -} diff --git a/src/test/ui/fn/fn-fat-arrow-return.rs b/src/test/ui/fn/fn-fat-arrow-return.rs deleted file mode 100644 index 4bdcd70d7fc..00000000000 --- a/src/test/ui/fn/fn-fat-arrow-return.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix -#![allow(unused)] -fn a() => usize { 0 } -//~^ ERROR return types are denoted using `->` - -fn bar(_: u32) {} - -fn baz() -> *const dyn Fn(u32) { unimplemented!() } - -fn foo() { - match () { - _ if baz() == &bar as &dyn Fn(u32) => (), - () => (), - } -} - -fn main() { -} diff --git a/src/test/ui/fn/fn-fat-arrow-return.stderr b/src/test/ui/fn/fn-fat-arrow-return.stderr deleted file mode 100644 index 1fcdb18a514..00000000000 --- a/src/test/ui/fn/fn-fat-arrow-return.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: return types are denoted using `->` - --> $DIR/fn-fat-arrow-return.rs:3:8 - | -LL | fn a() => usize { 0 } - | ^^ help: use `->` instead - -error: aborting due to previous error - diff --git a/src/test/ui/fn/fn-fat-arrow-return2.rs b/src/test/ui/fn/fn-fat-arrow-return2.rs deleted file mode 100644 index 316fa2cbf02..00000000000 --- a/src/test/ui/fn/fn-fat-arrow-return2.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn a() => impl Fn() => bool { - //~^ ERROR return types are denoted using `->` - //~| ERROR expected `;` or `{`, found `=>` - unimplemented!() -} - -fn main() { - let foo = |a: bool| => bool { a }; - dbg!(foo(false)); -} diff --git a/src/test/ui/fn/fn-fat-arrow-return2.stderr b/src/test/ui/fn/fn-fat-arrow-return2.stderr deleted file mode 100644 index a6f9fe3b573..00000000000 --- a/src/test/ui/fn/fn-fat-arrow-return2.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: return types are denoted using `->` - --> $DIR/fn-fat-arrow-return2.rs:1:8 - | -LL | fn a() => impl Fn() => bool { - | ^^ help: use `->` instead - -error: expected `;` or `{`, found `=>` - --> $DIR/fn-fat-arrow-return2.rs:1:21 - | -LL | fn a() => impl Fn() => bool { - | ^^ expected `;` or `{` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/fn/fn-recover-return-sign.fixed b/src/test/ui/fn/fn-recover-return-sign.fixed new file mode 100644 index 00000000000..076be6a35a4 --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.fixed @@ -0,0 +1,28 @@ +// run-rustfix +#![allow(unused)] +fn a() -> usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn b()-> usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { + let foo = |a: bool| -> bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(foo(false)); + + let bar = |a: bool|-> bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(bar(false)); +} diff --git a/src/test/ui/fn/fn-recover-return-sign.rs b/src/test/ui/fn/fn-recover-return-sign.rs new file mode 100644 index 00000000000..0656023c0f8 --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.rs @@ -0,0 +1,28 @@ +// run-rustfix +#![allow(unused)] +fn a() => usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn b(): usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { + let foo = |a: bool| => bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(foo(false)); + + let bar = |a: bool|: bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(bar(false)); +} diff --git a/src/test/ui/fn/fn-recover-return-sign.stderr b/src/test/ui/fn/fn-recover-return-sign.stderr new file mode 100644 index 00000000000..983109730ff --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.stderr @@ -0,0 +1,26 @@ +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:3:8 + | +LL | fn a() => usize { 0 } + | ^^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:6:7 + | +LL | fn b(): usize { 0 } + | ^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:21:25 + | +LL | let foo = |a: bool| => bool { a }; + | ^^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:25:24 + | +LL | let bar = |a: bool|: bool { a }; + | ^ help: use `->` instead + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/fn/fn-recover-return-sign2.rs b/src/test/ui/fn/fn-recover-return-sign2.rs new file mode 100644 index 00000000000..b6a6a1ec2a6 --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign2.rs @@ -0,0 +1,8 @@ +// Separate test file because `Fn() => bool` isn't getting fixed and rustfix complained that +// even though a fix was applied the code was still incorrect + +fn foo() => impl Fn() => bool { + //~^ ERROR return types are denoted using `->` + //~| ERROR expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>` + unimplemented!() +} diff --git a/src/test/ui/fn/fn-recover-return-sign2.stderr b/src/test/ui/fn/fn-recover-return-sign2.stderr new file mode 100644 index 00000000000..d62cacd4bf5 --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign2.stderr @@ -0,0 +1,14 @@ +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign2.rs:4:10 + | +LL | fn foo() => impl Fn() => bool { + | ^^ help: use `->` instead + +error: expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>` + --> $DIR/fn-recover-return-sign2.rs:4:23 + | +LL | fn foo() => impl Fn() => bool { + | ^^ expected one of `+`, `->`, `::`, `;`, `where`, or `{` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/fn-colon-return-type.rs b/src/test/ui/parser/fn-colon-return-type.rs index c791fb3ae67..0001ef57c99 100644 --- a/src/test/ui/parser/fn-colon-return-type.rs +++ b/src/test/ui/parser/fn-colon-return-type.rs @@ -1,4 +1,5 @@ -fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` +fn foo(x: i32): i32 { +//~^ ERROR return types are denoted using `->` x } diff --git a/src/test/ui/parser/fn-colon-return-type.stderr b/src/test/ui/parser/fn-colon-return-type.stderr index 92df9bc60bd..1de91878205 100644 --- a/src/test/ui/parser/fn-colon-return-type.stderr +++ b/src/test/ui/parser/fn-colon-return-type.stderr @@ -1,8 +1,8 @@ -error: expected one of `->`, `;`, `where`, or `{`, found `:` +error: return types are denoted using `->` --> $DIR/fn-colon-return-type.rs:1:15 | LL | fn foo(x: i32): i32 { - | ^ expected one of `->`, `;`, `where`, or `{` + | ^ help: use `->` instead error: aborting due to previous error diff --git a/src/test/ui/parser/not-a-pred.rs b/src/test/ui/parser/not-a-pred.rs index 1b3d9bf66bb..5518b554d8e 100644 --- a/src/test/ui/parser/not-a-pred.rs +++ b/src/test/ui/parser/not-a-pred.rs @@ -1,6 +1,15 @@ fn f(a: isize, b: isize) : lt(a, b) { } -//~^ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` +//~^ ERROR return types are denoted using `->` +//~| ERROR expected type, found function `lt` [E0573] +//~| ERROR expected type, found local variable `a` [E0573] +//~| ERROR expected type, found local variable `b` [E0573] fn lt(a: isize, b: isize) { } -fn main() { let a: isize = 10; let b: isize = 23; check (lt(a, b)); f(a, b); } +fn main() { + let a: isize = 10; + let b: isize = 23; + check (lt(a, b)); + //~^ ERROR cannot find function `check` in this scope [E0425] + f(a, b); +} diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr index ec413c5594c..bcc64a687fd 100644 --- a/src/test/ui/parser/not-a-pred.stderr +++ b/src/test/ui/parser/not-a-pred.stderr @@ -1,8 +1,34 @@ -error: expected one of `->`, `;`, `where`, or `{`, found `:` +error: return types are denoted using `->` --> $DIR/not-a-pred.rs:1:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ expected one of `->`, `;`, `where`, or `{` + | ^ help: use `->` instead -error: aborting due to previous error +error[E0573]: expected type, found function `lt` + --> $DIR/not-a-pred.rs:1:28 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^^^^^^^^ not a type + +error[E0573]: expected type, found local variable `a` + --> $DIR/not-a-pred.rs:1:31 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^ not a type + +error[E0573]: expected type, found local variable `b` + --> $DIR/not-a-pred.rs:1:34 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^ not a type + +error[E0425]: cannot find function `check` in this scope + --> $DIR/not-a-pred.rs:12:5 + | +LL | check (lt(a, b)); + | ^^^^^ not found in this scope + +error: aborting due to 5 previous errors +Some errors have detailed explanations: E0425, E0573. +For more information about an error, try `rustc --explain E0425`. -- cgit 1.4.1-3-g733a5 From 1e27b65d8e877fd33ff8de20c359282577b8956c Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Thu, 3 Dec 2020 12:37:19 -0600 Subject: Recover on `const impl<> X for Y` --- compiler/rustc_parse/src/parser/item.rs | 41 ++++++++++++++++++++-- .../const-impl-norecover.rs | 13 +++++++ .../const-impl-norecover.stderr | 8 +++++ .../const-impl-recovery.rs | 16 +++++++++ .../const-impl-recovery.stderr | 24 +++++++++++++ 5 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5954b370e6d..4c92c198679 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -247,9 +247,14 @@ impl<'a> Parser<'a> { (ident, ItemKind::Static(ty, m, expr)) } else if let Const::Yes(const_span) = self.parse_constness() { // CONST ITEM - self.recover_const_mut(const_span); - let (ident, ty, expr) = self.parse_item_global(None)?; - (ident, ItemKind::Const(def(), ty, expr)) + if self.token.is_keyword(kw::Impl) { + // recover from `const impl`, suggest `impl const` + self.recover_const_impl(const_span, attrs, def())? + } else { + self.recover_const_mut(const_span); + let (ident, ty, expr) = self.parse_item_global(None)?; + (ident, ItemKind::Const(def(), ty, expr)) + } } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM self.parse_item_trait(attrs, lo)? @@ -988,6 +993,36 @@ impl<'a> Parser<'a> { } } + /// Recover on `const impl` with `const` already eaten. + fn recover_const_impl( + &mut self, + const_span: Span, + attrs: &mut Vec, + defaultness: Defaultness, + ) -> PResult<'a, ItemInfo> { + let impl_span = self.token.span; + let mut err = self.expected_ident_found(); + let mut impl_info = self.parse_item_impl(attrs, defaultness)?; + match impl_info.1 { + // only try to recover if this is implementing a trait for a type + ItemKind::Impl { of_trait: Some(ref trai), ref mut constness, .. } => { + *constness = Const::Yes(const_span); + + let before_trait = trai.path.span.shrink_to_lo(); + let const_up_to_impl = const_span.with_hi(impl_span.lo()); + err.multipart_suggestion( + "you might have meant to write a const trait impl", + vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())], + Applicability::MaybeIncorrect, + ) + .emit(); + } + ItemKind::Impl { .. } => return Err(err), + _ => unreachable!(), + } + Ok(impl_info) + } + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. /// diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs new file mode 100644 index 00000000000..936c90e88aa --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs @@ -0,0 +1,13 @@ +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +struct Foo; + +const impl Foo { //~ ERROR: expected identifier, found keyword + fn bar() {} +} + +fn main() { + // shouldn't error here because we shouldn't have been able to recover above + Foo::bar(); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr new file mode 100644 index 00000000000..612511a4799 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-norecover.rs:6:7 + | +LL | const impl Foo { + | ^^^^ expected identifier, found keyword + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs new file mode 100644 index 00000000000..fd3dd2cef9d --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs @@ -0,0 +1,16 @@ +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +trait Foo {} + +const impl Foo for i32 {} //~ ERROR: expected identifier, found keyword + +trait Bar {} + +const impl Bar for T {} //~ ERROR: expected identifier, found keyword + +const fn still_implements() {} + +const _: () = still_implements::(); + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr new file mode 100644 index 00000000000..84fb619dc96 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr @@ -0,0 +1,24 @@ +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-recovery.rs:6:7 + | +LL | const impl Foo for i32 {} + | ^^^^ expected identifier, found keyword + | +help: you might have meant to write a const trait impl + | +LL | impl const Foo for i32 {} + |-- ^^^^^ + +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-recovery.rs:10:7 + | +LL | const impl Bar for T {} + | ^^^^ expected identifier, found keyword + | +help: you might have meant to write a const trait impl + | +LL | impl const Bar for T {} + |-- ^^^^^ + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From e6fa6334dd54f7c96514b520c5b9f261df3fc16b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 12 Dec 2020 15:20:22 -0500 Subject: Properly capture trailing 'unglued' token If we try to capture the `Vec` in `Option>`, we'll need to capture a `>` token which was 'unglued' from a `>>` token. The processing of unglueing a token for parsing purposes bypasses the usual capturing infrastructure, so we currently lose the trailing `>`. As a result, we fall back to the reparsed `TokenStream`, causing us to lose spans. This commit makes token capturing keep track of a trailing 'unglued' token. Note that we don't need to care about unglueing except at the end of the captured tokens - if we capture both the first and second unglued tokens, then we'll end up capturing the full 'glued' token, which already works correctly. --- compiler/rustc_parse/src/parser/mod.rs | 67 +++++++++++++++++++--- src/test/ui/proc-macro/capture-unglued-token.rs | 20 +++++++ .../ui/proc-macro/capture-unglued-token.stdout | 28 +++++++++ 3 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/proc-macro/capture-unglued-token.rs create mode 100644 src/test/ui/proc-macro/capture-unglued-token.stdout (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index df4695b18e7..d51a0fcbf09 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -17,7 +17,7 @@ pub use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, Spacing}; -use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit}; @@ -132,6 +132,28 @@ struct TokenCursor { // Counts the number of calls to `next` or `next_desugared`, // depending on whether `desugar_doc_comments` is set. num_next_calls: usize, + // During parsing, we may sometimes need to 'unglue' a + // glued token into two component tokens + // (e.g. '>>' into '>' and '>), so that the parser + // can consume them one at a time. This process + // bypasses the normal capturing mechanism + // (e.g. `num_next_calls` will not be incremented), + // since the 'unglued' tokens due not exist in + // the original `TokenStream`. + // + // If we end up consuming both unglued tokens, + // then this is not an issue - we'll end up + // capturing the single 'glued' token. + // + // However, in certain circumstances, we may + // want to capture just the first 'unglued' token. + // For example, capturing the `Vec` + // in `Option>` requires us to unglue + // the trailing `>>` token. The `append_unglued_token` + // field is used to track this token - it gets + // appended to the captured stream when + // we evaluate a `LazyTokenStream` + append_unglued_token: Option, } #[derive(Clone)] @@ -336,6 +358,7 @@ impl<'a> Parser<'a> { stack: Vec::new(), num_next_calls: 0, desugar_doc_comments, + append_unglued_token: None, }, desugar_doc_comments, unmatched_angle_bracket_count: 0, @@ -359,6 +382,10 @@ impl<'a> Parser<'a> { self.token_cursor.next() }; self.token_cursor.num_next_calls += 1; + // We've retrieved an token from the underlying + // cursor, so we no longer need to worry about + // an unglued token. See `break_and_eat` for more details + self.token_cursor.append_unglued_token = None; if next.span.is_dummy() { // Tweak the location for better diagnostics, but keep syntactic context intact. next.span = fallback_span.with_ctxt(next.span.ctxt()); @@ -555,6 +582,14 @@ impl<'a> Parser<'a> { let first_span = self.sess.source_map().start_point(self.token.span); let second_span = self.token.span.with_lo(first_span.hi()); self.token = Token::new(first, first_span); + // Keep track of this token - if we end token capturing now, + // we'll want to append this token to the captured stream. + // + // If we consume any additional tokens, then this token + // is not needed (we'll capture the entire 'glued' token), + // and `next_tok` will set this field to `None` + self.token_cursor.append_unglued_token = + Some((TokenTree::Token(self.token.clone()), Spacing::Alone)); // Use the spacing of the glued token as the spacing // of the unglued second token. self.bump_with((Token::new(second, second_span), self.token_spacing)); @@ -1230,6 +1265,7 @@ impl<'a> Parser<'a> { num_calls: usize, desugar_doc_comments: bool, trailing_semi: bool, + append_unglued_token: Option, } impl CreateTokenStream for LazyTokenStreamImpl { fn create_token_stream(&self) -> TokenStream { @@ -1253,12 +1289,18 @@ impl<'a> Parser<'a> { })) .take(num_calls); - make_token_stream(tokens) + make_token_stream(tokens, self.append_unglued_token.clone()) } fn add_trailing_semi(&self) -> Box { if self.trailing_semi { panic!("Called `add_trailing_semi` twice!"); } + if self.append_unglued_token.is_some() { + panic!( + "Cannot call `add_trailing_semi` when we have an unglued token {:?}", + self.append_unglued_token + ); + } let mut new = self.clone(); new.trailing_semi = true; Box::new(new) @@ -1271,6 +1313,7 @@ impl<'a> Parser<'a> { cursor_snapshot, desugar_doc_comments: self.desugar_doc_comments, trailing_semi: false, + append_unglued_token: self.token_cursor.append_unglued_token.clone(), }; Ok((ret, Some(LazyTokenStream::new(lazy_impl)))) } @@ -1325,7 +1368,10 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &Pa /// Converts a flattened iterator of tokens (including open and close delimiter tokens) /// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair /// of open and close delims. -fn make_token_stream(tokens: impl Iterator) -> TokenStream { +fn make_token_stream( + tokens: impl Iterator, + append_unglued_token: Option, +) -> TokenStream { #[derive(Debug)] struct FrameData { open: Span, @@ -1348,14 +1394,17 @@ fn make_token_stream(tokens: impl Iterator) -> TokenStr .inner .push((delimited, Spacing::Alone)); } - token => stack - .last_mut() - .expect("Bottom token frame is missing!") - .inner - .push((TokenTree::Token(token), spacing)), + token => { + stack + .last_mut() + .expect("Bottom token frame is missing!") + .inner + .push((TokenTree::Token(token), spacing)); + } } } - let final_buf = stack.pop().expect("Missing final buf!"); + let mut final_buf = stack.pop().expect("Missing final buf!"); + final_buf.inner.extend(append_unglued_token); assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack); TokenStream::new(final_buf.inner) } diff --git a/src/test/ui/proc-macro/capture-unglued-token.rs b/src/test/ui/proc-macro/capture-unglued-token.rs new file mode 100644 index 00000000000..727b779776b --- /dev/null +++ b/src/test/ui/proc-macro/capture-unglued-token.rs @@ -0,0 +1,20 @@ +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// check-pass + +// Tests that we properly handle parsing a nonterminal +// where we have two consecutive angle brackets (one inside +// the nonterminal, and one outside) + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; +extern crate test_macros; + +macro_rules! trailing_angle { + (Option<$field:ty>) => { + test_macros::print_bang_consume!($field); + } +} + +trailing_angle!(Option>); +fn main() {} diff --git a/src/test/ui/proc-macro/capture-unglued-token.stdout b/src/test/ui/proc-macro/capture-unglued-token.stdout new file mode 100644 index 00000000000..7e6b540332c --- /dev/null +++ b/src/test/ui/proc-macro/capture-unglued-token.stdout @@ -0,0 +1,28 @@ +PRINT-BANG INPUT (DISPLAY): Vec +PRINT-BANG RE-COLLECTED (DISPLAY): Vec < u8 > +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "Vec", + span: $DIR/capture-unglued-token.rs:19:24: 19:27 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/capture-unglued-token.rs:19:27: 19:28 (#0), + }, + Ident { + ident: "u8", + span: $DIR/capture-unglued-token.rs:19:28: 19:30 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/capture-unglued-token.rs:19:30: 19:31 (#0), + }, + ], + span: $DIR/capture-unglued-token.rs:15:42: 15:48 (#4), + }, +] -- cgit 1.4.1-3-g733a5 From e916641fd35bddabc8b018a5e51fe23b93875c66 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Thu, 17 Dec 2020 13:44:08 +0100 Subject: Address review comments --- compiler/rustc_parse/src/parser/ty.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index ee0dc8f6304..9553f5d09e8 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,6 +43,16 @@ pub(super) enum RecoverQPath { No, } +/// Signals whether parsing a type should recover `->`. +/// +/// More specifically, when parsing a function like: +/// ```rust +/// fn foo() => u8 { 0 } +/// fn bar(): u8 { 0 } +/// ``` +/// The compiler will try to recover interpreting `foo() => u8` as `foo() -> u8` when calling +/// `parse_ty` with anything except `RecoverReturnSign::No`, and it will try to recover `bar(): u8` +/// as `bar() -> u8` when passing `RecoverReturnSign::Yes` to `parse_ty` #[derive(Copy, Clone, PartialEq)] pub(super) enum RecoverReturnSign { Yes, @@ -51,6 +61,10 @@ pub(super) enum RecoverReturnSign { } impl RecoverReturnSign { + /// [RecoverReturnSign::Yes] allows for recovering `fn foo() => u8` and `fn foo(): u8`, + /// [RecoverReturnSign::OnlyFatArrow] allows for recovering only `fn foo() => u8` (recovering + /// colons can cause problems when parsing where clauses), and + /// [RecoverReturnSign::No] doesn't allow for any recovery of the return type arrow fn can_recover(self, token: &TokenKind) -> bool { match self { Self::Yes => matches!(token, token::FatArrow | token::Colon), @@ -81,8 +95,8 @@ impl<'a> Parser<'a> { pub fn parse_ty(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::No, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -93,8 +107,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::Yes, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -108,8 +122,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::No, - RecoverQPath::Yes, AllowCVariadic::No, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -118,8 +132,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::Yes, + RecoverQPath::Yes, RecoverReturnSign::OnlyFatArrow, ) } @@ -135,8 +149,8 @@ impl<'a> Parser<'a> { // FIXME(Centril): Can we unconditionally `allow_plus`? let ty = self.parse_ty_common( allow_plus, - recover_qpath, AllowCVariadic::No, + recover_qpath, recover_return_sign, )?; FnRetTy::Ty(ty) @@ -154,8 +168,8 @@ impl<'a> Parser<'a> { .emit(); let ty = self.parse_ty_common( allow_plus, - recover_qpath, AllowCVariadic::No, + recover_qpath, recover_return_sign, )?; FnRetTy::Ty(ty) @@ -167,8 +181,8 @@ impl<'a> Parser<'a> { fn parse_ty_common( &mut self, allow_plus: AllowPlus, - recover_qpath: RecoverQPath, allow_c_variadic: AllowCVariadic, + recover_qpath: RecoverQPath, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; -- cgit 1.4.1-3-g733a5 From d6f1787447e1132d929efbb5b772be232e336c23 Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 17 Dec 2020 13:51:20 -0800 Subject: Don't allow `const` to begin a nonterminal Thanks to Vadim Petrochenkov who [told me what the fix was][z]! [z]: https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/finding.20which.20macro.20rule.20to.20use/near/220240422 --- compiler/rustc_parse/src/parser/nonterminal.rs | 2 ++ src/test/ui/inline-const/macro-with-const.rs | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/inline-const/macro-with-const.rs (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index c007f96a798..76ad5acd530 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -27,6 +27,8 @@ impl<'a> Parser<'a> { token.can_begin_expr() // This exception is here for backwards compatibility. && !token.is_keyword(kw::Let) + // This exception is here for backwards compatibility. + && !token.is_keyword(kw::Const) } NonterminalKind::Ty => token.can_begin_type(), NonterminalKind::Ident => get_macro_ident(token).is_some(), diff --git a/src/test/ui/inline-const/macro-with-const.rs b/src/test/ui/inline-const/macro-with-const.rs new file mode 100644 index 00000000000..e7393166d8d --- /dev/null +++ b/src/test/ui/inline-const/macro-with-const.rs @@ -0,0 +1,20 @@ +// check-pass + +macro_rules! exp { + (const $n:expr) => { + $n + }; +} + +macro_rules! stmt { + (exp $e:expr) => { + $e + }; + (exp $($t:tt)+) => { + exp!($($t)+) + }; +} + +fn main() { + stmt!(exp const 1); +} -- cgit 1.4.1-3-g733a5 From 1a7d00a529503ac38a6b1ae28e8e779e434e02e0 Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 10 Nov 2020 18:00:53 -0600 Subject: implement edition-specific :pat behavior for 2015/18 --- compiler/rustc_expand/src/mbe/macro_parser.rs | 33 +++++++++++---- compiler/rustc_parse/src/parser/expr.rs | 8 ++-- compiler/rustc_parse/src/parser/mod.rs | 1 + compiler/rustc_parse/src/parser/nonterminal.rs | 23 +++++++++-- compiler/rustc_parse/src/parser/pat.rs | 17 ++++++-- compiler/rustc_parse/src/parser/stmt.rs | 4 +- src/test/ui/macros/macro-pat-follow-2018.rs | 15 +++++++ src/test/ui/macros/macro-pat-follow.rs | 16 ++------ .../or-patterns/or-patterns-syntactic-fail-2018.rs | 15 +++++++ .../or-patterns-syntactic-fail-2018.stderr | 20 +++++++++ .../ui/or-patterns/or-patterns-syntactic-fail.rs | 10 ----- .../or-patterns/or-patterns-syntactic-fail.stderr | 48 +++++++--------------- .../or-patterns/or-patterns-syntactic-pass-2021.rs | 14 +++++++ src/test/ui/pattern/or-pattern-macro-pat.rs | 44 ++++++++++++++++++++ 14 files changed, 193 insertions(+), 75 deletions(-) create mode 100644 src/test/ui/macros/macro-pat-follow-2018.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs create mode 100644 src/test/ui/pattern/or-pattern-macro-pat.rs (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index c37f9125675..3cf2d8f8ac1 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -77,9 +77,9 @@ use TokenTreeOrTokenTreeSlice::*; use crate::mbe::{self, TokenTree}; use rustc_ast::token::{self, DocComment, Nonterminal, Token}; -use rustc_parse::parser::Parser; +use rustc_parse::parser::{OrPatNonterminalMode, Parser}; use rustc_session::parse::ParseSess; -use rustc_span::symbol::MacroRulesNormalizedIdent; +use rustc_span::{edition::Edition, symbol::MacroRulesNormalizedIdent}; use smallvec::{smallvec, SmallVec}; @@ -414,6 +414,18 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { } } +/// In edition 2015/18, `:pat` can only match `pat` because otherwise, we have +/// breakage. As of edition 2021, `:pat` matches `top_pat`. +/// +/// See for more info. +fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode { + match edition { + Edition::Edition2015 | Edition::Edition2018 => OrPatNonterminalMode::NoTopAlt, + // FIXME(mark-i-m): uncomment this when edition 2021 machinery is added. + // Edition::Edition2021 => OrPatNonterminalMode::TopPat, + } +} + /// Process the matcher positions of `cur_items` until it is empty. In the process, this will /// produce more items in `next_items`, `eof_items`, and `bb_items`. /// @@ -553,10 +565,14 @@ fn inner_parse_loop<'root, 'tt>( // We need to match a metavar with a valid ident... call out to the black-box // parser by adding an item to `bb_items`. - TokenTree::MetaVarDecl(_, _, kind) => { - // Built-in nonterminals never start with these tokens, - // so we can eliminate them from consideration. - if Parser::nonterminal_may_begin_with(kind, token) { + TokenTree::MetaVarDecl(span, _, kind) => { + // Built-in nonterminals never start with these tokens, so we can eliminate + // them from consideration. + // + // We use the span of the metavariable declaration to determine any + // edition-specific matching behavior for non-terminals. + if Parser::nonterminal_may_begin_with(kind, token, or_pat_mode(span.edition())) + { bb_items.push(item); } } @@ -717,7 +733,10 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na let mut item = bb_items.pop().unwrap(); if let TokenTree::MetaVarDecl(span, _, kind) = item.top_elts.get_tt(item.idx) { let match_cur = item.match_cur; - let nt = match parser.to_mut().parse_nonterminal(kind) { + // We use the span of the metavariable declaration to determine any + // edition-specific matching behavior for non-terminals. + let nt = match parser.to_mut().parse_nonterminal(kind, or_pat_mode(span.edition())) + { Err(mut err) => { err.span_label( span, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4d2167442be..eed3e9947b2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,4 +1,4 @@ -use super::pat::{GateOr, PARAM_EXPECTED}; +use super::pat::{GateOr, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; @@ -1729,7 +1729,7 @@ impl<'a> Parser<'a> { /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::No)?; + let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?; self.expect(&token::Eq)?; let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) @@ -1792,7 +1792,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_pat(GateOr::Yes)?; + let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; if !self.eat_keyword(kw::In) { self.error_missing_in_for_loop(); } @@ -1902,7 +1902,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - let pat = self.parse_top_pat(GateOr::No)?; + let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?; let guard = if self.eat_keyword(kw::If) { let if_span = self.prev_token.span; let cond = self.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d51a0fcbf09..e19ebb8fd2f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -12,6 +12,7 @@ mod ty; use crate::lexer::UnmatchedBrace; pub use diagnostics::AttemptLocalParseRecovery; use diagnostics::Error; +pub use pat::OrPatNonterminalMode; pub use path::PathStyle; use rustc_ast::ptr::P; diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 76ad5acd530..a6b9ac1014e 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -4,6 +4,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; +use crate::parser::pat::{GateOr, OrPatNonterminalMode, RecoverComma}; use crate::parser::{FollowedByType, Parser, PathStyle}; impl<'a> Parser<'a> { @@ -11,7 +12,11 @@ impl<'a> Parser<'a> { /// /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that /// token. Be conservative (return true) if not sure. - pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { + pub fn nonterminal_may_begin_with( + kind: NonterminalKind, + token: &Token, + or_pat_mode: OrPatNonterminalMode, + ) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { match *nt { @@ -70,6 +75,8 @@ impl<'a> Parser<'a> { token::ModSep | // path token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) + // leading vert `|` or-pattern + token::BinOp(token::Or) => matches!(or_pat_mode, OrPatNonterminalMode::TopPat), token::Interpolated(ref nt) => may_be_ident(nt), _ => false, }, @@ -86,7 +93,12 @@ impl<'a> Parser<'a> { } } - pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonterminal> { + /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). + pub fn parse_nonterminal( + &mut self, + kind: NonterminalKind, + or_pat_mode: OrPatNonterminalMode, + ) -> PResult<'a, Nonterminal> { // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`) // needs to have them force-captured here. // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, @@ -130,7 +142,12 @@ impl<'a> Parser<'a> { } } NonterminalKind::Pat => { - let (mut pat, tokens) = self.collect_tokens(|this| this.parse_pat(None))?; + let (mut pat, tokens) = self.collect_tokens(|this| match or_pat_mode { + OrPatNonterminalMode::TopPat => { + this.parse_top_pat(GateOr::Yes, RecoverComma::No) + } + OrPatNonterminalMode::NoTopAlt => this.parse_pat(None), + })?; // We have have eaten an NtPat, which could already have tokens if pat.tokens.is_none() { pat.tokens = tokens; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index b62c7373800..1da371e0b72 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -26,11 +26,18 @@ pub(super) enum GateOr { /// Whether or not to recover a `,` when parsing or-patterns. #[derive(PartialEq, Copy, Clone)] -enum RecoverComma { +pub(super) enum RecoverComma { Yes, No, } +/// Used when parsing a non-terminal (see `parse_nonterminal`) to determine if `:pat` should match +/// `top_pat` or `pat`. See issue . +pub enum OrPatNonterminalMode { + TopPat, + NoTopAlt, +} + impl<'a> Parser<'a> { /// Parses a pattern. /// @@ -43,13 +50,17 @@ impl<'a> Parser<'a> { /// Entry point to the main pattern parser. /// 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> { + pub(super) fn parse_top_pat( + &mut self, + gate_or: GateOr, + rc: RecoverComma, + ) -> 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_span = self.prev_token.span; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; + let pat = self.parse_pat_with_or(None, gate_or, rc)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index e974556f43a..2942747991a 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -1,7 +1,7 @@ use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN; use super::diagnostics::{AttemptLocalParseRecovery, Error}; use super::expr::LhsExpr; -use super::pat::GateOr; +use super::pat::{GateOr, RecoverComma}; use super::path::PathStyle; use super::{BlockMode, Parser, Restrictions, SemiColonMode}; use crate::maybe_whole; @@ -185,7 +185,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::Yes)?; + let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` diff --git a/src/test/ui/macros/macro-pat-follow-2018.rs b/src/test/ui/macros/macro-pat-follow-2018.rs new file mode 100644 index 00000000000..ce2911de986 --- /dev/null +++ b/src/test/ui/macros/macro-pat-follow-2018.rs @@ -0,0 +1,15 @@ +// run-pass +// edition:2018 + +macro_rules! pat_bar { + ($p:pat | $p2:pat) => {{ + match Some(1u8) { + $p | $p2 => {} + _ => {} + } + }}; +} + +fn main() { + pat_bar!(Some(1u8) | None); +} diff --git a/src/test/ui/macros/macro-pat-follow.rs b/src/test/ui/macros/macro-pat-follow.rs index 8673cf79467..8e02789fdd8 100644 --- a/src/test/ui/macros/macro-pat-follow.rs +++ b/src/test/ui/macros/macro-pat-follow.rs @@ -3,29 +3,19 @@ macro_rules! pat_in { ($p:pat in $e:expr) => {{ let mut iter = $e.into_iter(); while let $p = iter.next() {} - }} + }}; } macro_rules! pat_if { ($p:pat if $e:expr) => {{ match Some(1u8) { - $p if $e => {}, + $p if $e => {} _ => {} } - }} -} - -macro_rules! pat_bar { - ($p:pat | $p2:pat) => {{ - match Some(1u8) { - $p | $p2 => {}, - _ => {} - } - }} + }}; } fn main() { pat_in!(Some(_) in 0..10); pat_if!(Some(x) if x > 0); - pat_bar!(Some(1u8) | None); } diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs new file mode 100644 index 00000000000..9c3c5dd360e --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs @@ -0,0 +1,15 @@ +// Test that :pat doesn't accept top-level or-patterns in edition 2018. + +// edition:2018 + +#![feature(or_patterns)] + +fn main() {} + +// Test the `pat` macro fragment parser: +macro_rules! accept_pat { + ($p:pat) => {}; +} + +accept_pat!(p | q); //~ ERROR no rules expected the token `|` +accept_pat!(|p| q); //~ ERROR no rules expected the token `|` diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr new file mode 100644 index 00000000000..7dbc3087663 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr @@ -0,0 +1,20 @@ +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail-2018.rs:14:15 + | +LL | macro_rules! accept_pat { + | ----------------------- when calling this macro +... +LL | accept_pat!(p | q); + | ^ no rules expected this token in macro call + +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail-2018.rs:15:13 + | +LL | macro_rules! accept_pat { + | ----------------------- when calling this macro +... +LL | accept_pat!(|p| q); + | ^ no rules expected this token in macro call + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs index d2322005652..efe90b3e3c6 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -5,16 +5,6 @@ fn main() {} -// Test the `pat` macro fragment parser: -macro_rules! accept_pat { - ($p:pat) => {} -} - -accept_pat!(p | q); //~ ERROR no rules expected the token `|` -accept_pat!(| p | q); //~ ERROR no rules expected the token `|` - -// Non-macro tests: - enum E { A, B } use E::*; diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 861d274ab5c..989aeb52006 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -1,53 +1,53 @@ error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:27:13 + --> $DIR/or-patterns-syntactic-fail.rs:17:13 | LL | fn fun1(A | B: E) {} | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is not allowed in a parameter pattern - --> $DIR/or-patterns-syntactic-fail.rs:29:13 + --> $DIR/or-patterns-syntactic-fail.rs:19:13 | LL | fn fun2(| A | B: E) {} | ^ help: remove the `|` error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:29:15 + --> $DIR/or-patterns-syntactic-fail.rs:19:15 | LL | fn fun2(| A | B: E) {} | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:40:11 + --> $DIR/or-patterns-syntactic-fail.rs:30:11 | LL | let ( | A | B) = E::A; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:41:11 + --> $DIR/or-patterns-syntactic-fail.rs:31:11 | LL | let ( | A | B,) = (E::B,); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:42:11 + --> $DIR/or-patterns-syntactic-fail.rs:32:11 | LL | let [ | A | B ] = [E::A]; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:43:13 + --> $DIR/or-patterns-syntactic-fail.rs:33:13 | LL | let TS( | A | B ); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:44:17 + --> $DIR/or-patterns-syntactic-fail.rs:34:17 | LL | let NS { f: | A | B }; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:46:11 + --> $DIR/or-patterns-syntactic-fail.rs:36:11 | LL | let ( || A | B) = E::A; | ^^ help: remove the `||` @@ -55,7 +55,7 @@ LL | let ( || A | B) = E::A; = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:47:11 + --> $DIR/or-patterns-syntactic-fail.rs:37:11 | LL | let [ || A | B ] = [E::A]; | ^^ help: remove the `||` @@ -63,7 +63,7 @@ LL | let [ || A | B ] = [E::A]; = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:48:13 + --> $DIR/or-patterns-syntactic-fail.rs:38:13 | LL | let TS( || A | B ); | ^^ help: remove the `||` @@ -71,33 +71,15 @@ LL | let TS( || A | B ); = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:49:17 + --> $DIR/or-patterns-syntactic-fail.rs:39:17 | LL | let NS { f: || A | B }; | ^^ help: remove the `||` | = note: alternatives in or-patterns are separated with `|`, not `||` -error: no rules expected the token `|` - --> $DIR/or-patterns-syntactic-fail.rs:13:15 - | -LL | macro_rules! accept_pat { - | ----------------------- when calling this macro -... -LL | accept_pat!(p | q); - | ^ no rules expected this token in macro call - -error: no rules expected the token `|` - --> $DIR/or-patterns-syntactic-fail.rs:14:13 - | -LL | macro_rules! accept_pat { - | ----------------------- when calling this macro -... -LL | accept_pat!(| p | q); - | ^ no rules expected this token in macro call - error[E0369]: no implementation for `E | ()` - --> $DIR/or-patterns-syntactic-fail.rs:23:22 + --> $DIR/or-patterns-syntactic-fail.rs:13:22 | LL | let _ = |A | B: E| (); | ----^ -- () @@ -107,7 +89,7 @@ LL | let _ = |A | B: E| (); = note: an implementation of `std::ops::BitOr` might be missing for `E` error[E0308]: mismatched types - --> $DIR/or-patterns-syntactic-fail.rs:51:36 + --> $DIR/or-patterns-syntactic-fail.rs:41:36 | LL | let recovery_witness: String = 0; | ------ ^ @@ -116,7 +98,7 @@ LL | let recovery_witness: String = 0; | | help: try using a conversion method: `0.to_string()` | expected due to this -error: aborting due to 16 previous errors +error: aborting due to 14 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs new file mode 100644 index 00000000000..f0ce7597aee --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs @@ -0,0 +1,14 @@ +// Tests that :pat in macros in edition 2021 allows top-level or-patterns. + +// run-pass +// ignore-test +// edition:2021 +// FIXME(mark-i-m): unignore when 2021 machinery is in place. + +macro_rules! accept_pat { + ($p:pat) => {}; +} + +accept_pat!(p | q); + +fn main() {} diff --git a/src/test/ui/pattern/or-pattern-macro-pat.rs b/src/test/ui/pattern/or-pattern-macro-pat.rs new file mode 100644 index 00000000000..8749407675b --- /dev/null +++ b/src/test/ui/pattern/or-pattern-macro-pat.rs @@ -0,0 +1,44 @@ +// run-pass +// edition:2021 +// ignore-test +// FIXME(mark-i-m): enable this test again when 2021 machinery is available + +#![feature(or_patterns)] + +use Foo::*; + +#[derive(Eq, PartialEq, Debug)] +enum Foo { + A(u64), + B(u64), + C, + D, +} + +macro_rules! foo { + ($orpat:pat, $val:expr) => { + match $val { + x @ ($orpat) => x, // leading vert would not be allowed in $orpat + _ => B(0xDEADBEEFu64), + } + }; +} + +macro_rules! bar { + ($orpat:pat, $val:expr) => { + match $val { + $orpat => 42, // leading vert allowed here + _ => 0xDEADBEEFu64, + } + }; +} + +fn main() { + // Test or-pattern. + let y = foo!(A(_)|B(_), A(32)); + assert_eq!(y, A(32)); + + // Leading vert in or-pattern. + let y = bar!(|C| D, C); + assert_eq!(y, 42u64); +} -- cgit 1.4.1-3-g733a5 From a272d621bc7a2ca61d704fbe531dc532d49ab402 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Fri, 18 Dec 2020 17:32:26 +0100 Subject: Implemented a compiler diagnostic for move async mistake Ran the tidy check Following the diagnostic guide better Diagnostic generation is now relegated to its own function in the diagnostics module. Added tests Fixed the ui test --- compiler/rustc_parse/src/parser/diagnostics.rs | 18 ++++++++++++++++++ compiler/rustc_parse/src/parser/expr.rs | 18 ++++++++++++++---- .../incorrect-move-async-order-issue-79694.fixed | 8 ++++++++ .../parser/incorrect-move-async-order-issue-79694.rs | 8 ++++++++ .../incorrect-move-async-order-issue-79694.stderr | 13 +++++++++++++ 5 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.rs create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 350a372a684..98c7b9a63a5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1912,4 +1912,22 @@ impl<'a> Parser<'a> { *self = snapshot; Err(err) } + + /// Get the diagnostics for the cases where `move async` is found. + /// + /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword + pub(super) fn incorrect_move_async_order_found( + &self, + move_async_span: Span, + ) -> DiagnosticBuilder<'a> { + let mut err = + self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect"); + err.span_suggestion_verbose( + move_async_span, + "try switching the order", + "async move".to_owned(), + Applicability::MaybeIncorrect, + ); + err + } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93be478fc8c..7d0d4f30137 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1603,7 +1603,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::async_closure, span); } - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; let body = match decl.output { @@ -1626,8 +1626,18 @@ impl<'a> Parser<'a> { } /// Parses an optional `move` prefix to a closure-like construct. - fn parse_capture_clause(&mut self) -> CaptureBy { - if self.eat_keyword(kw::Move) { CaptureBy::Value } else { CaptureBy::Ref } + fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { + if self.eat_keyword(kw::Move) { + // Check for `move async` and recover + if self.check_keyword(kw::Async) { + let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.incorrect_move_async_order_found(move_async_span)) + } else { + Ok(CaptureBy::Value) + } + } else { + Ok(CaptureBy::Ref) + } } /// Parses the `|arg, arg|` header of a closure. @@ -2018,7 +2028,7 @@ impl<'a> Parser<'a> { fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.expect_keyword(kw::Async)?; - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body); diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed new file mode 100644 index 00000000000..055800d23b6 --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs new file mode 100644 index 00000000000..e8be16516d6 --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr new file mode 100644 index 00000000000..2add9fb33c7 --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr @@ -0,0 +1,13 @@ +error: the order of `move` and `async` is incorrect + --> $DIR/incorrect-move-async-order-issue-79694.rs:7:13 + | +LL | let _ = move async { }; + | ^^^^^^^^^^ + | +help: try switching the order + | +LL | let _ = async move { }; + | ^^^^^^^^^^ + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From d12a358673b17ed74fe1a584b4cab66fe62e18d0 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Thu, 24 Dec 2020 02:55:21 +0100 Subject: use matches!() macro in more places --- compiler/rustc_ast/src/ast.rs | 45 ++++-------------- compiler/rustc_ast/src/attr/mod.rs | 5 +- compiler/rustc_ast/src/token.rs | 53 ++++++++-------------- compiler/rustc_ast/src/util/classify.rs | 18 ++++---- compiler/rustc_ast/src/util/comments.rs | 6 +-- .../rustc_builtin_macros/src/deriving/clone.rs | 7 ++- .../src/deriving/generic/mod.rs | 12 ++--- compiler/rustc_builtin_macros/src/format.rs | 5 +- .../rustc_builtin_macros/src/format_foreign.rs | 5 +- compiler/rustc_builtin_macros/src/llvm_asm.rs | 8 ++-- .../rustc_builtin_macros/src/proc_macro_harness.rs | 5 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 8 ++-- .../nice_region_error/trait_impl_difference.rs | 5 +- compiler/rustc_infer/src/infer/free_regions.rs | 5 +- .../src/infer/lexical_region_resolve/mod.rs | 11 +---- compiler/rustc_middle/src/hir/map/blocks.rs | 20 ++------ compiler/rustc_middle/src/mir/coverage.rs | 10 +--- compiler/rustc_middle/src/ty/error.rs | 7 +-- compiler/rustc_middle/src/ty/sty.rs | 5 +- compiler/rustc_mir_build/src/build/expr/into.rs | 6 +-- compiler/rustc_parse/src/parser/path.rs | 7 ++- compiler/rustc_passes/src/dead.rs | 38 ++++++++-------- compiler/rustc_passes/src/liveness.rs | 5 +- compiler/rustc_resolve/src/late/diagnostics.rs | 19 ++++---- .../rustc_trait_selection/src/traits/auto_trait.rs | 10 +--- .../rustc_trait_selection/src/traits/coherence.rs | 6 +-- .../src/traits/error_reporting/mod.rs | 12 ++--- compiler/rustc_trait_selection/src/traits/mod.rs | 5 +- compiler/rustc_typeck/src/astconv/generics.rs | 22 ++++----- compiler/rustc_typeck/src/check/check.rs | 12 ++--- compiler/rustc_typeck/src/check/fn_ctxt/checks.rs | 5 +- compiler/rustc_typeck/src/check/regionck.rs | 5 +- compiler/rustc_typeck/src/collect.rs | 8 ++-- compiler/rustc_typeck/src/expr_use_visitor.rs | 8 ++-- 34 files changed, 138 insertions(+), 270 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 220bbed7e78..478e61dd121 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -167,10 +167,7 @@ pub enum GenericArgs { impl GenericArgs { pub fn is_angle_bracketed(&self) -> bool { - match *self { - AngleBracketed(..) => true, - _ => false, - } + matches!(self, AngleBracketed(..)) } pub fn span(&self) -> Span { @@ -629,10 +626,7 @@ impl Pat { /// Is this a `..` pattern? pub fn is_rest(&self) -> bool { - match self.kind { - PatKind::Rest => true, - _ => false, - } + matches!(self.kind, PatKind::Rest) } } @@ -852,10 +846,7 @@ impl BinOpKind { } } pub fn lazy(&self) -> bool { - match *self { - BinOpKind::And | BinOpKind::Or => true, - _ => false, - } + matches!(self, BinOpKind::And | BinOpKind::Or) } pub fn is_comparison(&self) -> bool { @@ -963,17 +954,11 @@ impl Stmt { } pub fn is_item(&self) -> bool { - match self.kind { - StmtKind::Item(_) => true, - _ => false, - } + matches!(self.kind, StmtKind::Item(_)) } pub fn is_expr(&self) -> bool { - match self.kind { - StmtKind::Expr(_) => true, - _ => false, - } + matches!(self.kind, StmtKind::Expr(_)) } } @@ -1652,26 +1637,17 @@ pub enum LitKind { impl LitKind { /// Returns `true` if this literal is a string. pub fn is_str(&self) -> bool { - match *self { - LitKind::Str(..) => true, - _ => false, - } + matches!(self, LitKind::Str(..)) } /// Returns `true` if this literal is byte literal string. pub fn is_bytestr(&self) -> bool { - match self { - LitKind::ByteStr(_) => true, - _ => false, - } + matches!(self, LitKind::ByteStr(_)) } /// Returns `true` if this is a numeric literal. pub fn is_numeric(&self) -> bool { - match *self { - LitKind::Int(..) | LitKind::Float(..) => true, - _ => false, - } + matches!(self, LitKind::Int(..) | LitKind::Float(..)) } /// Returns `true` if this literal has no suffix. @@ -2237,10 +2213,7 @@ impl FnDecl { self.inputs.get(0).map_or(false, Param::is_self) } pub fn c_variadic(&self) -> bool { - self.inputs.last().map_or(false, |arg| match arg.ty.kind { - TyKind::CVarArgs => true, - _ => false, - }) + self.inputs.last().map_or(false, |arg| matches!(arg.ty.kind, TyKind::CVarArgs)) } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 19c7c479f04..726ae5e51f7 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -234,10 +234,7 @@ impl MetaItem { } pub fn is_word(&self) -> bool { - match self.kind { - MetaItemKind::Word => true, - _ => false, - } + matches!(self.kind, MetaItemKind::Word) } pub fn has_name(&self, name: Symbol) -> bool { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index a74464937c8..cd1e444bcf7 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -130,10 +130,7 @@ impl LitKind { } crate fn may_have_suffix(self) -> bool { - match self { - Integer | Float | Err => true, - _ => false, - } + matches!(self, Integer | Float | Err) } } @@ -305,10 +302,7 @@ impl TokenKind { } pub fn should_end_const_arg(&self) -> bool { - match self { - Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true, - _ => false, - } + matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr)) } } @@ -346,18 +340,21 @@ impl Token { } pub fn is_op(&self) -> bool { - match self.kind { - OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | Eof => false, - _ => true, - } + !matches!( + self.kind, + OpenDelim(..) + | CloseDelim(..) + | Literal(..) + | DocComment(..) + | Ident(..) + | Lifetime(..) + | Interpolated(..) + | Eof + ) } pub fn is_like_plus(&self) -> bool { - match self.kind { - BinOp(Plus) | BinOpEq(Plus) => true, - _ => false, - } + matches!(self.kind, BinOp(Plus) | BinOpEq(Plus)) } /// Returns `true` if the token can appear at the start of an expression. @@ -379,13 +376,10 @@ impl Token { ModSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => match **nt { - NtLiteral(..) | + Interpolated(ref nt) => matches!(**nt, NtLiteral(..) | NtExpr(..) | NtBlock(..) | - NtPath(..) => true, - _ => false, - }, + NtPath(..)), _ => false, } } @@ -405,10 +399,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path ModSep => true, // global path - Interpolated(ref nt) => match **nt { - NtTy(..) | NtPath(..) => true, - _ => false, - }, + Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)), _ => false, } } @@ -417,10 +408,7 @@ impl Token { pub fn can_begin_const_arg(&self) -> bool { match self.kind { OpenDelim(Brace) => true, - Interpolated(ref nt) => match **nt { - NtExpr(..) | NtBlock(..) | NtLiteral(..) => true, - _ => false, - }, + Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), _ => self.can_begin_literal_maybe_minus(), } } @@ -436,10 +424,7 @@ impl Token { /// Returns `true` if the token is any literal. pub fn is_lit(&self) -> bool { - match self.kind { - Literal(..) => true, - _ => false, - } + matches!(self.kind, Literal(..)) } /// Returns `true` if the token is any literal, a minus (which can prefix a literal, diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 60422a2e573..90786520fe8 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -12,14 +12,14 @@ use crate::ast; /// |x| 5 /// isn't parsed as (if true {...} else {...} | x) | 5 pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { - match e.kind { + !matches!( + e.kind, ast::ExprKind::If(..) - | ast::ExprKind::Match(..) - | ast::ExprKind::Block(..) - | ast::ExprKind::While(..) - | ast::ExprKind::Loop(..) - | ast::ExprKind::ForLoop(..) - | ast::ExprKind::TryBlock(..) => false, - _ => true, - } + | ast::ExprKind::Match(..) + | ast::ExprKind::Block(..) + | ast::ExprKind::While(..) + | ast::ExprKind::Loop(..) + | ast::ExprKind::ForLoop(..) + | ast::ExprKind::TryBlock(..) + ) } diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index e97c8cc4562..e0052b76040 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -178,10 +178,8 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec { if doc_style.is_none() { - let code_to_the_right = match text[pos + token.len..].chars().next() { - Some('\r' | '\n') => false, - _ => true, - }; + let code_to_the_right = + !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n')); let style = match (code_to_the_left, code_to_the_right) { (_, true) => CommentStyle::Mixed, (false, false) => CommentStyle::Isolated, diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 957c8035399..ca1226b445d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -38,10 +38,9 @@ pub fn expand_deriving_clone( | ItemKind::Enum(_, Generics { ref params, .. }) => { let container_id = cx.current_expansion.id.expn_data().parent; if cx.resolver.has_derive_copy(container_id) - && !params.iter().any(|param| match param.kind { - ast::GenericParamKind::Type { .. } => true, - _ => false, - }) + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) { bounds = vec![]; is_shallow = true; diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6531e68be9c..e78d1368b35 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -404,12 +404,10 @@ impl<'a> TraitDef<'a> { let has_no_type_params = match item.kind { ast::ItemKind::Struct(_, ref generics) | ast::ItemKind::Enum(_, ref generics) - | ast::ItemKind::Union(_, ref generics) => { - !generics.params.iter().any(|param| match param.kind { - ast::GenericParamKind::Type { .. } => true, - _ => false, - }) - } + | ast::ItemKind::Union(_, ref generics) => !generics + .params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), _ => unreachable!(), }; let container_id = cx.current_expansion.id.expn_data().parent; @@ -868,7 +866,7 @@ impl<'a> MethodDef<'a> { Self_ if nonstatic => { self_args.push(arg_expr); } - Ptr(ref ty, _) if (if let Self_ = **ty { true } else { false }) && nonstatic => { + Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => { self_args.push(cx.expr_deref(trait_.span, arg_expr)) } _ => { diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 550524e652a..85ca1da6f1d 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1044,10 +1044,7 @@ pub fn expand_preparsed_format_args( let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg { parse::String(_) => false, - parse::NextArgument(arg) => match arg.position { - parse::Position::ArgumentIs(_) => true, - _ => false, - }, + parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)), }); cx.build_index_map(); diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index f00dfd1241f..0496c72cb00 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -580,10 +580,7 @@ pub mod printf { } fn is_flag(c: &char) -> bool { - match c { - '0' | '-' | '+' | ' ' | '#' | '\'' => true, - _ => false, - } + matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'') } #[cfg(test)] diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs index db73fdbe24f..d203b5bc542 100644 --- a/compiler/rustc_builtin_macros/src/llvm_asm.rs +++ b/compiler/rustc_builtin_macros/src/llvm_asm.rs @@ -87,9 +87,11 @@ fn parse_inline_asm<'a>( // parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription. let first_colon = tts .trees() - .position(|tt| match tt { - tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) => true, - _ => false, + .position(|tt| { + matches!( + tt, + tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) + ) }) .unwrap_or(tts.len()); let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect()); diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 4e91436199a..7582d980539 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -256,10 +256,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // we're just not interested in this item. // // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. - let is_fn = match item.kind { - ast::ItemKind::Fn(..) => true, - _ => false, - }; + let is_fn = matches!(item.kind, ast::ItemKind::Fn(..)); let mut found_attr: Option<&'a ast::Attribute> = None; diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 44bb0deeae9..57e49ba8d1a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -112,12 +112,12 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { }; // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = match context { + let is_consume = matches!( + context, PlaceContext::NonMutatingUse( NonMutatingUseContext::Copy | NonMutatingUseContext::Move, - ) => true, - _ => false, - }; + ) + ); if is_consume { let base_ty = mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx()); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 4d3217a9c0b..0958afa0308 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -132,10 +132,7 @@ impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { [segment] if segment .res - .map(|res| match res { - Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true, - _ => false, - }) + .map(|res| matches!(res, Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _))) .unwrap_or(false) => { self.types.push(path.span); diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 32f73237dd4..728dc2de370 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -93,10 +93,7 @@ impl<'tcx> FreeRegionMap<'tcx> { /// True for free regions other than `'static`. pub fn is_free(&self, r: Region<'_>) -> bool { - match *r { - ty::ReEarlyBound(_) | ty::ReFree(_) => true, - _ => false, - } + matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_)) } /// True if `r` is a free region or static of the sort that this diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index d7b2ce7ee20..ab34cda8cc1 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -393,10 +393,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { if self.expand_node(a_region, b_vid, b_data) { changes.push(b_vid); } - match *b_data { - VarValue::Value(ReStatic) | VarValue::ErrorValue => false, - _ => true, - } + !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue) }); } } @@ -972,11 +969,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } VerifyBound::IsEmpty => { - if let ty::ReEmpty(_) = min { - true - } else { - false - } + matches!(min, ty::ReEmpty(_)) } VerifyBound::AnyBound(bs) => { diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs index 6f572a4875f..9d392c7b26b 100644 --- a/compiler/rustc_middle/src/hir/map/blocks.rs +++ b/compiler/rustc_middle/src/hir/map/blocks.rs @@ -42,37 +42,25 @@ trait MaybeFnLike { impl MaybeFnLike for hir::Item<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ItemKind::Fn(..) => true, - _ => false, - } + matches!(self.kind, hir::ItemKind::Fn(..)) } } impl MaybeFnLike for hir::ImplItem<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ImplItemKind::Fn(..) => true, - _ => false, - } + matches!(self.kind, hir::ImplItemKind::Fn(..)) } } impl MaybeFnLike for hir::TraitItem<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true, - _ => false, - } + matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) } } impl MaybeFnLike for hir::Expr<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ExprKind::Closure(..) => true, - _ => false, - } + matches!(self.kind, hir::ExprKind::Closure(..)) } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 8a6bf9dff7b..95096d0fb71 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -118,17 +118,11 @@ impl CoverageKind { } pub fn is_counter(&self) -> bool { - match self { - Self::Counter { .. } => true, - _ => false, - } + matches!(self, Self::Counter { .. }) } pub fn is_expression(&self) -> bool { - match self { - Self::Expression { .. } => true, - _ => false, - } + matches!(self, Self::Expression { .. }) } pub fn is_unreachable(&self) -> bool { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index fc02e78b2fa..fe20925b387 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -647,14 +647,11 @@ impl Trait for X { let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. - let callable_scope = match body_owner { - Some( + let callable_scope = matches!(body_owner, Some( hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), - ) => true, - _ => false, - }; + )); let impl_comparison = matches!( cause_code, ObligationCauseCode::CompareImplMethodObligation { .. } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9fa399a0169..4ce76409c6f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -215,10 +215,7 @@ pub enum TyKind<'tcx> { impl TyKind<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - match self { - Bool | Char | Int(_) | Uint(_) | Float(_) => true, - _ => false, - } + matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_)) } /// Get the article ("a" or "an") to use with this type. diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1f70fdb5ae3..09281799041 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -40,11 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr_span = expr.span; let source_info = this.source_info(expr_span); - let expr_is_block_or_scope = match expr.kind { - ExprKind::Block { .. } => true, - ExprKind::Scope { .. } => true, - _ => false, - }; + let expr_is_block_or_scope = matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. }); let schedule_drop = move |this: &mut Self| { if let Some(drop_scope) = scope { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4510e86e034..60a47ca12b8 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -501,10 +501,9 @@ impl<'a> Parser<'a> { pub(super) fn expr_is_valid_const_arg(&self, expr: &P) -> bool { match &expr.kind { ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true, - ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind { - ast::ExprKind::Lit(_) => true, - _ => false, - }, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) => { + matches!(expr.kind, ast::ExprKind::Lit(_)) + } // We can only resolve single-segment paths at the moment, because multi-segment paths // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`. ast::ExprKind::Path(None, path) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 00152878d6d..c4fb0cf5b28 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -23,18 +23,18 @@ use rustc_span::symbol::{sym, Symbol}; // function, then we should explore its block to check for codes that // may need to be marked as live. fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { - match tcx.hir().find(hir_id) { + matches!( + tcx.hir().find(hir_id), Some( Node::Item(..) - | Node::ImplItem(..) - | Node::ForeignItem(..) - | Node::TraitItem(..) - | Node::Variant(..) - | Node::AnonConst(..) - | Node::Pat(..), - ) => true, - _ => false, - } + | Node::ImplItem(..) + | Node::ForeignItem(..) + | Node::TraitItem(..) + | Node::Variant(..) + | Node::AnonConst(..) + | Node::Pat(..), + ) + ) } struct MarkSymbolVisitor<'tcx> { @@ -500,16 +500,16 @@ struct DeadVisitor<'tcx> { impl DeadVisitor<'tcx> { fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool { - let should_warn = match item.kind { + let should_warn = matches!( + item.kind, hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) => true, - _ => false, - }; + | hir::ItemKind::Const(..) + | hir::ItemKind::Fn(..) + | hir::ItemKind::TyAlias(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..) + ); should_warn && !self.symbol_is_live(item.hir_id) } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 86ce35c6d99..54e3cc69aea 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -367,10 +367,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - let is_shorthand = match param.pat.kind { - rustc_hir::PatKind::Struct(..) => true, - _ => false, - }; + let is_shorthand = matches!(param.pat.kind, rustc_hir::PatKind::Struct(..)); param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = if is_shorthand { Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true }) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 68f59baffce..b7c703f0e8f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1653,17 +1653,14 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { for missing in &self.missing_named_lifetime_spots { match missing { MissingLifetimeSpot::Generics(generics) => { - let (span, sugg) = if let Some(param) = - generics.params.iter().find(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Elided, - } => false, - _ => true, - }) { + let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| { + !matches!(p.kind, hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } | hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Elided, + }) + }) { (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) } else { suggests_in_band = true; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6ab16886ed2..fc6a9a7f209 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -35,10 +35,7 @@ pub enum AutoTraitResult { #[allow(dead_code)] impl AutoTraitResult { fn is_auto(&self) -> bool { - match *self { - AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, - _ => false, - } + matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl) } } @@ -601,10 +598,7 @@ impl AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - match *p.ty().skip_binder().kind() { - ty::Projection(proj) if proj == p.skip_binder().projection_ty => true, - _ => false, - } + matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty) } fn evaluate_nested_obligations( diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9324d55ac1b..99b96f60964 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -193,10 +193,8 @@ fn overlap_within_probe( let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); - let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) { - Some(true) => true, - _ => false, - }; + let involves_placeholder = + matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true)); Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9feba7bfc49..1d82e732907 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -861,10 +861,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { let arg_length = arguments.len(); - let distinct = match &other[..] { - &[ArgKind::Tuple(..)] => true, - _ => false, - }; + let distinct = matches!(other, &[ArgKind::Tuple(..)]); match (arg_length, arguments.get(0)) { (1, Some(&ArgKind::Tuple(_, ref fields))) => { format!("a single {}-tuple as argument", fields.len()) @@ -1201,12 +1198,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { normalized_ty, data.ty ); - let is_normalized_ty_expected = match &obligation.cause.code { - ObligationCauseCode::ItemObligation(_) + let is_normalized_ty_expected = !matches!(obligation.cause.code, ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ObjectCastObligation(_) => false, - _ => true, - }; + | ObligationCauseCode::ObjectCastObligation(_)); if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( is_normalized_ty_expected, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2fb9b3cd5d3..9c894e99a38 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -323,9 +323,8 @@ pub fn normalize_param_env_or_error<'tcx>( // This works fairly well because trait matching does not actually care about param-env // TypeOutlives predicates - these are normally used by regionck. let outlives_predicates: Vec<_> = predicates - .drain_filter(|predicate| match predicate.skip_binders() { - ty::PredicateAtom::TypeOutlives(..) => true, - _ => false, + .drain_filter(|predicate| { + matches!(predicate.skip_binders(), ty::PredicateAtom::TypeOutlives(..)) }) .collect(); diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index b7e77f389f8..0feac036f00 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -526,18 +526,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generics: &ty::Generics, ) -> bool { let explicit = !seg.infer_args; - let impl_trait = - generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { - synthetic: - Some( - hir::SyntheticTyParamKind::ImplTrait - | hir::SyntheticTyParamKind::FromAttr, - ), - .. - } => true, - _ => false, - }); + let impl_trait = generics.params.iter().any(|param| { + matches!(param.kind, ty::GenericParamDefKind::Type { + synthetic: + Some( + hir::SyntheticTyParamKind::ImplTrait + | hir::SyntheticTyParamKind::FromAttr, + ), + .. + }) + }); if explicit && impl_trait { let spans = seg diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index ec7369fd3e8..9c60e8933d4 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -543,10 +543,9 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if let Some(ty) = prohibit_opaque.break_value() { let is_async = match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { - hir::OpaqueTyOrigin::AsyncFn => true, - _ => false, - }, + ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + matches!(origin, hir::OpaqueTyOrigin::AsyncFn) + } _ => unreachable!(), }; @@ -1321,10 +1320,7 @@ pub fn check_enum<'tcx>( } if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { - let is_unit = |var: &hir::Variant<'_>| match var.data { - hir::VariantData::Unit(..) => true, - _ => false, - }; + let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..)); let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); let has_non_units = vs.iter().any(|var| !is_unit(var)); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 333bda00dbe..3e60924d6fc 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -325,10 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); } - let is_closure = match arg.kind { - ExprKind::Closure(..) => true, - _ => false, - }; + let is_closure = matches!(arg.kind, ExprKind::Closure(..)); if is_closure != check_closures { continue; diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index b8b98cef763..eca6ce1ecdb 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -354,10 +354,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { hir_id: hir::HirId, ) { assert!( - match fk { - intravisit::FnKind::Closure(..) => true, - _ => false, - }, + matches!(fk, intravisit::FnKind::Closure(..)), "visit_fn invoked for something other than a closure" ); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index bc6b2037c18..603643d094d 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -156,10 +156,10 @@ crate fn placeholder_type_error( if let Some(span) = span { sugg.push((span, format!("<{}>", type_name))); } - } else if let Some(arg) = generics.iter().find(|arg| match arg.name { - hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true, - _ => false, - }) { + } else if let Some(arg) = generics + .iter() + .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))) + { // Account for `_` already present in cases like `struct S<_>(_);` and suggest // `struct S(T);` instead of `struct S<_, T>(T);`. sugg.push((arg.span, (*type_name).to_string())); diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index ce9fd5575cf..3ce244e11bf 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -595,10 +595,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let upvars = self.tcx().upvars_mentioned(self.body_owner); // For purposes of this function, generator and closures are equivalent. - let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() { - ty::Closure(..) | ty::Generator(..) => true, - _ => false, - }; + let body_owner_is_closure = matches!( + self.tcx().type_of(self.body_owner.to_def_id()).kind(), + ty::Closure(..) | ty::Generator(..) + ); if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id) { -- cgit 1.4.1-3-g733a5 From 06cc9c26da18848fd97b6d0d6e4e1760497a3c0c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 17 Nov 2020 10:55:13 +0100 Subject: stabilize min_const_generics --- compiler/rustc_arena/src/lib.rs | 2 +- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast_passes/src/ast_validation.rs | 10 ++++------ compiler/rustc_ast_passes/src/feature_gate.rs | 15 +-------------- compiler/rustc_data_structures/src/lib.rs | 2 +- compiler/rustc_feature/src/accepted.rs | 2 ++ compiler/rustc_feature/src/active.rs | 9 ++++----- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 -- compiler/rustc_parse/src/parser/generics.rs | 4 +--- compiler/rustc_resolve/src/late/diagnostics.rs | 6 +++--- compiler/rustc_resolve/src/late/lifetimes.rs | 4 ++-- compiler/rustc_resolve/src/lib.rs | 12 ++++++++++-- compiler/rustc_serialize/src/lib.rs | 2 +- compiler/rustc_typeck/src/check/wfcheck.rs | 14 +++++++------- compiler/rustc_typeck/src/collect.rs | 2 +- 17 files changed, 41 insertions(+), 51 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index f468bad635a..a0493056b81 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -16,7 +16,7 @@ #![feature(new_uninit)] #![feature(maybe_uninit_slice)] #![feature(array_value_iter)] -#![feature(min_const_generics)] +#![cfg_attr(bootstrap, feature(min_const_generics))] #![feature(min_specialization)] #![cfg_attr(test, feature(test))] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 220bbed7e78..45cc6d894e9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1128,7 +1128,7 @@ impl Expr { /// Is this expr either `N`, or `{ N }`. /// /// If this is not the case, name resolution does not resolve `N` when using - /// `feature(min_const_generics)` as more complex expressions are not supported. + /// `min_const_generics` as more complex expressions are not supported. pub fn is_potential_trivial_const_param(&self) -> bool { let this = if let ExprKind::Block(ref block, None) = self.kind { if block.stmts.len() == 1 { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index bf6d3322176..686300c7c5f 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -773,14 +773,12 @@ fn validate_generic_param_order<'a>( err.span_suggestion( span, &format!( - "reorder the parameters: lifetimes{}", + "reorder the parameters: lifetimes, {}", if sess.features_untracked().const_generics { - ", then consts and types" - } else if sess.features_untracked().min_const_generics { - ", then types, then consts" + "then consts and types" } else { - ", then types" - }, + "then types, then consts" + } ), ordered_params.clone(), Applicability::MachineApplicable, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index bb222675239..56e1f9989b0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId}; -use rustc_ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; +use rustc_ast::{PatKind, RangeEnd, VariantData}; use rustc_errors::struct_span_err; use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; use rustc_feature::{Features, GateIssue}; @@ -529,19 +529,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_fn(self, fn_kind, span) } - fn visit_generic_param(&mut self, param: &'a GenericParam) { - if let GenericParamKind::Const { .. } = param.kind { - gate_feature_fn!( - &self, - |x: &Features| x.const_generics || x.min_const_generics, - param.ident.span, - sym::min_const_generics, - "const generics are unstable" - ); - } - visit::walk_generic_param(self, param) - } - fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { if let AssocTyConstraintKind::Bound { .. } = constraint.kind { gate_feature_post!( diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index d903a557c7f..01d3a759316 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -27,7 +27,7 @@ #![feature(thread_id_value)] #![feature(extend_one)] #![feature(const_panic)] -#![feature(min_const_generics)] +#![cfg_attr(bootstrap, feature(min_const_generics))] #![feature(new_uninit)] #![feature(once_cell)] #![feature(maybe_uninit_uninit_array)] diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 4401ec0a04e..aa54ffb132d 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -273,6 +273,8 @@ declare_features! ( /// Allows patterns with concurrent by-move and by-ref bindings. /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. (accepted, move_ref_pattern, "1.48.0", Some(68354), None), + /// The smallest useful subset of `const_generics`. + (accepted, min_const_generics, "1.51.0", Some(74878), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 845e03150d7..d60ae8ef75b 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -578,9 +578,6 @@ declare_features! ( /// Allows calling `transmute` in const fn (active, const_fn_transmute, "1.46.0", Some(53605), None), - /// The smallest useful subset of `const_generics`. - (active, min_const_generics, "1.47.0", Some(74878), None), - /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), @@ -651,5 +648,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ /// Some features are not allowed to be used together at the same time, if /// the two are present, produce an error. -pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = - &[(sym::const_generics, sym::min_const_generics)]; +/// +/// Currently empty, but we will probably need this again in the future, +/// so let's keep it in for now. +pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[]; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 676c85e4afd..fa943d0d748 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2299,7 +2299,7 @@ impl EarlyLintPass for IncompleteFeatures { } } -const HAS_MIN_FEATURES: &[Symbol] = &[sym::const_generics, sym::specialization]; +const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization]; declare_lint! { /// The `invalid_value` lint detects creating a value that is not valid, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9b944f202a9..b2db09cbc80 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1386,7 +1386,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn lazy_normalization(self) -> bool { let features = self.features(); - // Note: We do not enable lazy normalization for `features.min_const_generics`. + // Note: We do not enable lazy normalization for `min_const_generics`. features.const_generics || features.lazy_normalization_consts } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8395692446d..1fe1400fabe 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1638,8 +1638,6 @@ pub type PlaceholderConst<'tcx> = Placeholder>; /// which cause cycle errors. /// /// ```rust -/// #![feature(const_generics)] -/// /// struct A; /// impl A { /// fn foo(&self) -> [u8; N] { [0; N] } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index ed8d4f78426..860e63020bb 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -5,7 +5,7 @@ use rustc_ast::{ self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause, }; use rustc_errors::PResult; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::kw; impl<'a> Parser<'a> { /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. @@ -56,8 +56,6 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty()?; - self.sess.gated_spans.gate(sym::min_const_generics, const_span.to(self.prev_token.span)); - Ok(GenericParam { ident, id: ast::DUMMY_NODE_ID, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 68f59baffce..d253a9dda86 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1985,8 +1985,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } } - /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics` so - /// this function will emit an error if `min_const_generics` is enabled, the body identified by + /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`. + /// This function will emit an error if `const_generics` is not enabled, the body identified by /// `body_id` is an anonymous constant and `lifetime_ref` is non-static. crate fn maybe_emit_forbidden_non_static_lifetime_error( &self, @@ -2002,7 +2002,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore ); - if self.tcx.features().min_const_generics && is_anon_const && !is_allowed_lifetime { + if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime { feature_err( &self.tcx.sess.parse_sess, sym::const_generics, diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 69f28045bb5..d5ba6f3b53b 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1769,8 +1769,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let result = loop { match *scope { Scope::Body { id, s } => { - // Non-static lifetimes are prohibited in anonymous constants under - // `min_const_generics`. + // Non-static lifetimes are prohibited in anonymous constants without + // `const_generics`. self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref); outermost_body = Some(id); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f764fbc3f8d..5c79cfa9c1d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2624,8 +2624,12 @@ impl<'a> Resolver<'a> { continue; } ConstantItemRibKind(trivial) => { + let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !trivial && self.session.features_untracked().min_const_generics { + if !(trivial + || features.const_generics + || features.lazy_normalization_consts) + { // HACK(min_const_generics): If we encounter `Self` in an anonymous constant // we can't easily tell if it's generic at this stage, so we instead remember // this and then enforce the self type to be concrete later on. @@ -2713,8 +2717,12 @@ impl<'a> Resolver<'a> { continue; } ConstantItemRibKind(trivial) => { + let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !trivial && self.session.features_untracked().min_const_generics { + if !(trivial + || features.const_generics + || features.lazy_normalization_consts) + { if record_used { self.report_error( span, diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index fab29f29e87..ac1cdc6ad45 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -13,7 +13,7 @@ Core encoding and decoding interfaces. #![feature(never_type)] #![feature(nll)] #![feature(associated_type_bounds)] -#![feature(min_const_generics)] +#![cfg_attr(bootstrap, feature(min_const_generics))] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index c09f8cce5b4..cd871a4da97 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -293,7 +293,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { let err_ty_str; let mut is_ptr = true; - let err = if tcx.features().min_const_generics { + let err = if tcx.features().const_generics { + match ty.peel_refs().kind() { + ty::FnPtr(_) => Some("function pointers"), + ty::RawPtr(_) => Some("raw pointers"), + _ => None, + } + } else { match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None, ty::FnPtr(_) => Some("function pointers"), @@ -304,12 +310,6 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { Some(err_ty_str.as_str()) } } - } else { - match ty.peel_refs().kind() { - ty::FnPtr(_) => Some("function pointers"), - ty::RawPtr(_) => Some("raw pointers"), - _ => None, - } }; if let Some(unsupported_type) = err { if is_ptr { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index bc6b2037c18..dd4bfc7a751 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1260,7 +1260,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // used with const generics, e.g. `Foo<{N+1}>`, can work at all. // // Note that we do not supply the parent generics when using - // `feature(min_const_generics)`. + // `min_const_generics`. Some(parent_def_id.to_def_id()) } else { let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); -- cgit 1.4.1-3-g733a5 From 4ae99cc843b923d05e5c0993f732c5e0a9097852 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 19 Dec 2020 19:29:56 +0900 Subject: Fix ICE when pointing at multi bytes character --- compiler/rustc_parse/src/parser/mod.rs | 6 +-- .../multibyte-char-use-seperator-issue-80134.rs | 12 +++++ ...multibyte-char-use-seperator-issue-80134.stderr | 52 ++++++++++++++++++++++ src/test/ui/similar-tokens.fixed | 13 ------ src/test/ui/similar-tokens.rs | 2 - src/test/ui/similar-tokens.stderr | 2 +- 6 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/parser/multibyte-char-use-seperator-issue-80134.rs create mode 100644 src/test/ui/parser/multibyte-char-use-seperator-issue-80134.stderr delete mode 100644 src/test/ui/similar-tokens.fixed (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index e19ebb8fd2f..1062000fede 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -721,13 +721,9 @@ impl<'a> Parser<'a> { Ok(t) => { // Parsed successfully, therefore most probably the code only // misses a separator. - let mut exp_span = self.sess.source_map().next_point(sp); - if self.sess.source_map().is_multiline(exp_span) { - exp_span = sp; - } expect_err .span_suggestion_short( - exp_span, + sp, &format!("missing `{}`", token_str), token_str, Applicability::MaybeIncorrect, diff --git a/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.rs b/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.rs new file mode 100644 index 00000000000..f3ae3aba9b9 --- /dev/null +++ b/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.rs @@ -0,0 +1,12 @@ +// Regression test for #80134. + +fn main() { + (()é); + //~^ ERROR: expected one of `)`, `,`, `.`, `?`, or an operator + //~| ERROR: cannot find value `é` in this scope + //~| ERROR: non-ascii idents are not fully supported + (()氷); + //~^ ERROR: expected one of `)`, `,`, `.`, `?`, or an operator + //~| ERROR: cannot find value `氷` in this scope + //~| ERROR: non-ascii idents are not fully supported +} diff --git a/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.stderr b/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.stderr new file mode 100644 index 00000000000..892cc92b1bd --- /dev/null +++ b/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.stderr @@ -0,0 +1,52 @@ +error: expected one of `)`, `,`, `.`, `?`, or an operator, found `é` + --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8 + | +LL | (()é); + | ^ + | | + | expected one of `)`, `,`, `.`, `?`, or an operator + | help: missing `,` + +error: expected one of `)`, `,`, `.`, `?`, or an operator, found `氷` + --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8 + | +LL | (()氷); + | -^ + | | + | expected one of `)`, `,`, `.`, `?`, or an operator + | help: missing `,` + +error[E0425]: cannot find value `é` in this scope + --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8 + | +LL | (()é); + | ^ not found in this scope + +error[E0425]: cannot find value `氷` in this scope + --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8 + | +LL | (()氷); + | ^^ not found in this scope + +error[E0658]: non-ascii idents are not fully supported + --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8 + | +LL | (()é); + | ^ + | + = note: see issue #55467 for more information + = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable + +error[E0658]: non-ascii idents are not fully supported + --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8 + | +LL | (()氷); + | ^^ + | + = note: see issue #55467 for more information + = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0425, E0658. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/similar-tokens.fixed b/src/test/ui/similar-tokens.fixed deleted file mode 100644 index addba76ae3b..00000000000 --- a/src/test/ui/similar-tokens.fixed +++ /dev/null @@ -1,13 +0,0 @@ -// run-rustfix - -#![allow(unused_imports)] - -pub mod x { - pub struct A; - pub struct B; -} - -// `.` is similar to `,` so list parsing should continue to closing `}` -use x::{A, B}; //~ ERROR expected one of `,`, `::`, `as`, or `}`, found `.` - -fn main() {} diff --git a/src/test/ui/similar-tokens.rs b/src/test/ui/similar-tokens.rs index 3d1bf5fe54a..e3024c61ad2 100644 --- a/src/test/ui/similar-tokens.rs +++ b/src/test/ui/similar-tokens.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![allow(unused_imports)] pub mod x { diff --git a/src/test/ui/similar-tokens.stderr b/src/test/ui/similar-tokens.stderr index 6a8d09ebae6..90acfc052dd 100644 --- a/src/test/ui/similar-tokens.stderr +++ b/src/test/ui/similar-tokens.stderr @@ -1,5 +1,5 @@ error: expected one of `,`, `::`, `as`, or `}`, found `.` - --> $DIR/similar-tokens.rs:11:10 + --> $DIR/similar-tokens.rs:9:10 | LL | use x::{A. B}; | ^ -- cgit 1.4.1-3-g733a5 From edeac1778cbab28bb1d141e90e7ae6dc2eb97e60 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 29 Dec 2020 20:28:08 -0500 Subject: Rename kw::Invalid -> kw::Empty See https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Is.20there.20a.20symbol.20for.20the.20empty.20string.3F/near/220054471 for context. --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_builtin_macros/src/llvm_asm.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 4 ++-- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/context.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 10 +++++----- compiler/rustc_mir_build/src/build/mod.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 6 +++--- compiler/rustc_passes/src/liveness.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_resolve/src/build_reduced_graph.rs | 6 +++--- compiler/rustc_resolve/src/def_collector.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 6 +++--- compiler/rustc_resolve/src/macros.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 8 ++++---- compiler/rustc_typeck/src/check/expr.rs | 4 ++-- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 2 +- src/librustdoc/clean/mod.rs | 4 ++-- src/librustdoc/html/render/mod.rs | 6 +++--- src/tools/clippy/clippy_lints/src/lifetimes.rs | 2 +- 27 files changed, 46 insertions(+), 46 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2e1b5a74a7b..9dc6d6c98c7 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1716,7 +1716,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind { PatKind::Ident(_, ident, _) => ident, - _ => Ident::new(kw::Invalid, param.pat.span), + _ => Ident::new(kw::Empty, param.pat.span), })) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 686300c7c5f..f9eb69bb438 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -184,7 +184,7 @@ impl<'a> AstValidator<'a> { } fn check_lifetime(&self, ident: Ident) { - let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid]; + let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index dcb6e115eda..333a396a0b4 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2787,7 +2787,7 @@ impl<'a> State<'a> { self.print_explicit_self(&eself); } else { let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind { - ident.name == kw::Invalid + ident.name == kw::Empty } else { false }; diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs index db73fdbe24f..5f2b1c34d2b 100644 --- a/compiler/rustc_builtin_macros/src/llvm_asm.rs +++ b/compiler/rustc_builtin_macros/src/llvm_asm.rs @@ -93,7 +93,7 @@ fn parse_inline_asm<'a>( }) .unwrap_or(tts.len()); let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect()); - let mut asm = kw::Invalid; + let mut asm = kw::Empty; let mut asm_str_style = None; let mut outputs = Vec::new(); let mut inputs = Vec::new(); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index d5b2cbaa558..f1eae605da0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // (after #67586 gets fixed). None } else { - let name = kw::Invalid; + let name = kw::Empty; let decl = &self.mir.local_decls[local]; let dbg_var = if full_debug_info { self.adjusted_span_and_dbg_scope(decl.source_info).map( @@ -204,7 +204,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None } else { Some(match whole_local_var.or(fallback_var) { - Some(var) if var.name != kw::Invalid => var.name.to_string(), + Some(var) if var.name != kw::Empty => var.name.to_string(), _ => format!("{:?}", local), }) }; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2abebbd0303..b18d75dc6a3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -28,7 +28,7 @@ pub struct Lifetime { pub span: Span, /// Either "`'a`", referring to a named lifetime definition, - /// or "``" (i.e., `kw::Invalid`), for elision placeholders. + /// or "``" (i.e., `kw::Empty`), for elision placeholders. /// /// HIR lowering inserts these placeholders in type paths that /// refer to type definitions needing lifetime parameters, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index fa943d0d748..a8371274f61 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -868,7 +868,7 @@ impl EarlyLintPass for AnonymousParameters { if let ast::AssocItemKind::Fn(_, ref sig, _, _) = it.kind { for arg in sig.decl.inputs.iter() { if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind { - if ident.name == kw::Invalid { + if ident.name == kw::Empty { cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| { let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index bfeef490489..ea4f7daec43 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -728,7 +728,7 @@ impl<'tcx> LateContext<'tcx> { /// Check if a `DefId`'s path matches the given absolute type path usage. /// - /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; + /// Anonymous scopes such as `extern` imports are matched with `kw::Empty`; /// inherent `impl` blocks are matched with the name of the type. /// /// Instead of using this method, it is often preferable to instead use diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index fe29f9d177f..744fdc83a91 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -132,7 +132,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { impl Collector<'tcx> { fn register_native_lib(&mut self, span: Option, lib: NativeLib) { - if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) { + if lib.name.as_ref().map(|&s| s == kw::Empty).unwrap_or(false) { match span { Some(span) => { struct_span_err!( diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 598e28c1a3a..09d5b102103 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -379,7 +379,7 @@ impl<'hir> Map<'hir> { pub fn body_param_names(&self, id: BodyId) -> impl Iterator + 'hir { self.body(id).params.iter().map(|arg| match arg.pat.kind { PatKind::Binding(_, _, ident, _) => ident, - _ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP), + _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP), }) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 9b178d9d2bd..893572785f7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1481,7 +1481,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { // FIXME(eddyb) `name` should never be empty, but it // currently is for `extern { ... }` "foreign modules". let name = disambiguated_data.data.name(); - if name != DefPathDataName::Named(kw::Invalid) { + if name != DefPathDataName::Named(kw::Empty) { if !self.empty_path { write!(self, "::")?; } @@ -1608,14 +1608,14 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { match *region { ty::ReEarlyBound(ref data) => { - data.name != kw::Invalid && data.name != kw::UnderscoreLifetime + data.name != kw::Empty && data.name != kw::UnderscoreLifetime } ty::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { - if name != kw::Invalid && name != kw::UnderscoreLifetime { + if name != kw::Empty && name != kw::UnderscoreLifetime { return true; } } @@ -1685,7 +1685,7 @@ impl FmtPrinter<'_, '_, F> { // `explain_region()` or `note_and_explain_region()`. match *region { ty::ReEarlyBound(ref data) => { - if data.name != kw::Invalid { + if data.name != kw::Empty { p!(write("{}", data.name)); return Ok(self); } @@ -1694,7 +1694,7 @@ impl FmtPrinter<'_, '_, F> { | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { - if name != kw::Invalid && name != kw::UnderscoreLifetime { + if name != kw::Empty && name != kw::UnderscoreLifetime { p!(write("{}", name)); return Ok(self); } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e0414643812..99661599525 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -854,7 +854,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut mutability = Mutability::Not; // FIXME(project-rfc-2229#8): Store more precise information - let mut name = kw::Invalid; + let mut name = kw::Empty; if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { name = ident.name; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 634cce403df..c6669f04682 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -494,7 +494,7 @@ impl<'a> Parser<'a> { let polarity = self.parse_polarity(); // Parse both types and traits as a type, then reinterpret if necessary. - let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span)); + let err_path = |span| ast::Path::from_ident(Ident::new(kw::Empty, span)); let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt) { let span = self.prev_token.span.between(self.token.span); @@ -1699,7 +1699,7 @@ impl<'a> Parser<'a> { // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); // Create a placeholder argument for proper arg count (issue #34264). - Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_token.span)))) + Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)))) }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; @@ -1759,7 +1759,7 @@ impl<'a> Parser<'a> { } match ty { Ok(ty) => { - let ident = Ident::new(kw::Invalid, self.prev_token.span); + let ident = Ident::new(kw::Empty, self.prev_token.span); let bm = BindingMode::ByValue(Mutability::Not); let pat = self.mk_pat_ident(ty.span, bm, ident); (pat, ty) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 86ce35c6d99..b6f63130090 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1385,7 +1385,7 @@ impl<'tcx> Liveness<'_, 'tcx> { fn should_warn(&self, var: Variable) -> Option { let name = self.ir.variable_name(var); - if name == kw::Invalid { + if name == kw::Empty { return None; } let name: &str = &name.as_str(); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 3b4249a93e1..b13377bb2b1 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -959,7 +959,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { in_update_syntax: bool, ) { // definition of the field - let ident = Ident::new(kw::Invalid, use_ctxt); + let ident = Ident::new(kw::Empty, use_ctxt); let current_hir = self.current_item.unwrap(); let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, current_hir).1; if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 06e9969697d..6657201aaeb 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -342,7 +342,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let field_names = vdata .fields() .iter() - .map(|field| respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))) + .map(|field| respan(field.span, field.ident.map_or(kw::Empty, |ident| ident.name))) .collect(); self.insert_field_names(def_id, field_names); } @@ -527,7 +527,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // HACK(eddyb) unclear how good this is, but keeping `$crate` // in `source` breaks `src/test/compile-fail/import-crate-var.rs`, // while the current crate doesn't have a valid `crate_name`. - if crate_name != kw::Invalid { + if crate_name != kw::Empty { // `crate_name` should not be interpreted as relative. module_path.push(Segment { ident: Ident { name: kw::PathRoot, span: source.ident.span }, @@ -656,7 +656,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &'b Item) { - if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Invalid { + if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty { // Fake crate root item from expand. return; } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 69773ba1d72..48bce884394 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -74,7 +74,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { // information we encapsulate into, the better let def_data = match &i.kind { ItemKind::Impl { .. } => DefPathData::Impl, - ItemKind::Mod(..) if i.ident.name == kw::Invalid => { + ItemKind::Mod(..) if i.ident.name == kw::Empty => { // Fake crate root item from expand. return visit::walk_item(self, i); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b13462587bc..e45d7223849 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1641,7 +1641,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } // Record as bound if it's valid: - let ident_valid = ident.name != kw::Invalid; + let ident_valid = ident.name != kw::Empty; if ident_valid { bindings.last_mut().unwrap().1.insert(ident); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5c79cfa9c1d..c2780b46f6c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1182,12 +1182,12 @@ impl<'a> Resolver<'a> { ) -> Resolver<'a> { let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }; let root_def_id = root_local_def_id.to_def_id(); - let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid); + let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); let graph_root = arenas.alloc_module(ModuleData { no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude), ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span) }); - let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid); + let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); let empty_module = arenas.alloc_module(ModuleData { no_implicit_prelude: true, ..ModuleData::new( @@ -1797,7 +1797,7 @@ impl<'a> Resolver<'a> { ribs: &[Rib<'a>], ) -> Option> { assert!(ns == TypeNS || ns == ValueNS); - if ident.name == kw::Invalid { + if ident.name == kw::Empty { return Some(LexicalScopeBinding::Res(Res::Err)); } let (general_span, normalized_span) = if ident.name == kw::SelfUpper { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c8dbe685128..5ad7c83ca36 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -160,7 +160,7 @@ impl<'a> ResolverExpand for Resolver<'a> { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); match self.resolve_crate_root(ident).kind { - ModuleKind::Def(.., name) if name != kw::Invalid => name, + ModuleKind::Def(.., name) if name != kw::Empty => name, _ => kw::Crate, } }); diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 0f82db1d05a..fdc0d225bb8 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1065,7 +1065,7 @@ pub fn decode_syntax_context< parent: SyntaxContext::root(), opaque: SyntaxContext::root(), opaque_and_semitransparent: SyntaxContext::root(), - dollar_crate_name: kw::Invalid, + dollar_crate_name: kw::Empty, }); let mut ctxts = outer_ctxts.lock(); let new_len = raw_id as usize + 1; @@ -1092,7 +1092,7 @@ pub fn decode_syntax_context< ctxt_data, ); // Make sure nothing weird happening while `decode_data` was running - assert_eq!(dummy.dollar_crate_name, kw::Invalid); + assert_eq!(dummy.dollar_crate_name, kw::Empty); }); Ok(new_ctxt) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 99a523c3f3b..d324465c895 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -25,7 +25,7 @@ symbols! { Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. - Invalid: "", + Empty: "", PathRoot: "{{root}}", DollarCrate: "$crate", Underscore: "_", @@ -1273,7 +1273,7 @@ impl Ident { #[inline] pub fn invalid() -> Ident { - Ident::with_dummy_span(kw::Invalid) + Ident::with_dummy_span(kw::Empty) } /// Maps a string to an identifier with a dummy span. @@ -1470,7 +1470,7 @@ impl Symbol { } pub fn is_empty(self) -> bool { - self == kw::Invalid + self == kw::Empty } /// This method is supposed to be used in error messages, so it's expected to be @@ -1654,7 +1654,7 @@ impl Symbol { /// Returns `true` if this symbol can be a raw identifier. pub fn can_be_raw(self) -> bool { - self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword() + self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword() } } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index ec0e039b5d2..93eb2cfc72a 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -883,7 +883,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) } Err(error) => { - if segment.ident.name != kw::Invalid { + if segment.ident.name != kw::Empty { self.report_extended_method_error(segment, span, args, rcvr_t, error); } Err(()) @@ -1547,7 +1547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return field_ty; } - if field.name == kw::Invalid { + if field.name == kw::Empty { } else if self.method_exists(field, expr_t, expr.hir_id, true) { self.ban_take_value_of_method(expr, expr_t, field); } else if !expr_t.is_primitive_ty() { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 41a403a010e..2a8b77da44f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -914,7 +914,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), _ => Err(ErrorReported), }; - if item_name.name != kw::Invalid { + if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, ty, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dd96178cdb7..657b8d3879f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -941,7 +941,7 @@ impl<'a> Clean for (&'a [hir::Ty<'a>], &'a [Ident]) { .iter() .enumerate() .map(|(i, ty)| { - let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Invalid); + let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Empty); if name.is_empty() { name = kw::Underscore; } @@ -1000,7 +1000,7 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { .iter() .map(|t| Argument { type_: t.clean(cx), - name: names.next().map(|i| i.name).unwrap_or(kw::Invalid), + name: names.next().map(|i| i.name).unwrap_or(kw::Empty), }) .collect(), }, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 185df60735f..a6ac3bdb714 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2086,8 +2086,8 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl (true, false) => return Ordering::Greater, } } - let lhs = i1.name.unwrap_or(kw::Invalid).as_str(); - let rhs = i2.name.unwrap_or(kw::Invalid).as_str(); + let lhs = i1.name.unwrap_or(kw::Empty).as_str(); + let rhs = i2.name.unwrap_or(kw::Empty).as_str(); compare_names(&lhs, &rhs) } @@ -4206,7 +4206,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache: ty: \"{ty}\", \ relpath: \"{path}\"\ }};", - name = it.name.unwrap_or(kw::Invalid), + name = it.name.unwrap_or(kw::Empty), ty = it.type_(), path = relpath ); diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 4d737b3f49b..e84c8b4e5b3 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -501,7 +501,7 @@ impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - if lifetime.name.ident().name != kw::Invalid && lifetime.name.ident().name != kw::StaticLifetime { + if lifetime.name.ident().name != kw::Empty && lifetime.name.ident().name != kw::StaticLifetime { self.lifetimes_used_in_body = true; } } -- cgit 1.4.1-3-g733a5 From 40bf3c0f09240836d55431165f20cf221816c958 Mon Sep 17 00:00:00 2001 From: mark Date: Mon, 28 Dec 2020 16:57:13 -0600 Subject: Implement edition-based macro pat feature --- compiler/rustc_ast/src/token.rs | 35 +++++++++-- compiler/rustc_expand/src/mbe/macro_parser.rs | 24 ++------ compiler/rustc_expand/src/mbe/macro_rules.rs | 16 +++-- compiler/rustc_expand/src/mbe/quoted.rs | 68 +++++++++++++++------- compiler/rustc_feature/src/active.rs | 3 + compiler/rustc_parse/src/parser/mod.rs | 1 - compiler/rustc_parse/src/parser/nonterminal.rs | 27 ++++----- compiler/rustc_parse/src/parser/pat.rs | 7 --- compiler/rustc_span/src/symbol.rs | 3 + src/test/ui/feature-gate-edition_macro_pats.rs | 8 +++ src/test/ui/feature-gate-edition_macro_pats.stderr | 21 +++++++ src/test/ui/macros/edition-macro-pats.rs | 14 +++++ 12 files changed, 151 insertions(+), 76 deletions(-) create mode 100644 src/test/ui/feature-gate-edition_macro_pats.rs create mode 100644 src/test/ui/feature-gate-edition_macro_pats.stderr create mode 100644 src/test/ui/macros/edition-macro-pats.rs (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index cd1e444bcf7..6dde304e8cf 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -15,7 +15,7 @@ use rustc_span::hygiene::ExpnKind; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{self, FileName, RealFileName, Span, DUMMY_SP}; +use rustc_span::{self, edition::Edition, FileName, RealFileName, Span, DUMMY_SP}; use std::borrow::Cow; use std::{fmt, mem}; @@ -690,7 +690,16 @@ pub enum NonterminalKind { Item, Block, Stmt, - Pat, + Pat2018 { + /// Keep track of whether the user used `:pat2018` or `:pat` and we inferred it from the + /// edition of the span. This is used for diagnostics. + inferred: bool, + }, + Pat2021 { + /// Keep track of whether the user used `:pat2018` or `:pat` and we inferred it from the + /// edition of the span. This is used for diagnostics. + inferred: bool, + }, Expr, Ty, Ident, @@ -703,12 +712,25 @@ pub enum NonterminalKind { } impl NonterminalKind { - pub fn from_symbol(symbol: Symbol) -> Option { + /// The `edition` closure is used to get the edition for the given symbol. Doing + /// `span.edition()` is expensive, so we do it lazily. + pub fn from_symbol( + symbol: Symbol, + edition: impl FnOnce() -> Edition, + ) -> Option { Some(match symbol { sym::item => NonterminalKind::Item, sym::block => NonterminalKind::Block, sym::stmt => NonterminalKind::Stmt, - sym::pat => NonterminalKind::Pat, + sym::pat => match edition() { + Edition::Edition2015 | Edition::Edition2018 => { + NonterminalKind::Pat2018 { inferred: true } + } + // FIXME(mark-i-m): uncomment when 2021 machinery is available. + //Edition::Edition2021 => NonterminalKind::Pat2021{inferred:true}, + }, + sym::pat2018 => NonterminalKind::Pat2018 { inferred: false }, + sym::pat2021 => NonterminalKind::Pat2021 { inferred: false }, sym::expr => NonterminalKind::Expr, sym::ty => NonterminalKind::Ty, sym::ident => NonterminalKind::Ident, @@ -726,7 +748,10 @@ impl NonterminalKind { NonterminalKind::Item => sym::item, NonterminalKind::Block => sym::block, NonterminalKind::Stmt => sym::stmt, - NonterminalKind::Pat => sym::pat, + NonterminalKind::Pat2018 { inferred: false } => sym::pat2018, + NonterminalKind::Pat2021 { inferred: false } => sym::pat2021, + NonterminalKind::Pat2018 { inferred: true } + | NonterminalKind::Pat2021 { inferred: true } => sym::pat, NonterminalKind::Expr => sym::expr, NonterminalKind::Ty => sym::ty, NonterminalKind::Ident => sym::ident, diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 0c44f5fe9e1..e76cc6f1fed 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -77,9 +77,9 @@ use TokenTreeOrTokenTreeSlice::*; use crate::mbe::{self, TokenTree}; use rustc_ast::token::{self, DocComment, Nonterminal, Token}; -use rustc_parse::parser::{OrPatNonterminalMode, Parser}; +use rustc_parse::parser::Parser; use rustc_session::parse::ParseSess; -use rustc_span::{edition::Edition, symbol::MacroRulesNormalizedIdent}; +use rustc_span::symbol::MacroRulesNormalizedIdent; use smallvec::{smallvec, SmallVec}; @@ -419,18 +419,6 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { } } -/// In edition 2015/18, `:pat` can only match `pat` because otherwise, we have -/// breakage. As of edition 2021, `:pat` matches `top_pat`. -/// -/// See for more info. -fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode { - match edition { - Edition::Edition2015 | Edition::Edition2018 => OrPatNonterminalMode::NoTopAlt, - // FIXME(mark-i-m): uncomment this when edition 2021 machinery is added. - // Edition::Edition2021 => OrPatNonterminalMode::TopPat, - } -} - /// Process the matcher positions of `cur_items` until it is empty. In the process, this will /// produce more items in `next_items`, `eof_items`, and `bb_items`. /// @@ -578,14 +566,13 @@ fn inner_parse_loop<'root, 'tt>( // We need to match a metavar with a valid ident... call out to the black-box // parser by adding an item to `bb_items`. - TokenTree::MetaVarDecl(span, _, Some(kind)) => { + TokenTree::MetaVarDecl(_, _, Some(kind)) => { // Built-in nonterminals never start with these tokens, so we can eliminate // them from consideration. // // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. - if Parser::nonterminal_may_begin_with(kind, token, or_pat_mode(span.edition())) - { + if Parser::nonterminal_may_begin_with(kind, token) { bb_items.push(item); } } @@ -749,8 +736,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na let match_cur = item.match_cur; // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. - let nt = match parser.to_mut().parse_nonterminal(kind, or_pat_mode(span.edition())) - { + let nt = match parser.to_mut().parse_nonterminal(kind) { Err(mut err) => { err.span_label( span, diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 89d375b257d..3d126749d54 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -476,10 +476,15 @@ pub fn compile_declarative_macro( .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - let tt = - mbe::quoted::parse(tt.clone().into(), true, &sess.parse_sess, def.id) - .pop() - .unwrap(); + let tt = mbe::quoted::parse( + tt.clone().into(), + true, + &sess.parse_sess, + def.id, + features, + ) + .pop() + .unwrap(); valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def.attrs, &tt); return tt; } @@ -501,6 +506,7 @@ pub fn compile_declarative_macro( false, &sess.parse_sess, def.id, + features, ) .pop() .unwrap(); @@ -1090,7 +1096,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - NonterminalKind::Pat => { + NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => { const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 01b11bb979d..a4b44931fc1 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -5,8 +5,9 @@ use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; -use rustc_session::parse::ParseSess; -use rustc_span::symbol::{kw, Ident}; +use rustc_feature::Features; +use rustc_session::parse::{feature_err, ParseSess}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -29,10 +30,8 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ /// `ident` are "matchers". They are not present in the body of a macro rule -- just in the /// pattern, so we pass a parameter to indicate whether to expect them or not. /// - `sess`: the parsing session. Any errors will be emitted to this session. -/// - `features`, `attrs`: language feature flags and attributes so that we know whether to use -/// unstable features or not. -/// - `edition`: which edition are we in. -/// - `macro_node_id`: the NodeId of the macro we are parsing. +/// - `node_id`: the NodeId of the macro we are parsing. +/// - `features`: language features so we can do feature gating. /// /// # Returns /// @@ -42,6 +41,7 @@ pub(super) fn parse( expect_matchers: bool, sess: &ParseSess, node_id: NodeId, + features: &Features, ) -> Vec { // Will contain the final collection of `self::TokenTree` let mut result = Vec::new(); @@ -52,7 +52,7 @@ pub(super) fn parse( while let Some(tree) = trees.next() { // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`). - let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id); + let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features); match tree { TokenTree::MetaVar(start_sp, ident) if expect_matchers => { let span = match trees.next() { @@ -61,18 +61,39 @@ pub(super) fn parse( Some(tokenstream::TokenTree::Token(token)) => match token.ident() { Some((frag, _)) => { let span = token.span.with_lo(start_sp.lo()); - let kind = token::NonterminalKind::from_symbol(frag.name) - .unwrap_or_else(|| { - let msg = format!( - "invalid fragment specifier `{}`", - frag.name - ); - sess.span_diagnostic - .struct_span_err(span, &msg) - .help(VALID_FRAGMENT_NAMES_MSG) + + match frag.name { + sym::pat2018 | sym::pat2021 => { + if !features.edition_macro_pats { + feature_err( + sess, + sym::edition_macro_pats, + frag.span, + "`pat2018` and `pat2021` are unstable.", + ) .emit(); - token::NonterminalKind::Ident - }); + } + } + _ => {} + } + + let kind = + token::NonterminalKind::from_symbol(frag.name, || { + span.edition() + }) + .unwrap_or_else( + || { + let msg = format!( + "invalid fragment specifier `{}`", + frag.name + ); + sess.span_diagnostic + .struct_span_err(span, &msg) + .help(VALID_FRAGMENT_NAMES_MSG) + .emit(); + token::NonterminalKind::Ident + }, + ); result.push(TokenTree::MetaVarDecl(span, ident, Some(kind))); continue; } @@ -110,14 +131,14 @@ pub(super) fn parse( /// converting `tree` /// - `expect_matchers`: same as for `parse` (see above). /// - `sess`: the parsing session. Any errors will be emitted to this session. -/// - `features`, `attrs`: language feature flags and attributes so that we know whether to use -/// unstable features or not. +/// - `features`: language features so we can do feature gating. fn parse_tree( tree: tokenstream::TokenTree, outer_trees: &mut impl Iterator, expect_matchers: bool, sess: &ParseSess, node_id: NodeId, + features: &Features, ) -> TokenTree { // Depending on what `tree` is, we could be parsing different parts of a macro match tree { @@ -145,7 +166,7 @@ fn parse_tree( sess.span_diagnostic.span_err(span.entire(), &msg); } // Parse the contents of the sequence itself - let sequence = parse(tts, expect_matchers, sess, node_id); + let sequence = parse(tts, expect_matchers, sess, node_id, features); // Get the Kleene operator and optional separator let (separator, kleene) = parse_sep_and_kleene_op(&mut trees, span.entire(), sess); @@ -196,7 +217,10 @@ fn parse_tree( // descend into the delimited set and further parse it. tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited( span, - Lrc::new(Delimited { delim, tts: parse(tts, expect_matchers, sess, node_id) }), + Lrc::new(Delimited { + delim, + tts: parse(tts, expect_matchers, sess, node_id, features), + }), ), } } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index d60ae8ef75b..c61857a1cd0 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -620,6 +620,9 @@ declare_features! ( /// Allows arbitrary expressions in key-value attributes at parse time. (active, extended_key_value_attributes, "1.50.0", Some(78835), None), + /// `:pat2018` and `:pat2021` macro matchers. + (active, edition_macro_pats, "1.51.0", Some(54883), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index e19ebb8fd2f..d51a0fcbf09 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -12,7 +12,6 @@ mod ty; use crate::lexer::UnmatchedBrace; pub use diagnostics::AttemptLocalParseRecovery; use diagnostics::Error; -pub use pat::OrPatNonterminalMode; pub use path::PathStyle; use rustc_ast::ptr::P; diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index a6b9ac1014e..eb5d7075f00 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -4,7 +4,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; -use crate::parser::pat::{GateOr, OrPatNonterminalMode, RecoverComma}; +use crate::parser::pat::{GateOr, RecoverComma}; use crate::parser::{FollowedByType, Parser, PathStyle}; impl<'a> Parser<'a> { @@ -12,11 +12,7 @@ impl<'a> Parser<'a> { /// /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that /// token. Be conservative (return true) if not sure. - pub fn nonterminal_may_begin_with( - kind: NonterminalKind, - token: &Token, - or_pat_mode: OrPatNonterminalMode, - ) -> bool { + pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { match *nt { @@ -62,7 +58,7 @@ impl<'a> Parser<'a> { }, _ => false, }, - NonterminalKind::Pat => match token.kind { + NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => match token.kind { token::Ident(..) | // box, ref, mut, and other identifiers (can stricten) token::OpenDelim(token::Paren) | // tuple pattern token::OpenDelim(token::Bracket) | // slice pattern @@ -76,7 +72,7 @@ impl<'a> Parser<'a> { token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) // leading vert `|` or-pattern - token::BinOp(token::Or) => matches!(or_pat_mode, OrPatNonterminalMode::TopPat), + token::BinOp(token::Or) => matches!(kind, NonterminalKind::Pat2021 {..}), token::Interpolated(ref nt) => may_be_ident(nt), _ => false, }, @@ -94,11 +90,7 @@ impl<'a> Parser<'a> { } /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). - pub fn parse_nonterminal( - &mut self, - kind: NonterminalKind, - or_pat_mode: OrPatNonterminalMode, - ) -> PResult<'a, Nonterminal> { + pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonterminal> { // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`) // needs to have them force-captured here. // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, @@ -141,12 +133,13 @@ impl<'a> Parser<'a> { } } } - NonterminalKind::Pat => { - let (mut pat, tokens) = self.collect_tokens(|this| match or_pat_mode { - OrPatNonterminalMode::TopPat => { + NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => { + let (mut pat, tokens) = self.collect_tokens(|this| match kind { + NonterminalKind::Pat2018 { .. } => this.parse_pat(None), + NonterminalKind::Pat2021 { .. } => { this.parse_top_pat(GateOr::Yes, RecoverComma::No) } - OrPatNonterminalMode::NoTopAlt => this.parse_pat(None), + _ => unreachable!(), })?; // We have have eaten an NtPat, which could already have tokens if pat.tokens.is_none() { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 1da371e0b72..456e32680fe 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -31,13 +31,6 @@ pub(super) enum RecoverComma { No, } -/// Used when parsing a non-terminal (see `parse_nonterminal`) to determine if `:pat` should match -/// `top_pat` or `pat`. See issue . -pub enum OrPatNonterminalMode { - TopPat, - NoTopAlt, -} - impl<'a> Parser<'a> { /// Parses a pattern. /// diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bc57a00e31b..eb3588d5775 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -470,6 +470,7 @@ symbols! { dropck_parametricity, dylib, dyn_trait, + edition_macro_pats, eh_catch_typeinfo, eh_personality, emit_enum, @@ -808,6 +809,8 @@ symbols! { partial_ord, passes, pat, + pat2018, + pat2021, path, pattern_parentheses, phantom_data, diff --git a/src/test/ui/feature-gate-edition_macro_pats.rs b/src/test/ui/feature-gate-edition_macro_pats.rs new file mode 100644 index 00000000000..bd8a21ea36a --- /dev/null +++ b/src/test/ui/feature-gate-edition_macro_pats.rs @@ -0,0 +1,8 @@ +// Feature gate test for `edition_macro_pats` feature. + +macro_rules! foo { + ($x:pat2018) => {}; //~ERROR `pat2018` and `pat2021` are unstable + ($x:pat2021) => {}; //~ERROR `pat2018` and `pat2021` are unstable +} + +fn main() {} diff --git a/src/test/ui/feature-gate-edition_macro_pats.stderr b/src/test/ui/feature-gate-edition_macro_pats.stderr new file mode 100644 index 00000000000..89bfb239d9e --- /dev/null +++ b/src/test/ui/feature-gate-edition_macro_pats.stderr @@ -0,0 +1,21 @@ +error[E0658]: `pat2018` and `pat2021` are unstable. + --> $DIR/feature-gate-edition_macro_pats.rs:4:9 + | +LL | ($x:pat2018) => {}; + | ^^^^^^^ + | + = note: see issue #54883 for more information + = help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable + +error[E0658]: `pat2018` and `pat2021` are unstable. + --> $DIR/feature-gate-edition_macro_pats.rs:5:9 + | +LL | ($x:pat2021) => {}; + | ^^^^^^^ + | + = note: see issue #54883 for more information + = help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macros/edition-macro-pats.rs b/src/test/ui/macros/edition-macro-pats.rs new file mode 100644 index 00000000000..ea1f9bff6bf --- /dev/null +++ b/src/test/ui/macros/edition-macro-pats.rs @@ -0,0 +1,14 @@ +// run-pass + +#![feature(or_patterns)] +#![feature(edition_macro_pats)] + +macro_rules! foo { + (a $x:pat2018) => {}; + (b $x:pat2021) => {}; +} + +fn main() { + foo!(a None); + foo!(b 1 | 2); +} -- cgit 1.4.1-3-g733a5