From 053afa7aec67d0bc8dc23e8217d77846ca9fc3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 5 Aug 2019 19:23:46 -0700 Subject: [PATCH 01/45] Do not complain about unused code when used in `impl` `Self` type --- src/librustc/middle/dead.rs | 26 ++++++++++---- src/test/ui/derive-uninhabited-enum-38885.rs | 11 +++--- .../ui/derive-uninhabited-enum-38885.stderr | 14 +++----- .../ui/lint/lint-dead-code-const-and-self.rs | 35 +++++++++++++++++++ 4 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/lint/lint-dead-code-const-and-self.rs diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 8ce8bb52566c6..d4805a7c78322 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -30,10 +30,11 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { Some(Node::Item(..)) | Some(Node::ImplItem(..)) | Some(Node::ForeignItem(..)) | - Some(Node::TraitItem(..)) => - true, - _ => - false + Some(Node::TraitItem(..)) | + Some(Node::Variant(..)) | + Some(Node::AnonConst(..)) | + Some(Node::Pat(..)) => true, + _ => false } } @@ -75,7 +76,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(res.def_id()); } _ if self.in_pat => {}, - Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) | + Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {} Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => { let variant_id = self.tcx.parent(ctor_def_id).unwrap(); @@ -92,6 +93,14 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(variant_id); } } + Res::SelfTy(t, i) => { + if let Some(t) = t { + self.check_def_id(t); + } + if let Some(i) = i { + self.check_def_id(i); + } + } Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {} _ => { self.check_def_id(res.def_id()); @@ -271,7 +280,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { let res = self.tables.qpath_res(path, pat.hir_id); self.handle_field_pattern_match(pat, res, fields); } - PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => { + PatKind::Path(ref qpath) => { let res = self.tables.qpath_res(qpath, pat.hir_id); self.handle_res(res); } @@ -298,6 +307,11 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { } intravisit::walk_ty(self, ty); } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + self.live_symbols.insert(c.hir_id); + intravisit::walk_anon_const(self, c); + } } fn has_allow_dead_code_or_lang_attr( diff --git a/src/test/ui/derive-uninhabited-enum-38885.rs b/src/test/ui/derive-uninhabited-enum-38885.rs index 2c4d64e4e6063..010464adf5bce 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.rs +++ b/src/test/ui/derive-uninhabited-enum-38885.rs @@ -5,12 +5,15 @@ // when deriving Debug on an empty enum #[derive(Debug)] -enum Void {} //~ WARN never used +enum Void {} #[derive(Debug)] -enum Foo { //~ WARN never used +enum Foo { Bar(u8), - Void(Void), + Void(Void), //~ WARN never used } -fn main() {} +fn main() { + let x = Foo::Bar(42); + println!("{:?}", x); +} diff --git a/src/test/ui/derive-uninhabited-enum-38885.stderr b/src/test/ui/derive-uninhabited-enum-38885.stderr index 941c98b5506b2..a3ed6798a7039 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.stderr +++ b/src/test/ui/derive-uninhabited-enum-38885.stderr @@ -1,14 +1,8 @@ -warning: enum is never used: `Void` - --> $DIR/derive-uninhabited-enum-38885.rs:8:1 +warning: variant is never constructed: `Void` + --> $DIR/derive-uninhabited-enum-38885.rs:13:5 | -LL | enum Void {} - | ^^^^^^^^^ +LL | Void(Void), + | ^^^^^^^^^^ | = note: `-W dead-code` implied by `-W unused` -warning: enum is never used: `Foo` - --> $DIR/derive-uninhabited-enum-38885.rs:11:1 - | -LL | enum Foo { - | ^^^^^^^^ - diff --git a/src/test/ui/lint/lint-dead-code-const-and-self.rs b/src/test/ui/lint/lint-dead-code-const-and-self.rs new file mode 100644 index 0000000000000..1a7b3f43cda14 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-const-and-self.rs @@ -0,0 +1,35 @@ +// check-pass + +#![deny(dead_code)] + +const TLC: usize = 4; + +trait Tr { fn doit(&self); } + +impl Tr for [usize; TLC] { + fn doit(&self) { + println!("called 4"); + } +} + +struct X; +struct Y; +struct Z; + +trait Foo { + type Ty; + fn foo() -> Self::Ty; +} + +impl Foo for X { + type Ty = Z; + fn foo() -> Self::Ty { + unimplemented!() + } +} + +fn main() { + let s = [0,1,2,3]; + s.doit(); + X::foo(); +} From 352d97e6b7a3ddfd1f4de1d592fcf95d8a507f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 21 Aug 2019 16:30:11 -0700 Subject: [PATCH 02/45] Add more tests covering more cases --- .../lint-dead-code-empty-unused-enum-pub.rs | 6 +++++ .../lint/lint-dead-code-empty-unused-enum.rs | 5 ++++ .../lint-dead-code-empty-unused-enum.stderr | 15 +++++++++++ .../ui/lint/lint-dead-code-unused-enum.rs | 11 ++++++++ .../ui/lint/lint-dead-code-unused-enum.stderr | 27 +++++++++++++++++++ .../lint/lint-dead-code-unused-variant-pub.rs | 14 ++++++++++ .../ui/lint/lint-dead-code-unused-variant.rs | 13 +++++++++ .../lint/lint-dead-code-unused-variant.stderr | 15 +++++++++++ 8 files changed, 106 insertions(+) create mode 100644 src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs create mode 100644 src/test/ui/lint/lint-dead-code-empty-unused-enum.rs create mode 100644 src/test/ui/lint/lint-dead-code-empty-unused-enum.stderr create mode 100644 src/test/ui/lint/lint-dead-code-unused-enum.rs create mode 100644 src/test/ui/lint/lint-dead-code-unused-enum.stderr create mode 100644 src/test/ui/lint/lint-dead-code-unused-variant-pub.rs create mode 100644 src/test/ui/lint/lint-dead-code-unused-variant.rs create mode 100644 src/test/ui/lint/lint-dead-code-unused-variant.stderr diff --git a/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs b/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs new file mode 100644 index 0000000000000..2b06fcb69ceee --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs @@ -0,0 +1,6 @@ +// run-pass +#![deny(unused)] + +pub enum E {} + +fn main() {} diff --git a/src/test/ui/lint/lint-dead-code-empty-unused-enum.rs b/src/test/ui/lint/lint-dead-code-empty-unused-enum.rs new file mode 100644 index 0000000000000..834681d77e613 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-empty-unused-enum.rs @@ -0,0 +1,5 @@ +#![deny(unused)] + +enum E {} //~ ERROR enum is never used + +fn main() {} diff --git a/src/test/ui/lint/lint-dead-code-empty-unused-enum.stderr b/src/test/ui/lint/lint-dead-code-empty-unused-enum.stderr new file mode 100644 index 0000000000000..4e3bebfc48bde --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-empty-unused-enum.stderr @@ -0,0 +1,15 @@ +error: enum is never used: `E` + --> $DIR/lint-dead-code-empty-unused-enum.rs:3:1 + | +LL | enum E {} + | ^^^^^^ + | +note: lint level defined here + --> $DIR/lint-dead-code-empty-unused-enum.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(unused)]` + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-dead-code-unused-enum.rs b/src/test/ui/lint/lint-dead-code-unused-enum.rs new file mode 100644 index 0000000000000..e57fac259c5d5 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-enum.rs @@ -0,0 +1,11 @@ +#![deny(unused)] + +struct F; //~ ERROR struct is never constructed +struct B; //~ ERROR struct is never constructed + +enum E { //~ ERROR enum is never used + Foo(F), + Bar(B), +} + +fn main() {} diff --git a/src/test/ui/lint/lint-dead-code-unused-enum.stderr b/src/test/ui/lint/lint-dead-code-unused-enum.stderr new file mode 100644 index 0000000000000..ea711e7b05ee6 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-enum.stderr @@ -0,0 +1,27 @@ +error: struct is never constructed: `F` + --> $DIR/lint-dead-code-unused-enum.rs:3:1 + | +LL | struct F; + | ^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-dead-code-unused-enum.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(unused)]` + +error: struct is never constructed: `B` + --> $DIR/lint-dead-code-unused-enum.rs:4:1 + | +LL | struct B; + | ^^^^^^^^^ + +error: enum is never used: `E` + --> $DIR/lint-dead-code-unused-enum.rs:6:1 + | +LL | enum E { + | ^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs b/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs new file mode 100644 index 0000000000000..918300ba79354 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs @@ -0,0 +1,14 @@ +// run-pass +#![deny(unused)] + +pub struct F; +pub struct B; + +pub enum E { + Foo(F), + Bar(B), +} + +fn main() { + let _ = E::Foo(F); +} diff --git a/src/test/ui/lint/lint-dead-code-unused-variant.rs b/src/test/ui/lint/lint-dead-code-unused-variant.rs new file mode 100644 index 0000000000000..69ab29042e5a4 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-variant.rs @@ -0,0 +1,13 @@ +#![deny(unused)] + +struct F; +struct B; + +enum E { + Foo(F), + Bar(B), //~ ERROR variant is never constructed +} + +fn main() { + let _ = E::Foo(F); +} diff --git a/src/test/ui/lint/lint-dead-code-unused-variant.stderr b/src/test/ui/lint/lint-dead-code-unused-variant.stderr new file mode 100644 index 0000000000000..919996ec30020 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-variant.stderr @@ -0,0 +1,15 @@ +error: variant is never constructed: `Bar` + --> $DIR/lint-dead-code-unused-variant.rs:8:5 + | +LL | Bar(B), + | ^^^^^^ + | +note: lint level defined here + --> $DIR/lint-dead-code-unused-variant.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(unused)]` + +error: aborting due to previous error + From 912feabfc282d0040f5e56bfbba752069d4f5a1f Mon Sep 17 00:00:00 2001 From: Baoshan Pang Date: Fri, 23 Aug 2019 13:25:01 -0700 Subject: [PATCH 03/45] VxWorks does not provide a way to set the task name except at creation time --- src/libstd/sys/vxworks/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs index 58af8cbe48e36..ef896f6a6e8cf 100644 --- a/src/libstd/sys/vxworks/thread.rs +++ b/src/libstd/sys/vxworks/thread.rs @@ -77,7 +77,7 @@ impl Thread { } pub fn set_name(_name: &CStr) { - assert!(false, "FIXME: set_name"); + // VxWorks does not provide a way to set the task name except at creation time } pub fn sleep(dur: Duration) { From a577316b0a136b5ca980032cf1dbe683103ba15f Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 24 Aug 2019 13:36:57 +0200 Subject: [PATCH 04/45] Removed the confusing FnOnce example. closes #47091 --- src/libcore/ops/function.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index b9552eaa1a0e5..9bb1ae8572b71 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -184,15 +184,6 @@ pub trait FnMut : FnOnce { /// [nomicon]: ../../nomicon/hrtb.html /// /// # Examples -/// -/// ## Calling a by-value closure -/// -/// ``` -/// let x = 5; -/// let square_x = move || x * x; -/// assert_eq!(square_x(), 25); -/// ``` -/// /// ## Using a `FnOnce` parameter /// /// ``` From 55f8dde6c89e3af68d4c59232f3d06e6130e9f0a Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 24 Aug 2019 13:38:09 +0200 Subject: [PATCH 05/45] Added an extra line to make the formatting conform to the rest of the document. --- src/libcore/ops/function.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index 9bb1ae8572b71..4a0a2720fe441 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -184,6 +184,7 @@ pub trait FnMut : FnOnce { /// [nomicon]: ../../nomicon/hrtb.html /// /// # Examples +/// /// ## Using a `FnOnce` parameter /// /// ``` From 8ca9c7bbe5f2be252881e1edbd2a2ce97e75244f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 24 Aug 2019 17:45:03 +0200 Subject: [PATCH 06/45] Fix tidy feature gate error reporting Feature gate definitions were split into multiple files in #63824 but tidy kept reporting the hard-coded path. Now, it shows the full path to the correct file. --- src/tools/tidy/src/features.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 468e56001012f..50e9116c778ea 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -176,7 +176,10 @@ pub fn check(path: &Path, bad: &mut bool, verbose: bool) -> CollectedFeatures { CollectedFeatures { lib: lib_features, lang: features } } -fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { +fn format_features<'a>( + features: &'a Features, + family: &'a str, +) -> impl Iterator + 'a { features.iter().map(move |(name, feature)| { format!("{:<32} {:<8} {:<12} {:<8}", name, @@ -228,7 +231,8 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { } fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features { - let contents = t!(fs::read_to_string(base.join("libsyntax/feature_gate").join(file))); + let path = base.join("libsyntax/feature_gate").join(file); + let contents = t!(fs::read_to_string(&path)); // We allow rustc-internal features to omit a tracking issue. // To make tidy accept omitting a tracking issue, group the list of features @@ -259,8 +263,9 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features if in_feature_group { tidy_error!( bad, - // ignore-tidy-linelength - "libsyntax/feature_gate.rs:{}: new feature group is started without ending the previous one", + "{}:{}: \ + new feature group is started without ending the previous one", + path.display(), line_number, ); } @@ -289,7 +294,8 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features Err(err) => { tidy_error!( bad, - "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({:?})", + "{}:{}: failed to parse since: {} ({:?})", + path.display(), line_number, since_str, err, @@ -301,7 +307,8 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features if prev_since > since { tidy_error!( bad, - "libsyntax/feature_gate.rs:{}: feature {} is not sorted by since", + "{}:{}: feature {} is not sorted by since", + path.display(), line_number, name, ); @@ -315,7 +322,8 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features *bad = true; tidy_error!( bad, - "libsyntax/feature_gate.rs:{}: no tracking issue for feature {}", + "{}:{}: no tracking issue for feature {}", + path.display(), line_number, name, ); From c9619a4202bd013f1be2776c328937ddd643e7b7 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 24 Aug 2019 17:47:26 +0200 Subject: [PATCH 07/45] Use doc comments for feature gate descriptions This is just in preparation for future usage of these texts. --- src/libsyntax/feature_gate/accepted.rs | 218 +++++++++--------- src/libsyntax/feature_gate/active.rs | 305 +++++++++++++------------ src/libsyntax/feature_gate/removed.rs | 22 +- 3 files changed, 284 insertions(+), 261 deletions(-) diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs index 32a0b76d5f0d8..28e4d2c073c7c 100644 --- a/src/libsyntax/feature_gate/accepted.rs +++ b/src/libsyntax/feature_gate/accepted.rs @@ -3,7 +3,9 @@ use crate::symbol::{Symbol, sym}; macro_rules! declare_features { - ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { + ($( + $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None), + )+) => { /// Those language feature has since been Accepted (it was once Active) pub const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ $((sym::$feature, $ver, $issue, None)),+ @@ -16,11 +18,11 @@ declare_features! ( // feature-group-start: for testing purposes // ------------------------------------------------------------------------- - // A temporary feature gate used to enable parser extensions needed - // to bootstrap fix for #5723. + /// A temporary feature gate used to enable parser extensions needed + /// to bootstrap fix for #5723. (accepted, issue_5723_bootstrap, "1.0.0", None, None), - // These are used to test this portion of the compiler, - // they don't actually mean anything. + /// These are used to test this portion of the compiler, + /// they don't actually mean anything. (accepted, test_accepted_feature, "1.0.0", None, None), // ------------------------------------------------------------------------- @@ -31,203 +33,203 @@ declare_features! ( // feature-group-start: accepted features // ------------------------------------------------------------------------- - // Allows using associated `type`s in `trait`s. + /// Allows using associated `type`s in `trait`s. (accepted, associated_types, "1.0.0", None, None), - // Allows using assigning a default type to type parameters in algebraic data type definitions. + /// Allows using assigning a default type to type parameters in algebraic data type definitions. (accepted, default_type_params, "1.0.0", None, None), // FIXME: explain `globs`. (accepted, globs, "1.0.0", None, None), - // Allows `macro_rules!` items. + /// Allows `macro_rules!` items. (accepted, macro_rules, "1.0.0", None, None), - // Allows use of `&foo[a..b]` as a slicing syntax. + /// Allows use of `&foo[a..b]` as a slicing syntax. (accepted, slicing_syntax, "1.0.0", None, None), - // Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). + /// Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). (accepted, struct_variant, "1.0.0", None, None), - // Allows indexing tuples. + /// Allows indexing tuples. (accepted, tuple_indexing, "1.0.0", None, None), - // Allows the use of `if let` expressions. + /// Allows the use of `if let` expressions. (accepted, if_let, "1.0.0", None, None), - // Allows the use of `while let` expressions. + /// Allows the use of `while let` expressions. (accepted, while_let, "1.0.0", None, None), - // Allows using `#![no_std]`. + /// Allows using `#![no_std]`. (accepted, no_std, "1.6.0", None, None), - // Allows overloading augmented assignment operations like `a += b`. + /// Allows overloading augmented assignment operations like `a += b`. (accepted, augmented_assignments, "1.8.0", Some(28235), None), - // Allows empty structs and enum variants with braces. + /// Allows empty structs and enum variants with braces. (accepted, braced_empty_structs, "1.8.0", Some(29720), None), - // Allows `#[deprecated]` attribute. + /// Allows `#[deprecated]` attribute. (accepted, deprecated, "1.9.0", Some(29935), None), - // Allows macros to appear in the type position. + /// Allows macros to appear in the type position. (accepted, type_macros, "1.13.0", Some(27245), None), - // Allows use of the postfix `?` operator in expressions. + /// Allows use of the postfix `?` operator in expressions. (accepted, question_mark, "1.13.0", Some(31436), None), - // Allows `..` in tuple (struct) patterns. + /// Allows `..` in tuple (struct) patterns. (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), - // Allows some increased flexibility in the name resolution rules, - // especially around globs and shadowing (RFC 1560). + /// Allows some increased flexibility in the name resolution rules, + /// especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120), None), - // Allows using `Self` and associated types in struct expressions and patterns. + /// Allows using `Self` and associated types in struct expressions and patterns. (accepted, more_struct_aliases, "1.16.0", Some(37544), None), - // Allows elision of `'static` lifetimes in `static`s and `const`s. + /// Allows elision of `'static` lifetimes in `static`s and `const`s. (accepted, static_in_const, "1.17.0", Some(35897), None), - // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. + /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. (accepted, field_init_shorthand, "1.17.0", Some(37340), None), - // Allows the definition recursive static items. + /// Allows the definition recursive static items. (accepted, static_recursion, "1.17.0", Some(29719), None), - // Allows `pub(restricted)` visibilities (RFC 1422). + /// Allows `pub(restricted)` visibilities (RFC 1422). (accepted, pub_restricted, "1.18.0", Some(32409), None), - // Allows `#![windows_subsystem]`. + /// Allows `#![windows_subsystem]`. (accepted, windows_subsystem, "1.18.0", Some(37499), None), - // Allows `break {expr}` with a value inside `loop`s. + /// Allows `break {expr}` with a value inside `loop`s. (accepted, loop_break_value, "1.19.0", Some(37339), None), - // Allows numeric fields in struct expressions and patterns. + /// Allows numeric fields in struct expressions and patterns. (accepted, relaxed_adts, "1.19.0", Some(35626), None), - // Allows coercing non capturing closures to function pointers. + /// Allows coercing non capturing closures to function pointers. (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), - // Allows attributes on struct literal fields. + /// Allows attributes on struct literal fields. (accepted, struct_field_attributes, "1.20.0", Some(38814), None), - // Allows the definition of associated constants in `trait` or `impl` blocks. + /// Allows the definition of associated constants in `trait` or `impl` blocks. (accepted, associated_consts, "1.20.0", Some(29646), None), - // Allows usage of the `compile_error!` macro. + /// Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872), None), - // Allows code like `let x: &'static u32 = &42` to work (RFC 1414). + /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414). (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), - // Allows `Drop` types in constants (RFC 1440). + /// Allows `Drop` types in constants (RFC 1440). (accepted, drop_types_in_const, "1.22.0", Some(33156), None), - // Allows the sysV64 ABI to be specified on all platforms - // instead of just the platforms on which it is the C ABI. + /// Allows the sysV64 ABI to be specified on all platforms + /// instead of just the platforms on which it is the C ABI. (accepted, abi_sysv64, "1.24.0", Some(36167), None), - // Allows `repr(align(16))` struct attribute (RFC 1358). + /// Allows `repr(align(16))` struct attribute (RFC 1358). (accepted, repr_align, "1.25.0", Some(33626), None), - // Allows '|' at beginning of match arms (RFC 1925). + /// Allows '|' at beginning of match arms (RFC 1925). (accepted, match_beginning_vert, "1.25.0", Some(44101), None), - // Allows nested groups in `use` items (RFC 2128). + /// Allows nested groups in `use` items (RFC 2128). (accepted, use_nested_groups, "1.25.0", Some(44494), None), - // Allows indexing into constant arrays. + /// Allows indexing into constant arrays. (accepted, const_indexing, "1.26.0", Some(29947), None), - // Allows using `a..=b` and `..=b` as inclusive range syntaxes. + /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), - // Allows `..=` in patterns (RFC 1192). + /// Allows `..=` in patterns (RFC 1192). (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), - // Allows `fn main()` with return types which implements `Termination` (RFC 1937). + /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301), None), - // Allows implementing `Clone` for closures where possible (RFC 2132). + /// Allows implementing `Clone` for closures where possible (RFC 2132). (accepted, clone_closures, "1.26.0", Some(44490), None), - // Allows implementing `Copy` for closures where possible (RFC 2132). + /// Allows implementing `Copy` for closures where possible (RFC 2132). (accepted, copy_closures, "1.26.0", Some(44490), None), - // Allows `impl Trait` in function arguments. + /// Allows `impl Trait` in function arguments. (accepted, universal_impl_trait, "1.26.0", Some(34511), None), - // Allows `impl Trait` in function return types. + /// Allows `impl Trait` in function return types. (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), - // Allows using the `u128` and `i128` types. + /// Allows using the `u128` and `i128` types. (accepted, i128_type, "1.26.0", Some(35118), None), - // Allows default match binding modes (RFC 2005). + /// Allows default match binding modes (RFC 2005). (accepted, match_default_bindings, "1.26.0", Some(42640), None), - // Allows `'_` placeholder lifetimes. + /// Allows `'_` placeholder lifetimes. (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), - // Allows attributes on lifetime/type formal parameters in generics (RFC 1327). + /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). (accepted, generic_param_attrs, "1.27.0", Some(48848), None), - // Allows `cfg(target_feature = "...")`. + /// Allows `cfg(target_feature = "...")`. (accepted, cfg_target_feature, "1.27.0", Some(29717), None), - // Allows `#[target_feature(...)]`. + /// Allows `#[target_feature(...)]`. (accepted, target_feature, "1.27.0", None, None), - // Allows using `dyn Trait` as a syntax for trait objects. + /// Allows using `dyn Trait` as a syntax for trait objects. (accepted, dyn_trait, "1.27.0", Some(44662), None), - // Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). + /// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). (accepted, fn_must_use, "1.27.0", Some(43302), None), - // Allows use of the `:lifetime` macro fragment specifier. + /// Allows use of the `:lifetime` macro fragment specifier. (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), - // Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). + /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). (accepted, termination_trait_test, "1.27.0", Some(48854), None), - // Allows the `#[global_allocator]` attribute. + /// Allows the `#[global_allocator]` attribute. (accepted, global_allocator, "1.28.0", Some(27389), None), - // Allows `#[repr(transparent)]` attribute on newtype structs. + /// Allows `#[repr(transparent)]` attribute on newtype structs. (accepted, repr_transparent, "1.28.0", Some(43036), None), - // Allows procedural macros in `proc-macro` crates. + /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356), None), - // Allows `foo.rs` as an alternative to `foo/mod.rs`. + /// Allows `foo.rs` as an alternative to `foo/mod.rs`. (accepted, non_modrs_mods, "1.30.0", Some(44660), None), - // Allows use of the `:vis` macro fragment specifier + /// Allows use of the `:vis` macro fragment specifier (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), - // Allows importing and reexporting macros with `use`, - // enables macro modularization in general. + /// Allows importing and reexporting macros with `use`, + /// enables macro modularization in general. (accepted, use_extern_macros, "1.30.0", Some(35896), None), - // Allows keywords to be escaped for use as identifiers. + /// Allows keywords to be escaped for use as identifiers. (accepted, raw_identifiers, "1.30.0", Some(48589), None), - // Allows attributes scoped to tools. + /// Allows attributes scoped to tools. (accepted, tool_attributes, "1.30.0", Some(44690), None), - // Allows multi-segment paths in attributes and derives. + /// Allows multi-segment paths in attributes and derives. (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), - // Allows all literals in attribute lists and values of key-value pairs. + /// Allows all literals in attribute lists and values of key-value pairs. (accepted, attr_literals, "1.30.0", Some(34981), None), - // Allows inferring outlives requirements (RFC 2093). + /// Allows inferring outlives requirements (RFC 2093). (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), - // Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. - // This defines the behavior of panics. + /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. + /// This defines the behavior of panics. (accepted, panic_handler, "1.30.0", Some(44489), None), - // Allows `#[used]` to preserve symbols (see llvm.used). + /// Allows `#[used]` to preserve symbols (see llvm.used). (accepted, used, "1.30.0", Some(40289), None), - // Allows `crate` in paths. + /// Allows `crate` in paths. (accepted, crate_in_paths, "1.30.0", Some(45477), None), - // Allows resolving absolute paths as paths from other crates. + /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), - // Allows access to crate names passed via `--extern` through prelude. + /// Allows access to crate names passed via `--extern` through prelude. (accepted, extern_prelude, "1.30.0", Some(44660), None), - // Allows parentheses in patterns. + /// Allows parentheses in patterns. (accepted, pattern_parentheses, "1.31.0", Some(51087), None), - // Allows the definition of `const fn` functions. + /// Allows the definition of `const fn` functions. (accepted, min_const_fn, "1.31.0", Some(53555), None), - // Allows scoped lints. + /// Allows scoped lints. (accepted, tool_lints, "1.31.0", Some(44690), None), - // Allows lifetime elision in `impl` headers. For example: - // + `impl Iterator for &mut Iterator` - // + `impl Debug for Foo<'_>` + /// Allows lifetime elision in `impl` headers. For example: + /// + `impl Iterator for &mut Iterator` + /// + `impl Debug for Foo<'_>` (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), - // Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. + /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), - // Allows use of the `:literal` macro fragment specifier (RFC 1576). + /// Allows use of the `:literal` macro fragment specifier (RFC 1576). (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), - // Allows use of `?` as the Kleene "at most one" operator in macros. + /// Allows use of `?` as the Kleene "at most one" operator in macros. (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), - // Allows `Self` struct constructor (RFC 2302). + /// Allows `Self` struct constructor (RFC 2302). (accepted, self_struct_ctor, "1.32.0", Some(51994), None), - // Allows `Self` in type definitions (RFC 2300). + /// Allows `Self` in type definitions (RFC 2300). (accepted, self_in_typedefs, "1.32.0", Some(49303), None), - // Allows `use x::y;` to search `x` in the current scope. + /// Allows `use x::y;` to search `x` in the current scope. (accepted, uniform_paths, "1.32.0", Some(53130), None), - // Allows integer match exhaustiveness checking (RFC 2591). + /// Allows integer match exhaustiveness checking (RFC 2591). (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), - // Allows `use path as _;` and `extern crate c as _;`. + /// Allows `use path as _;` and `extern crate c as _;`. (accepted, underscore_imports, "1.33.0", Some(48216), None), - // Allows `#[repr(packed(N))]` attribute on structs. + /// Allows `#[repr(packed(N))]` attribute on structs. (accepted, repr_packed, "1.33.0", Some(33158), None), - // Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). + /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), - // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. + /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), - // Allows let bindings, assignments and destructuring in `const` functions and constants. - // As long as control flow is not implemented in const eval, `&&` and `||` may not be used - // at the same time as let bindings. + /// Allows let bindings, assignments and destructuring in `const` functions and constants. + /// As long as control flow is not implemented in const eval, `&&` and `||` may not be used + /// at the same time as let bindings. (accepted, const_let, "1.33.0", Some(48821), None), - // Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. + /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), - // Allows top level or-patterns (`p | q`) in `if let` and `while let`. + /// Allows top level or-patterns (`p | q`) in `if let` and `while let`. (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), - // Allows `cfg(target_vendor = "...")`. + /// Allows `cfg(target_vendor = "...")`. (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), - // Allows `extern crate self as foo;`. - // This puts local crate root into extern prelude under name `foo`. + /// Allows `extern crate self as foo;`. + /// This puts local crate root into extern prelude under name `foo`. (accepted, extern_crate_self, "1.34.0", Some(56409), None), - // Allows arbitrary delimited token streams in non-macro attributes. + /// Allows arbitrary delimited token streams in non-macro attributes. (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), - // Allows paths to enum variants on type aliases including `Self`. + /// Allows paths to enum variants on type aliases including `Self`. (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), - // Allows using `#[repr(align(X))]` on enums with equivalent semantics - // to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. + /// Allows using `#[repr(align(X))]` on enums with equivalent semantics + /// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. (accepted, repr_align_enum, "1.37.0", Some(57996), None), - // Allows `const _: TYPE = VALUE`. + /// Allows `const _: TYPE = VALUE`. (accepted, underscore_const_names, "1.37.0", Some(54912), None), - // Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. + /// Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. (accepted, async_await, "1.39.0", Some(50547), None), // ------------------------------------------------------------------------- diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 0bff4ed24a4ce..4008b79b141eb 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -3,6 +3,7 @@ use crate::edition::Edition; use crate::symbol::{Symbol, sym}; use syntax_pos::Span; +use super::{State, Feature}; macro_rules! set { ($field: ident) => {{ @@ -14,12 +15,24 @@ macro_rules! set { } macro_rules! declare_features { - ($((active, $feature: ident, $ver: expr, $issue: expr, $edition: expr),)+) => { + ($( + $(#[doc = $doc:tt])* (active, $feature:ident, $ver:expr, $issue:expr, $edition:expr), + )+) => { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. pub const ACTIVE_FEATURES: - &[(Symbol, &str, Option, Option, fn(&mut Features, Span))] = - &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+]; + &[Feature] = + &[$( + // (sym::$feature, $ver, $issue, $edition, set!($feature)) + Feature { + state: State::Active { set: set!($feature) }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: $edition, + description: concat!($($doc,)*), + } + ),+]; /// A set of features to be used by later passes. #[derive(Clone)] @@ -28,7 +41,10 @@ macro_rules! declare_features { pub declared_lang_features: Vec<(Symbol, Span, Option)>, /// `#![feature]` attrs for non-language (library) features pub declared_lib_features: Vec<(Symbol, Span)>, - $(pub $feature: bool),+ + $( + $(#[doc = $doc])* + pub $feature: bool + ),+ } impl Features { @@ -58,7 +74,7 @@ macro_rules! declare_features { // stable (active). // // Note that the features are grouped into internal/user-facing and then -// sorted by version inside those groups. This is inforced with tidy. +// sorted by version inside those groups. This is enforced with tidy. // // N.B., `tools/tidy/src/features.rs` parses this information directly out of the // source, so take care when modifying it. @@ -70,127 +86,127 @@ declare_features! ( // no-tracking-issue-start - // Allows using compiler's own crates. + /// Allows using compiler's own crates. (active, rustc_private, "1.0.0", Some(27812), None), - // Allows using the `rust-intrinsic`'s "ABI". + /// Allows using the `rust-intrinsic`'s "ABI". (active, intrinsics, "1.0.0", None, None), - // Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. + /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), - // Allows using the `#[stable]` and `#[unstable]` attributes. + /// Allows using the `#[stable]` and `#[unstable]` attributes. (active, staged_api, "1.0.0", None, None), - // Allows using `#[allow_internal_unstable]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). + /// Allows using `#[allow_internal_unstable]`. This is an + /// attribute on `macro_rules!` and can't use the attribute handling + /// below (it has to be checked before expansion possibly makes + /// macros disappear). (active, allow_internal_unstable, "1.0.0", None, None), - // Allows using `#[allow_internal_unsafe]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). + /// Allows using `#[allow_internal_unsafe]`. This is an + /// attribute on `macro_rules!` and can't use the attribute handling + /// below (it has to be checked before expansion possibly makes + /// macros disappear). (active, allow_internal_unsafe, "1.0.0", None, None), - // Allows using the macros: - // + `__diagnostic_used` - // + `__register_diagnostic` - // +`__build_diagnostic_array` + /// Allows using the macros: + /// + `__diagnostic_used` + /// + `__register_diagnostic` + /// +`__build_diagnostic_array` (active, rustc_diagnostic_macros, "1.0.0", None, None), - // Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which - // lets a function to be `const` when opted into with `#![feature(foo)]`. + /// Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which + /// lets a function to be `const` when opted into with `#![feature(foo)]`. (active, rustc_const_unstable, "1.0.0", None, None), - // no-tracking-issue-end + /// no-tracking-issue-end - // Allows using `#[link_name="llvm.*"]`. + /// Allows using `#[link_name="llvm.*"]`. (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - // Allows using `rustc_*` attributes (RFC 572). + /// Allows using `rustc_*` attributes (RFC 572). (active, rustc_attrs, "1.0.0", Some(29642), None), - // Allows using `#[on_unimplemented(..)]` on traits. + /// Allows using `#[on_unimplemented(..)]` on traits. (active, on_unimplemented, "1.0.0", Some(29628), None), - // Allows using the `box $expr` syntax. + /// Allows using the `box $expr` syntax. (active, box_syntax, "1.0.0", Some(49733), None), - // Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. + /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. (active, main, "1.0.0", Some(29634), None), - // Allows using `#[start]` on a function indicating that it is the program entrypoint. + /// Allows using `#[start]` on a function indicating that it is the program entrypoint. (active, start, "1.0.0", Some(29633), None), - // Allows using the `#[fundamental]` attribute. + /// Allows using the `#[fundamental]` attribute. (active, fundamental, "1.0.0", Some(29635), None), - // Allows using the `rust-call` ABI. + /// Allows using the `rust-call` ABI. (active, unboxed_closures, "1.0.0", Some(29625), None), - // Allows using the `#[linkage = ".."]` attribute. + /// Allows using the `#[linkage = ".."]` attribute. (active, linkage, "1.0.0", Some(29603), None), - // Allows features specific to OIBIT (auto traits). + /// Allows features specific to OIBIT (auto traits). (active, optin_builtin_traits, "1.0.0", Some(13231), None), - // Allows using `box` in patterns (RFC 469). + /// Allows using `box` in patterns (RFC 469). (active, box_patterns, "1.0.0", Some(29641), None), // no-tracking-issue-start - // Allows using `#[prelude_import]` on glob `use` items. + /// Allows using `#[prelude_import]` on glob `use` items. (active, prelude_import, "1.2.0", None, None), // no-tracking-issue-end // no-tracking-issue-start - // Allows using `#[omit_gdb_pretty_printer_section]`. + /// Allows using `#[omit_gdb_pretty_printer_section]`. (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), - // Allows using the `vectorcall` ABI. + /// Allows using the `vectorcall` ABI. (active, abi_vectorcall, "1.7.0", None, None), // no-tracking-issue-end - // Allows using `#[structural_match]` which indicates that a type is structurally matchable. + /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. (active, structural_match, "1.8.0", Some(31434), None), - // Allows using the `may_dangle` attribute (RFC 1327). + /// Allows using the `may_dangle` attribute (RFC 1327). (active, dropck_eyepatch, "1.10.0", Some(34761), None), - // Allows using the `#![panic_runtime]` attribute. + /// Allows using the `#![panic_runtime]` attribute. (active, panic_runtime, "1.10.0", Some(32837), None), - // Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. + /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. (active, needs_panic_runtime, "1.10.0", Some(32837), None), // no-tracking-issue-start - // Allows identifying the `compiler_builtins` crate. + /// Allows identifying the `compiler_builtins` crate. (active, compiler_builtins, "1.13.0", None, None), - // Allows using the `unadjusted` ABI; perma-unstable. + /// Allows using the `unadjusted` ABI; perma-unstable. (active, abi_unadjusted, "1.16.0", None, None), - // Allows identifying crates that contain sanitizer runtimes. + /// Allows identifying crates that contain sanitizer runtimes. (active, sanitizer_runtime, "1.17.0", None, None), - // Used to identify crates that contain the profiler runtime. + /// Used to identify crates that contain the profiler runtime. (active, profiler_runtime, "1.18.0", None, None), - // Allows using the `thiscall` ABI. + /// Allows using the `thiscall` ABI. (active, abi_thiscall, "1.19.0", None, None), - // Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. + /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. (active, allocator_internals, "1.20.0", None, None), // no-tracking-issue-end - // Added for testing E0705; perma-unstable. + /// Added for testing E0705; perma-unstable. (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), // ------------------------------------------------------------------------- @@ -228,281 +244,282 @@ declare_features! ( // feature-group-start: actual feature gates // ------------------------------------------------------------------------- - // Allows using the `#[link_args]` attribute. + /// Allows using the `#[link_args]` attribute. (active, link_args, "1.0.0", Some(29596), None), - // Allows defining identifiers beyond ASCII. + /// Allows defining identifiers beyond ASCII. (active, non_ascii_idents, "1.0.0", Some(55467), None), - // Allows using `#[plugin_registrar]` on functions. + /// Allows using `#[plugin_registrar]` on functions. (active, plugin_registrar, "1.0.0", Some(29597), None), - // Allows using `#![plugin(myplugin)]`. + /// Allows using `#![plugin(myplugin)]`. (active, plugin, "1.0.0", Some(29597), None), - // Allows using `#[thread_local]` on `static` items. + /// Allows using `#[thread_local]` on `static` items. (active, thread_local, "1.0.0", Some(29594), None), - // Allows the use of SIMD types in functions declared in `extern` blocks. + /// Allows the use of SIMD types in functions declared in `extern` blocks. (active, simd_ffi, "1.0.0", Some(27731), None), - // Allows using custom attributes (RFC 572). + /// Allows using custom attributes (RFC 572). (active, custom_attribute, "1.0.0", Some(29642), None), - // Allows using non lexical lifetimes (RFC 2094). + /// Allows using non lexical lifetimes (RFC 2094). (active, nll, "1.0.0", Some(43234), None), - // Allows using slice patterns. + /// Allows using slice patterns. (active, slice_patterns, "1.0.0", Some(62254), None), - // Allows the definition of `const` functions with some advanced features. + /// Allows the definition of `const` functions with some advanced features. (active, const_fn, "1.2.0", Some(57563), None), - // Allows associated type defaults. + /// Allows associated type defaults. (active, associated_type_defaults, "1.2.0", Some(29661), None), - // Allows `#![no_core]`. + /// Allows `#![no_core]`. (active, no_core, "1.3.0", Some(29639), None), - // Allows default type parameters to influence type inference. + /// Allows default type parameters to influence type inference. (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), - // Allows `repr(simd)` and importing the various simd intrinsics. + /// Allows `repr(simd)` and importing the various simd intrinsics. (active, repr_simd, "1.4.0", Some(27731), None), - // Allows `extern "platform-intrinsic" { ... }`. + /// Allows `extern "platform-intrinsic" { ... }`. (active, platform_intrinsics, "1.4.0", Some(27731), None), - // Allows `#[unwind(..)]`. - // - // Permits specifying whether a function should permit unwinding or abort on unwind. + /// Allows `#[unwind(..)]`. + /// + /// Permits specifying whether a function should permit unwinding or abort on unwind. (active, unwind_attributes, "1.4.0", Some(58760), None), - // Allows `#[no_debug]`. + /// Allows `#[no_debug]`. (active, no_debug, "1.5.0", Some(29721), None), - // Allows attributes on expressions and non-item statements. + /// Allows attributes on expressions and non-item statements. (active, stmt_expr_attributes, "1.6.0", Some(15701), None), - // Allows the use of type ascription in expressions. + /// Allows the use of type ascription in expressions. (active, type_ascription, "1.6.0", Some(23416), None), - // Allows `cfg(target_thread_local)`. + /// Allows `cfg(target_thread_local)`. (active, cfg_target_thread_local, "1.7.0", Some(29594), None), - // Allows specialization of implementations (RFC 1210). + /// Allows specialization of implementations (RFC 1210). (active, specialization, "1.7.0", Some(31844), None), - // Allows using `#[naked]` on functions. + /// Allows using `#[naked]` on functions. (active, naked_functions, "1.9.0", Some(32408), None), - // Allows `cfg(target_has_atomic = "...")`. + /// Allows `cfg(target_has_atomic = "...")`. (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - // Allows `X..Y` patterns. + /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - // Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. + /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. (active, never_type, "1.13.0", Some(35121), None), - // Allows exhaustive pattern matching on types that contain uninhabited types. + /// Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", Some(51085), None), - // Allows untagged unions `union U { ... }`. + /// Allows untagged unions `union U { ... }`. (active, untagged_unions, "1.13.0", Some(32836), None), - // Allows `#[link(..., cfg(..))]`. + /// Allows `#[link(..., cfg(..))]`. (active, link_cfg, "1.14.0", Some(37406), None), - // Allows `extern "ptx-*" fn()`. + /// Allows `extern "ptx-*" fn()`. (active, abi_ptx, "1.15.0", Some(38788), None), - // Allows the `#[repr(i128)]` attribute for enums. + /// Allows the `#[repr(i128)]` attribute for enums. (active, repr128, "1.16.0", Some(35118), None), - // Allows `#[link(kind="static-nobundle"...)]`. + /// Allows `#[link(kind="static-nobundle"...)]`. (active, static_nobundle, "1.16.0", Some(37403), None), - // Allows `extern "msp430-interrupt" fn()`. + /// Allows `extern "msp430-interrupt" fn()`. (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), - // Allows declarative macros 2.0 (`macro`). + /// Allows declarative macros 2.0 (`macro`). (active, decl_macro, "1.17.0", Some(39412), None), - // Allows `extern "x86-interrupt" fn()`. + /// Allows `extern "x86-interrupt" fn()`. (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - // Allows overlapping impls of marker traits. + /// Allows overlapping impls of marker traits. (active, overlapping_marker_traits, "1.18.0", Some(29864), None), - // Allows a test to fail without failing the whole suite. + /// Allows a test to fail without failing the whole suite. (active, allow_fail, "1.19.0", Some(46488), None), - // Allows unsized tuple coercion. + /// Allows unsized tuple coercion. (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - // Allows defining generators. + /// Allows defining generators. (active, generators, "1.21.0", Some(43122), None), - // Allows `#[doc(cfg(...))]`. + /// Allows `#[doc(cfg(...))]`. (active, doc_cfg, "1.21.0", Some(43781), None), - // Allows `#[doc(masked)]`. + /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), - // Allows `#[doc(spotlight)]`. + /// Allows `#[doc(spotlight)]`. (active, doc_spotlight, "1.22.0", Some(45040), None), - // Allows `#[doc(include = "some-file")]`. + /// Allows `#[doc(include = "some-file")]`. (active, external_doc, "1.22.0", Some(44732), None), - // Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). + /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). (active, non_exhaustive, "1.22.0", Some(44109), None), - // Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. + /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. (active, crate_visibility_modifier, "1.23.0", Some(53120), None), - // Allows defining `extern type`s. + /// Allows defining `extern type`s. (active, extern_types, "1.23.0", Some(43467), None), - // Allows trait methods with arbitrary self types. + /// Allows trait methods with arbitrary self types. (active, arbitrary_self_types, "1.23.0", Some(44874), None), - // Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). + /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). (active, in_band_lifetimes, "1.23.0", Some(44524), None), - // Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). + /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). (active, generic_associated_types, "1.23.0", Some(44265), None), - // Allows defining `trait X = A + B;` alias items. + /// Allows defining `trait X = A + B;` alias items. (active, trait_alias, "1.24.0", Some(41517), None), - // Allows infering `'static` outlives requirements (RFC 2093). + /// Allows infering `'static` outlives requirements (RFC 2093). (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), - // Allows macro invocations in `extern {}` blocks. + /// Allows macro invocations in `extern {}` blocks. (active, macros_in_extern, "1.27.0", Some(49476), None), - // Allows accessing fields of unions inside `const` functions. + /// Allows accessing fields of unions inside `const` functions. (active, const_fn_union, "1.27.0", Some(51909), None), - // Allows casting raw pointers to `usize` during const eval. + /// Allows casting raw pointers to `usize` during const eval. (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), - // Allows dereferencing raw pointers during const eval. + /// Allows dereferencing raw pointers during const eval. (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - // Allows comparing raw pointers during const eval. + /// Allows comparing raw pointers during const eval. (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), - // Allows `#[doc(alias = "...")]`. + /// Allows `#[doc(alias = "...")]`. (active, doc_alias, "1.27.0", Some(50146), None), - // Allows inconsistent bounds in where clauses. + /// Allows inconsistent bounds in where clauses. (active, trivial_bounds, "1.28.0", Some(48214), None), - // Allows `'a: { break 'a; }`. + /// Allows `'a: { break 'a; }`. (active, label_break_value, "1.28.0", Some(48594), None), - // Allows using `#[doc(keyword = "...")]`. + /// Allows using `#[doc(keyword = "...")]`. (active, doc_keyword, "1.28.0", Some(51315), None), - // Allows reinterpretation of the bits of a value of one type as another type during const eval. + /// Allows reinterpretation of the bits of a value of one type as another + /// type during const eval. (active, const_transmute, "1.29.0", Some(53605), None), - // Allows using `try {...}` expressions. + /// Allows using `try {...}` expressions. (active, try_blocks, "1.29.0", Some(31436), None), - // Allows defining an `#[alloc_error_handler]`. + /// Allows defining an `#[alloc_error_handler]`. (active, alloc_error_handler, "1.29.0", Some(51540), None), - // Allows using the `amdgpu-kernel` ABI. + /// Allows using the `amdgpu-kernel` ABI. (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - // Allows panicking during const eval (producing compile-time errors). + /// Allows panicking during const eval (producing compile-time errors). (active, const_panic, "1.30.0", Some(51999), None), - // Allows `#[marker]` on certain traits allowing overlapping implementations. + /// Allows `#[marker]` on certain traits allowing overlapping implementations. (active, marker_trait_attr, "1.30.0", Some(29864), None), - // Allows macro invocations on modules expressions and statements and - // procedural macros to expand to non-items. + /// Allows macro invocations on modules expressions and statements and + /// procedural macros to expand to non-items. (active, proc_macro_hygiene, "1.30.0", Some(54727), None), - // Allows unsized rvalues at arguments and parameters. + /// Allows unsized rvalues at arguments and parameters. (active, unsized_locals, "1.30.0", Some(48055), None), - // Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. + /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. (active, custom_test_frameworks, "1.30.0", Some(50297), None), - // Allows non-builtin attributes in inner attribute position. + /// Allows non-builtin attributes in inner attribute position. (active, custom_inner_attributes, "1.30.0", Some(54726), None), - // Allows mixing bind-by-move in patterns and references to those identifiers in guards. + /// Allows mixing bind-by-move in patterns and references to those identifiers in guards. (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), - // Allows `impl Trait` in bindings (`let`, `const`, `static`). + /// Allows `impl Trait` in bindings (`let`, `const`, `static`). (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), - // Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. + /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. (active, lint_reasons, "1.31.0", Some(54503), None), - // Allows exhaustive integer pattern matching on `usize` and `isize`. + /// Allows exhaustive integer pattern matching on `usize` and `isize`. (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), - // Allows relaxing the coherence rules such that - // `impl ForeignTrait for ForeignType is permitted. + /// Allows relaxing the coherence rules such that + /// `impl ForeignTrait for ForeignType is permitted. (active, re_rebalance_coherence, "1.32.0", Some(55437), None), - // Allows using `#[ffi_returns_twice]` on foreign functions. + /// Allows using `#[ffi_returns_twice]` on foreign functions. (active, ffi_returns_twice, "1.34.0", Some(58314), None), - // Allows const generic types (e.g. `struct Foo(...);`). + /// Allows const generic types (e.g. `struct Foo(...);`). (active, const_generics, "1.34.0", Some(44580), None), - // Allows using `#[optimize(X)]`. + /// Allows using `#[optimize(X)]`. (active, optimize_attribute, "1.34.0", Some(54882), None), - // Allows using C-variadics. + /// Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), - // Allows the user of associated type bounds. + /// Allows the user of associated type bounds. (active, associated_type_bounds, "1.34.0", Some(52662), None), - // Attributes on formal function params. + /// Attributes on formal function params. (active, param_attrs, "1.36.0", Some(60406), None), - // Allows calling constructor functions in `const fn`. + /// Allows calling constructor functions in `const fn`. (active, const_constructor, "1.37.0", Some(61456), None), - // Allows `if/while p && let q = r && ...` chains. + /// Allows `if/while p && let q = r && ...` chains. (active, let_chains, "1.37.0", Some(53667), None), - // Allows #[repr(transparent)] on enums (RFC 2645). + /// Allows #[repr(transparent)] on enums (RFC 2645). (active, transparent_enums, "1.37.0", Some(60405), None), - // Allows #[repr(transparent)] on unions (RFC 2645). + /// Allows #[repr(transparent)] on unions (RFC 2645). (active, transparent_unions, "1.37.0", Some(60405), None), - // Allows explicit discriminants on non-unit enum variants. + /// Allows explicit discriminants on non-unit enum variants. (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), - // Allows `impl Trait` with multiple unrelated lifetimes. + /// Allows `impl Trait` with multiple unrelated lifetimes. (active, member_constraints, "1.37.0", Some(61977), None), - // Allows `async || body` closures. + /// Allows `async || body` closures. (active, async_closure, "1.37.0", Some(62290), None), - // Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests + /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests (active, cfg_doctest, "1.37.0", Some(62210), None), - // Allows `[x; N]` where `x` is a constant (RFC 2203). + /// Allows `[x; N]` where `x` is a constant (RFC 2203). (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), - // Allows `impl Trait` to be used inside type aliases (RFC 2515). + /// Allows `impl Trait` to be used inside type aliases (RFC 2515). (active, type_alias_impl_trait, "1.38.0", Some(63063), None), - // Allows the use of or-patterns, e.g. `0 | 1`. + /// Allows the use of or-patterns, e.g. `0 | 1`. (active, or_patterns, "1.38.0", Some(54883), None), // ------------------------------------------------------------------------- diff --git a/src/libsyntax/feature_gate/removed.rs b/src/libsyntax/feature_gate/removed.rs index 6ebfeb29f677b..6494c82e1228b 100644 --- a/src/libsyntax/feature_gate/removed.rs +++ b/src/libsyntax/feature_gate/removed.rs @@ -3,14 +3,18 @@ use crate::symbol::{Symbol, sym}; macro_rules! declare_features { - ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { + ($( + $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), + )+) => { /// Represents unstable features which have since been removed (it was once Active) pub const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ $((sym::$feature, $ver, $issue, $reason)),+ ]; }; - ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { + ($( + $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None), + )+) => { /// Represents stable features which have since been removed (it was once Accepted) pub const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ $((sym::$feature, $ver, $issue, None)),+ @@ -25,17 +29,17 @@ declare_features! ( (removed, import_shadowing, "1.0.0", None, None, None), (removed, managed_boxes, "1.0.0", None, None, None), - // Allows use of unary negate on unsigned integers, e.g., -e for e: u8 + /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 (removed, negate_unsigned, "1.0.0", Some(29645), None, None), (removed, reflect, "1.0.0", Some(27749), None, None), - // A way to temporarily opt out of opt in copy. This will *never* be accepted. + /// A way to temporarily opt out of opt in copy. This will *never* be accepted. (removed, opt_out_copy, "1.0.0", None, None, None), (removed, quad_precision_float, "1.0.0", None, None, None), (removed, struct_inherit, "1.0.0", None, None, None), (removed, test_removed_feature, "1.0.0", None, None, None), (removed, visible_private_types, "1.0.0", None, None, None), (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), - // Allows using items which are missing stability attributes + /// Allows using items which are missing stability attributes (removed, unmarked_api, "1.0.0", None, None, None), (removed, allocator, "1.0.0", None, None, None), (removed, simd, "1.0.0", Some(27731), None, @@ -57,18 +61,18 @@ declare_features! ( Some("subsumed by `#![feature(proc_macro_hygiene)]`")), (removed, panic_implementation, "1.28.0", Some(44489), None, Some("subsumed by `#[panic_handler]`")), - // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. + /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. (removed, custom_derive, "1.32.0", Some(29644), None, Some("subsumed by `#[proc_macro_derive]`")), - // Paths of the form: `extern::foo::bar` + /// Paths of the form: `extern::foo::bar` (removed, extern_in_paths, "1.33.0", Some(55600), None, Some("subsumed by `::foo::bar` paths")), (removed, quote, "1.33.0", Some(29601), None, None), - // Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). + /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), (removed, await_macro, "1.38.0", Some(50547), None, Some("subsumed by `.await` syntax")), - // Allows defining `existential type`s. + /// Allows defining `existential type`s. (removed, existential_type, "1.38.0", Some(63063), None, Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), From 5299d8a191246cf55c8ead7b8be68c8aeca78d35 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 15:28:14 +0200 Subject: [PATCH 08/45] parser: extract `ban_unexpected_or_or`. --- src/libsyntax/parse/parser/pat.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 8cfa6abbe6270..4cda14907e46c 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -31,14 +31,7 @@ impl<'a> Parser<'a> { pats.push(self.parse_top_level_pat()?); if self.token == token::OrOr { - self.struct_span_err(self.token.span, "unexpected token `||` after pattern") - .span_suggestion( - self.token.span, - "use a single `|` to specify multiple patterns", - "|".to_owned(), - Applicability::MachineApplicable - ) - .emit(); + self.ban_unexpected_or_or(); self.bump(); } else if self.eat(&token::BinOp(token::Or)) { // This is a No-op. Continue the loop to parse the next @@ -49,6 +42,17 @@ impl<'a> Parser<'a> { }; } + fn ban_unexpected_or_or(&mut self) { + self.struct_span_err(self.token.span, "unexpected token `||` after pattern") + .span_suggestion( + self.token.span, + "use a single `|` to specify multiple patterns", + "|".to_owned(), + Applicability::MachineApplicable + ) + .emit(); + } + /// A wrapper around `parse_pat` with some special error handling for the /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast /// to subpatterns within such). @@ -116,9 +120,7 @@ impl<'a> Parser<'a> { let mut pats = vec![first_pat]; while self.eat(&token::BinOp(token::Or)) { - pats.push(self.parse_pat_with_range_pat( - true, expected - )?); + pats.push(self.parse_pat_with_range_pat(true, expected)?); } let or_pattern_span = lo.to(self.prev_span); From 1ba7550a8996cffc07c6af89dcd6e1cdc63b24cf Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 15:31:34 +0200 Subject: [PATCH 09/45] parser: type alias `type Expected = Option<&'static str>;`. --- src/libsyntax/parse/parser/pat.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 4cda14907e46c..36d5ed5c4aa64 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -12,12 +12,11 @@ use crate::ThinVec; use errors::{Applicability, DiagnosticBuilder}; +type Expected = Option<&'static str>; + impl<'a> Parser<'a> { /// Parses a pattern. - pub fn parse_pat( - &mut self, - expected: Option<&'static str> - ) -> PResult<'a, P> { + pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P> { self.parse_pat_with_range_pat(true, expected) } @@ -105,7 +104,7 @@ impl<'a> Parser<'a> { } /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). - fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P> { + fn parse_pat_with_or(&mut self, expected: Expected) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; @@ -135,7 +134,7 @@ impl<'a> Parser<'a> { fn parse_pat_with_range_pat( &mut self, allow_range_pat: bool, - expected: Option<&'static str>, + expected: Expected, ) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole!(self, NtPat, |x| x); @@ -257,7 +256,7 @@ impl<'a> Parser<'a> { } /// Parse `&pat` / `&mut pat`. - fn parse_pat_deref(&mut self, expected: Option<&'static str>) -> PResult<'a, PatKind> { + fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> { self.expect_and()?; let mutbl = self.parse_mutability(); @@ -363,7 +362,7 @@ impl<'a> Parser<'a> { fn fatal_unexpected_non_pat( &mut self, mut err: DiagnosticBuilder<'a>, - expected: Option<&'static str>, + expected: Expected, ) -> PResult<'a, P> { self.cancel(&mut err); From 0bbea47794d28f78cf313fde475a35a83d0e9842 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 15:45:44 +0200 Subject: [PATCH 10/45] parser: refactor `parse_pat_with_or` + use it in [p0, p1, ..] pats. --- src/libsyntax/parse/parser/pat.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 36d5ed5c4aa64..ca5a9f2a5a882 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -104,12 +104,12 @@ impl<'a> Parser<'a> { } /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). - fn parse_pat_with_or(&mut self, expected: Expected) -> PResult<'a, P> { + fn parse_pat_with_or(&mut self, expected: Expected, gate_or: bool) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; - // If the next token is not a `|`, this is not an or-pattern and - // we should exit here. + // If the next token is not a `|`, + // this is not an or-pattern and we should exit here. if !self.check(&token::BinOp(token::Or)) { return Ok(first_pat) } @@ -124,7 +124,10 @@ impl<'a> Parser<'a> { let or_pattern_span = lo.to(self.prev_span); - self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); + // Feature gate the or-pattern if instructed: + if gate_or { + self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); + } Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } @@ -145,7 +148,11 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Paren) => self.parse_pat_tuple_or_parens()?, token::OpenDelim(token::Bracket) => { // Parse `[pat, pat,...]` as a slice pattern. - PatKind::Slice(self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?.0) + let (pats, _) = self.parse_delim_comma_seq( + token::Bracket, + |p| p.parse_pat_with_or(None, true), + )?; + PatKind::Slice(pats) } token::DotDot => { self.bump(); @@ -273,7 +280,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or(None) + p.parse_pat_with_or(None, true) })?; // Here, `(pat,)` is a tuple pattern. @@ -517,7 +524,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true))?; Ok(PatKind::TupleStruct(path, fields)) } @@ -661,7 +668,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or(None)?; + let pat = self.parse_pat_with_or(None, true)?; hi = pat.span; (pat, fieldname, false) } else { From 30b841dce0a1c0f26588f4b5791a9eda1c1f42f4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 16:35:19 +0200 Subject: [PATCH 11/45] parser: improve or-patterns recovery. --- src/libsyntax/parse/parser/pat.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index ca5a9f2a5a882..e52d0bc9d483b 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -110,18 +110,25 @@ impl<'a> Parser<'a> { // If the next token is not a `|`, // this is not an or-pattern and we should exit here. - if !self.check(&token::BinOp(token::Or)) { + if !self.check(&token::BinOp(token::Or)) && self.token != token::OrOr { return Ok(first_pat) } let lo = first_pat.span; - let mut pats = vec![first_pat]; + loop { + if self.token == token::OrOr { + // Found `||`; Recover and pretend we parsed `|`. + self.ban_unexpected_or_or(); + self.bump(); + } else if self.eat(&token::BinOp(token::Or)) { + // Found `|`. Working towards a proper or-pattern. + } else { + break; + } - while self.eat(&token::BinOp(token::Or)) { pats.push(self.parse_pat_with_range_pat(true, expected)?); } - let or_pattern_span = lo.to(self.prev_span); // Feature gate the or-pattern if instructed: From d34ee769b061975bf637776052179058c1f00bd7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 16:45:08 +0200 Subject: [PATCH 12/45] parser: move `multiple-pattern-typo` -> `or-patterns` directory. --- .../ui/{did_you_mean => or-patterns}/multiple-pattern-typo.rs | 0 .../ui/{did_you_mean => or-patterns}/multiple-pattern-typo.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{did_you_mean => or-patterns}/multiple-pattern-typo.rs (100%) rename src/test/ui/{did_you_mean => or-patterns}/multiple-pattern-typo.stderr (100%) diff --git a/src/test/ui/did_you_mean/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs similarity index 100% rename from src/test/ui/did_you_mean/multiple-pattern-typo.rs rename to src/test/ui/or-patterns/multiple-pattern-typo.rs diff --git a/src/test/ui/did_you_mean/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr similarity index 100% rename from src/test/ui/did_you_mean/multiple-pattern-typo.stderr rename to src/test/ui/or-patterns/multiple-pattern-typo.stderr From 5f57feec0a3038ffc085ba897717b4ffd75445ee Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 16:52:49 +0200 Subject: [PATCH 13/45] parser: `multiple-pattern-typo`: cover more or-pattern places. --- .../ui/or-patterns/multiple-pattern-typo.rs | 33 +++++++++++++++ .../or-patterns/multiple-pattern-typo.stderr | 42 ++++++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs index 14ad33d53b08c..5d1da56674ba4 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.rs +++ b/src/test/ui/or-patterns/multiple-pattern-typo.rs @@ -1,7 +1,40 @@ +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash + fn main() { let x = 3; + match x { 1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern _ => (), } + + match x { + (1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + match (x,) { + (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + struct TS(u8); + + match TS(x) { + TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + struct NS { f: u8 } + + match (NS { f: x }) { + NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + match [x] { + [1 | 2 || 3] => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } } diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index a29fa584b2924..97f3470a54aa2 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -1,8 +1,46 @@ error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:4:15 + --> $DIR/multiple-pattern-typo.rs:8:15 | LL | 1 | 2 || 3 => (), | ^^ help: use a single `|` to specify multiple patterns: `|` -error: aborting due to previous error +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:13:16 + | +LL | (1 | 2 || 3) => (), + | ^^ help: use a single `|` to specify multiple patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:18:16 + | +LL | (1 | 2 || 3,) => (), + | ^^ help: use a single `|` to specify multiple patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:25:18 + | +LL | TS(1 | 2 || 3) => (), + | ^^ help: use a single `|` to specify multiple patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:32:23 + | +LL | NS { f: 1 | 2 || 3 } => (), + | ^^ help: use a single `|` to specify multiple patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:37:16 + | +LL | [1 | 2 || 3] => (), + | ^^ help: use a single `|` to specify multiple patterns: `|` + +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/multiple-pattern-typo.rs:1:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 6 previous errors From f852c7ce1c6f55bc816d90c6e7f8e9205bb6c6f2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 16:55:52 +0200 Subject: [PATCH 14/45] parser: simplify `parse_pat_with_or`. --- src/libsyntax/parse/parser/pat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index e52d0bc9d483b..89688a287a7f3 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -127,7 +127,7 @@ impl<'a> Parser<'a> { break; } - pats.push(self.parse_pat_with_range_pat(true, expected)?); + pats.push(self.parse_pat(expected)?); } let or_pattern_span = lo.to(self.prev_span); From 21d9b85c0da1b639f8d8b3585e08759f96d1c286 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 17:11:12 +0200 Subject: [PATCH 15/45] parser: extract `maybe_recover_unexpected_comma`. --- src/libsyntax/parse/parser/pat.rs | 67 +++++++++++++++++-------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 89688a287a7f3..588e5aef8a2f4 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -57,40 +57,45 @@ impl<'a> Parser<'a> { /// to subpatterns within such). pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { let pat = self.parse_pat(None)?; - if self.token == token::Comma { - // An unexpected comma after a top-level pattern is a clue that the - // user (perhaps more accustomed to some other language) forgot the - // parentheses in what should have been a tuple pattern; return a - // suggestion-enhanced error here rather than choking on the comma - // later. - let comma_span = self.token.span; - self.bump(); - if let Err(mut err) = self.skip_pat_list() { - // We didn't expect this to work anyway; we just wanted - // to advance to the end of the comma-sequence so we know - // the span to suggest parenthesizing - err.cancel(); - } - let seq_span = pat.span.to(self.prev_span); - let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - err.span_suggestion( - seq_span, - "try adding parentheses to match on a tuple..", - format!("({})", seq_snippet), - Applicability::MachineApplicable - ).span_suggestion( - seq_span, - "..or a vertical bar to match on multiple alternatives", - format!("{}", seq_snippet.replace(",", " |")), - Applicability::MachineApplicable - ); - } - return Err(err); - } + self.maybe_recover_unexpected_comma(pat.span)?; Ok(pat) } + fn maybe_recover_unexpected_comma(&mut self, lo: Span) -> PResult<'a, ()> { + if self.token != token::Comma { + return Ok(()); + } + + // An unexpected comma after a top-level pattern is a clue that the + // user (perhaps more accustomed to some other language) forgot the + // parentheses in what should have been a tuple pattern; return a + // suggestion-enhanced error here rather than choking on the comma later. + let comma_span = self.token.span; + self.bump(); + if let Err(mut err) = self.skip_pat_list() { + // We didn't expect this to work anyway; we just wanted to advance to the + // end of the comma-sequence so we know the span to suggest parenthesizing. + err.cancel(); + } + let seq_span = lo.to(self.prev_span); + let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + err.span_suggestion( + seq_span, + "try adding parentheses to match on a tuple..", + format!("({})", seq_snippet), + Applicability::MachineApplicable + ) + .span_suggestion( + seq_span, + "..or a vertical bar to match on multiple alternatives", + format!("{}", seq_snippet.replace(",", " |")), + Applicability::MachineApplicable + ); + } + Err(err) + } + /// Parse and throw away a parentesized comma separated /// sequence of patterns until `)` is reached. fn skip_pat_list(&mut self) -> PResult<'a, ()> { From a4a34ab62df777e885cac71ab171225b2cd1a812 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 17:44:27 +0200 Subject: [PATCH 16/45] parser: integrate `maybe_recover_unexpected_comma` in `parse_pat_with_or`. --- src/libsyntax/parse/parser/pat.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 588e5aef8a2f4..b2a026d0071e4 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -57,12 +57,12 @@ impl<'a> Parser<'a> { /// to subpatterns within such). pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { let pat = self.parse_pat(None)?; - self.maybe_recover_unexpected_comma(pat.span)?; + self.maybe_recover_unexpected_comma(pat.span, true)?; Ok(pat) } - fn maybe_recover_unexpected_comma(&mut self, lo: Span) -> PResult<'a, ()> { - if self.token != token::Comma { + fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: bool) -> PResult<'a, ()> { + if !top_level || self.token != token::Comma { return Ok(()); } @@ -109,9 +109,15 @@ impl<'a> Parser<'a> { } /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). - fn parse_pat_with_or(&mut self, expected: Expected, gate_or: bool) -> PResult<'a, P> { + fn parse_pat_with_or( + &mut self, + expected: Expected, + gate_or: bool, + top_level: bool + ) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; + self.maybe_recover_unexpected_comma(first_pat.span, top_level)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -132,7 +138,9 @@ impl<'a> Parser<'a> { break; } - pats.push(self.parse_pat(expected)?); + let pat = self.parse_pat(expected)?; + self.maybe_recover_unexpected_comma(pat.span, top_level)?; + pats.push(pat); } let or_pattern_span = lo.to(self.prev_span); @@ -162,7 +170,7 @@ impl<'a> Parser<'a> { // Parse `[pat, pat,...]` as a slice pattern. let (pats, _) = self.parse_delim_comma_seq( token::Bracket, - |p| p.parse_pat_with_or(None, true), + |p| p.parse_pat_with_or(None, true, false), )?; PatKind::Slice(pats) } @@ -292,7 +300,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or(None, true) + p.parse_pat_with_or(None, true, false) })?; // Here, `(pat,)` is a tuple pattern. @@ -536,7 +544,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true, false))?; Ok(PatKind::TupleStruct(path, fields)) } @@ -680,7 +688,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or(None, true)?; + let pat = self.parse_pat_with_or(None, true, false)?; hi = pat.span; (pat, fieldname, false) } else { From 7b59b4f14dae8c859718d60794021230e1e3ac29 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:13:19 +0200 Subject: [PATCH 17/45] parser: extract `eat_or_separator`. --- src/libsyntax/parse/parser/pat.rs | 58 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index b2a026d0071e4..3af64cef74f26 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -29,27 +29,10 @@ impl<'a> Parser<'a> { loop { pats.push(self.parse_top_level_pat()?); - if self.token == token::OrOr { - self.ban_unexpected_or_or(); - self.bump(); - } else if self.eat(&token::BinOp(token::Or)) { - // This is a No-op. Continue the loop to parse the next - // pattern. - } else { + if !self.eat_or_separator() { return Ok(pats); } - }; - } - - fn ban_unexpected_or_or(&mut self) { - self.struct_span_err(self.token.span, "unexpected token `||` after pattern") - .span_suggestion( - self.token.span, - "use a single `|` to specify multiple patterns", - "|".to_owned(), - Applicability::MachineApplicable - ) - .emit(); + } } /// A wrapper around `parse_pat` with some special error handling for the @@ -127,17 +110,7 @@ impl<'a> Parser<'a> { let lo = first_pat.span; let mut pats = vec![first_pat]; - loop { - if self.token == token::OrOr { - // Found `||`; Recover and pretend we parsed `|`. - self.ban_unexpected_or_or(); - self.bump(); - } else if self.eat(&token::BinOp(token::Or)) { - // Found `|`. Working towards a proper or-pattern. - } else { - break; - } - + while self.eat_or_separator() { let pat = self.parse_pat(expected)?; self.maybe_recover_unexpected_comma(pat.span, top_level)?; pats.push(pat); @@ -152,6 +125,31 @@ impl<'a> Parser<'a> { Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } + /// Eat the or-pattern `|` separator. + /// If instead a `||` token is encountered, recover and pretend we parsed `|`. + fn eat_or_separator(&mut self) -> bool { + match self.token.kind { + token::OrOr => { + // Found `||`; Recover and pretend we parsed `|`. + self.ban_unexpected_or_or(); + self.bump(); + true + } + _ => self.eat(&token::BinOp(token::Or)), + } + } + + fn ban_unexpected_or_or(&mut self) { + self.struct_span_err(self.token.span, "unexpected token `||` after pattern") + .span_suggestion( + self.token.span, + "use a single `|` to specify multiple patterns", + "|".to_owned(), + Applicability::MachineApplicable + ) + .emit(); + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( From dc5bbaf7b2df8dc2be6c0f1a9973867e5519300b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:15:17 +0200 Subject: [PATCH 18/45] parser: improve `parse_pat_with_or` docs. --- src/libsyntax/parse/parser/pat.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 3af64cef74f26..14ac509d6f706 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -91,7 +91,8 @@ impl<'a> Parser<'a> { Ok(()) } - /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). + /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). + /// Corresponds to `pat` in RFC 2535. fn parse_pat_with_or( &mut self, expected: Expected, From 6498959377421876040515af39b6491a2ec2a0c5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:34:35 +0200 Subject: [PATCH 19/45] parser: use `eat_or_separator` for leading vert. --- src/libsyntax/parse/parser/pat.rs | 4 ++-- src/test/ui/or-patterns/multiple-pattern-typo.rs | 5 +++++ src/test/ui/or-patterns/multiple-pattern-typo.stderr | 8 +++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 14ac509d6f706..1063e34753095 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -22,8 +22,8 @@ impl<'a> Parser<'a> { /// Parses patterns, separated by '|' s. pub(super) fn parse_pats(&mut self) -> PResult<'a, Vec>> { - // Allow a '|' before the pats (RFC 1925 + RFC 2530) - self.eat(&token::BinOp(token::Or)); + // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). + self.eat_or_separator(); let mut pats = Vec::new(); loop { diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs index 5d1da56674ba4..e308c0adb4eb8 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.rs +++ b/src/test/ui/or-patterns/multiple-pattern-typo.rs @@ -37,4 +37,9 @@ fn main() { [1 | 2 || 3] => (), //~ ERROR unexpected token `||` after pattern _ => (), } + + match x { + || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } } diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index 97f3470a54aa2..765c7879b12ca 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -34,6 +34,12 @@ error: unexpected token `||` after pattern LL | [1 | 2 || 3] => (), | ^^ help: use a single `|` to specify multiple patterns: `|` +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:42:9 + | +LL | || 1 | 2 | 3 => (), + | ^^ help: use a single `|` to specify multiple patterns: `|` + warning: the feature `or_patterns` is incomplete and may cause the compiler to crash --> $DIR/multiple-pattern-typo.rs:1:12 | @@ -42,5 +48,5 @@ LL | #![feature(or_patterns)] | = note: `#[warn(incomplete_features)]` on by default -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors From 39f5e5bec42a4c05588db45d12ab9aafc01776aa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:37:41 +0200 Subject: [PATCH 20/45] parser: move `maybe_recover_unexpected_comma` to a more appropriate place. --- src/libsyntax/parse/parser/pat.rs | 99 +++++++++++++++---------------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 1063e34753095..680a587205686 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -35,62 +35,12 @@ impl<'a> Parser<'a> { } } - /// A wrapper around `parse_pat` with some special error handling for the - /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast - /// to subpatterns within such). pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { let pat = self.parse_pat(None)?; self.maybe_recover_unexpected_comma(pat.span, true)?; Ok(pat) } - fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: bool) -> PResult<'a, ()> { - if !top_level || self.token != token::Comma { - return Ok(()); - } - - // An unexpected comma after a top-level pattern is a clue that the - // user (perhaps more accustomed to some other language) forgot the - // parentheses in what should have been a tuple pattern; return a - // suggestion-enhanced error here rather than choking on the comma later. - let comma_span = self.token.span; - self.bump(); - if let Err(mut err) = self.skip_pat_list() { - // We didn't expect this to work anyway; we just wanted to advance to the - // end of the comma-sequence so we know the span to suggest parenthesizing. - err.cancel(); - } - let seq_span = lo.to(self.prev_span); - let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - err.span_suggestion( - seq_span, - "try adding parentheses to match on a tuple..", - format!("({})", seq_snippet), - Applicability::MachineApplicable - ) - .span_suggestion( - seq_span, - "..or a vertical bar to match on multiple alternatives", - format!("{}", seq_snippet.replace(",", " |")), - Applicability::MachineApplicable - ); - } - Err(err) - } - - /// Parse and throw away a parentesized comma separated - /// sequence of patterns until `)` is reached. - fn skip_pat_list(&mut self) -> PResult<'a, ()> { - while !self.check(&token::CloseDelim(token::Paren)) { - self.parse_pat(None)?; - if !self.eat(&token::Comma) { - return Ok(()) - } - } - Ok(()) - } - /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). /// Corresponds to `pat` in RFC 2535. fn parse_pat_with_or( @@ -151,6 +101,55 @@ impl<'a> Parser<'a> { .emit(); } + /// Some special error handling for the "top-level" patterns in a match arm, + /// `for` loop, `let`, &c. (in contrast to subpatterns within such). + fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: bool) -> PResult<'a, ()> { + if !top_level || self.token != token::Comma { + return Ok(()); + } + + // An unexpected comma after a top-level pattern is a clue that the + // user (perhaps more accustomed to some other language) forgot the + // parentheses in what should have been a tuple pattern; return a + // suggestion-enhanced error here rather than choking on the comma later. + let comma_span = self.token.span; + self.bump(); + if let Err(mut err) = self.skip_pat_list() { + // We didn't expect this to work anyway; we just wanted to advance to the + // end of the comma-sequence so we know the span to suggest parenthesizing. + err.cancel(); + } + let seq_span = lo.to(self.prev_span); + let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + err.span_suggestion( + seq_span, + "try adding parentheses to match on a tuple..", + format!("({})", seq_snippet), + Applicability::MachineApplicable + ) + .span_suggestion( + seq_span, + "..or a vertical bar to match on multiple alternatives", + format!("{}", seq_snippet.replace(",", " |")), + Applicability::MachineApplicable + ); + } + Err(err) + } + + /// Parse and throw away a parentesized comma separated + /// sequence of patterns until `)` is reached. + fn skip_pat_list(&mut self) -> PResult<'a, ()> { + while !self.check(&token::CloseDelim(token::Paren)) { + self.parse_pat(None)?; + if !self.eat(&token::Comma) { + return Ok(()) + } + } + Ok(()) + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( From 8f6a0cdb0fd453580bed74586c6930b1498aa26f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:38:36 +0200 Subject: [PATCH 21/45] parser: document `ban_unexpected_or_or`. --- src/libsyntax/parse/parser/pat.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 680a587205686..8fab8884ca018 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -90,6 +90,7 @@ impl<'a> Parser<'a> { } } + /// We have parsed `||` instead of `|`. Error and suggest `|` instead. fn ban_unexpected_or_or(&mut self) { self.struct_span_err(self.token.span, "unexpected token `||` after pattern") .span_suggestion( From b7178ef9836fe8e98ffb3f8d4d870c94e6fe816d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 22:04:28 +0200 Subject: [PATCH 22/45] parser: `parse_pats` -> `parse_top_pat{_unpack}`. --- src/libsyntax/parse/parser/expr.rs | 12 +++++++----- src/libsyntax/parse/parser/pat.rs | 28 +++++++++++++++++----------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 5da9b75d53b04..b9dd851817160 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1241,11 +1241,12 @@ impl<'a> Parser<'a> { Ok(cond) } - /// Parses a `let $pats = $expr` pseudo-expression. + /// Parses a `let $pat = $expr` pseudo-expression. /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; - let pats = self.parse_pats()?; + // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. + let pat = self.parse_top_pat_unpack(false)?; self.expect(&token::Eq)?; let expr = self.with_res( Restrictions::NO_STRUCT_LITERAL, @@ -1253,7 +1254,7 @@ impl<'a> Parser<'a> { )?; let span = lo.to(expr.span); self.sess.gated_spans.let_chains.borrow_mut().push(span); - Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs)) + Ok(self.mk_expr(span, ExprKind::Let(pat, expr), attrs)) } /// `else` token already eaten @@ -1387,7 +1388,8 @@ impl<'a> Parser<'a> { crate fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - let pats = self.parse_pats()?; + // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. + let pat = self.parse_top_pat_unpack(false)?; let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { @@ -1448,7 +1450,7 @@ impl<'a> Parser<'a> { Ok(ast::Arm { attrs, - pats, + pats: pat, // FIXME(or_patterns, Centril | dlrobertson): this should just be `pat,`. guard, body: expr, span: lo.to(hi), diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 8fab8884ca018..e4a9dc0097752 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -20,19 +20,25 @@ impl<'a> Parser<'a> { self.parse_pat_with_range_pat(true, expected) } - /// Parses patterns, separated by '|' s. - pub(super) fn parse_pats(&mut self) -> PResult<'a, Vec>> { - // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - self.eat_or_separator(); - - let mut pats = Vec::new(); - loop { - pats.push(self.parse_top_level_pat()?); + // FIXME(or_patterns, Centril | dlrobertson): + // remove this and use `parse_top_pat` everywhere it is used instead. + pub(super) fn parse_top_pat_unpack(&mut self, gate_or: bool) -> PResult<'a, Vec>> { + self.parse_top_pat(gate_or) + .map(|pat| pat.and_then(|pat| match pat.node { + PatKind::Or(pats) => pats, + node => vec![self.mk_pat(pat.span, node)], + })) + } - if !self.eat_or_separator() { - return Ok(pats); - } + /// 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: bool) -> PResult<'a, P> { + // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). + if self.eat_or_separator() && gate_or { + self.sess.gated_spans.or_patterns.borrow_mut().push(self.prev_span); } + + self.parse_pat_with_or(None, gate_or, true) } pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { From 92d66a131711bc7817e599c81d081847f689654c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 22:35:53 +0200 Subject: [PATCH 23/45] parser: document `parse_pat`. --- src/libsyntax/parse/parser/pat.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index e4a9dc0097752..021e52798af26 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -16,6 +16,10 @@ type Expected = Option<&'static str>; impl<'a> Parser<'a> { /// Parses a pattern. + /// + /// Corresponds to `pat` in RFC 2535 and does not admit or-patterns + /// at the top level. Used when parsing the parameters of lambda expressions, + /// functions, function pointers, and `pat` macro fragments. pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P> { self.parse_pat_with_range_pat(true, expected) } From 95792b4d5a12276068e32f54c5d1561b8528a952 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 22:54:07 +0200 Subject: [PATCH 24/45] parser: `let` stmts & `for` exprs: allow or-patterns. --- src/libsyntax/parse/parser/expr.rs | 2 +- src/libsyntax/parse/parser/pat.rs | 6 ------ src/libsyntax/parse/parser/stmt.rs | 2 +- src/test/ui/parser/bad-match.rs | 2 +- src/test/ui/parser/bad-match.stderr | 4 ++-- src/test/ui/parser/bad-name.stderr | 4 ++-- src/test/ui/parser/issue-22647.rs | 2 +- src/test/ui/parser/issue-22647.stderr | 4 ++-- src/test/ui/parser/issue-22712.rs | 2 +- src/test/ui/parser/issue-22712.stderr | 4 ++-- src/test/ui/parser/issue-24197.rs | 2 +- src/test/ui/parser/issue-24197.stderr | 4 ++-- src/test/ui/parser/mut-patterns.rs | 3 ++- src/test/ui/parser/mut-patterns.stderr | 4 ++-- src/test/ui/parser/pat-lt-bracket-5.rs | 2 +- src/test/ui/parser/pat-lt-bracket-5.stderr | 4 ++-- src/test/ui/parser/pat-ranges-1.rs | 2 +- src/test/ui/parser/pat-ranges-1.stderr | 4 ++-- src/test/ui/parser/pat-ranges-2.rs | 2 +- src/test/ui/parser/pat-ranges-2.stderr | 4 ++-- src/test/ui/parser/pat-ranges-3.rs | 2 +- src/test/ui/parser/pat-ranges-3.stderr | 4 ++-- src/test/ui/parser/pat-ranges-4.rs | 2 +- src/test/ui/parser/pat-ranges-4.stderr | 4 ++-- 24 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index b9dd851817160..25a858b47353f 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1284,7 +1284,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_level_pat()?; + let pat = self.parse_top_pat(true)?; if !self.eat_keyword(kw::In) { let in_span = self.prev_span.between(self.token.span); self.struct_span_err(in_span, "missing `in` in `for` loop") diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 021e52798af26..e77d9120bce78 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -45,12 +45,6 @@ impl<'a> Parser<'a> { self.parse_pat_with_or(None, gate_or, true) } - pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { - let pat = self.parse_pat(None)?; - self.maybe_recover_unexpected_comma(pat.span, true)?; - Ok(pat) - } - /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). /// Corresponds to `pat` in RFC 2535. fn parse_pat_with_or( diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index c911caba4cd41..3c8cb4ea5a582 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -207,7 +207,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; - let pat = self.parse_top_level_pat()?; + let pat = self.parse_top_pat(true)?; 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/parser/bad-match.rs b/src/test/ui/parser/bad-match.rs index 79bc7eec3113e..04100d1701ddb 100644 --- a/src/test/ui/parser/bad-match.rs +++ b/src/test/ui/parser/bad-match.rs @@ -1,4 +1,4 @@ fn main() { - let isize x = 5; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `x` + let isize x = 5; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `x` match x; } diff --git a/src/test/ui/parser/bad-match.stderr b/src/test/ui/parser/bad-match.stderr index 2f29b978e9c91..d5baaf5e93b35 100644 --- a/src/test/ui/parser/bad-match.stderr +++ b/src/test/ui/parser/bad-match.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `x` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `x` --> $DIR/bad-match.rs:2:13 | LL | let isize x = 5; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/bad-name.stderr b/src/test/ui/parser/bad-name.stderr index 15e61cf06cae9..dce4dabedf5c8 100644 --- a/src/test/ui/parser/bad-name.stderr +++ b/src/test/ui/parser/bad-name.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `.` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` --> $DIR/bad-name.rs:4:8 | LL | let x.y::.z foo; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-22647.rs b/src/test/ui/parser/issue-22647.rs index 25cd7ffce5a97..a6861410682cb 100644 --- a/src/test/ui/parser/issue-22647.rs +++ b/src/test/ui/parser/issue-22647.rs @@ -1,5 +1,5 @@ fn main() { - let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` + let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<` where F: Fn() -> i32 { let x = f(); diff --git a/src/test/ui/parser/issue-22647.stderr b/src/test/ui/parser/issue-22647.stderr index 2dc56a5eca3a6..4b1ef4f3dfc78 100644 --- a/src/test/ui/parser/issue-22647.stderr +++ b/src/test/ui/parser/issue-22647.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `<` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` --> $DIR/issue-22647.rs:2:15 | LL | let caller = |f: F| - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-22712.rs b/src/test/ui/parser/issue-22712.rs index b03d578e3d638..774de9c7e6448 100644 --- a/src/test/ui/parser/issue-22712.rs +++ b/src/test/ui/parser/issue-22712.rs @@ -3,7 +3,7 @@ struct Foo { } fn bar() { - let Foo> //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` + let Foo> //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<` } fn main() {} diff --git a/src/test/ui/parser/issue-22712.stderr b/src/test/ui/parser/issue-22712.stderr index 167eaf962e0f4..d9e83144b367a 100644 --- a/src/test/ui/parser/issue-22712.stderr +++ b/src/test/ui/parser/issue-22712.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `<` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` --> $DIR/issue-22712.rs:6:12 | LL | let Foo> - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-24197.rs b/src/test/ui/parser/issue-24197.rs index 005ff9fa2e0ec..aaf5137461fa6 100644 --- a/src/test/ui/parser/issue-24197.rs +++ b/src/test/ui/parser/issue-24197.rs @@ -1,3 +1,3 @@ fn main() { - let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` + let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` } diff --git a/src/test/ui/parser/issue-24197.stderr b/src/test/ui/parser/issue-24197.stderr index 2dfb31432bc99..24818db622ad4 100644 --- a/src/test/ui/parser/issue-24197.stderr +++ b/src/test/ui/parser/issue-24197.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `[` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/issue-24197.rs:2:12 | LL | let buf[0] = 0; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index a5eb48252394f..bffeb1e2e7c40 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -2,5 +2,6 @@ pub fn main() { struct Foo { x: isize } - let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{` + let mut Foo { x: x } = Foo { x: 3 }; + //~^ ERROR: expected one of `:`, `;`, `=`, `@`, or `|`, found `{` } diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index 286956440ec34..b39209afd4295 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `{` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `{` --> $DIR/mut-patterns.rs:5:17 | LL | let mut Foo { x: x } = Foo { x: 3 }; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-5.rs b/src/test/ui/parser/pat-lt-bracket-5.rs index c4b9dd469f54c..aaece1f6bd9cb 100644 --- a/src/test/ui/parser/pat-lt-bracket-5.rs +++ b/src/test/ui/parser/pat-lt-bracket-5.rs @@ -1,3 +1,3 @@ fn main() { - let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` + let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` } diff --git a/src/test/ui/parser/pat-lt-bracket-5.stderr b/src/test/ui/parser/pat-lt-bracket-5.stderr index ce4cc05db19b2..167314dde0650 100644 --- a/src/test/ui/parser/pat-lt-bracket-5.stderr +++ b/src/test/ui/parser/pat-lt-bracket-5.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `[` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/pat-lt-bracket-5.rs:2:10 | LL | let v[0] = v[1]; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-1.rs b/src/test/ui/parser/pat-ranges-1.rs index ce953b2eb2299..1dafb5a07bb5a 100644 --- a/src/test/ui/parser/pat-ranges-1.rs +++ b/src/test/ui/parser/pat-ranges-1.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `..=` + let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, `=`, or `|`, found `..=` } diff --git a/src/test/ui/parser/pat-ranges-1.stderr b/src/test/ui/parser/pat-ranges-1.stderr index 6e0deccab8ca2..4e2c5d28381d8 100644 --- a/src/test/ui/parser/pat-ranges-1.stderr +++ b/src/test/ui/parser/pat-ranges-1.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, or `=`, found `..=` +error: expected one of `:`, `;`, `=`, or `|`, found `..=` --> $DIR/pat-ranges-1.rs:4:21 | LL | let macropus!() ..= 11 = 12; - | ^^^ expected one of `:`, `;`, or `=` here + | ^^^ expected one of `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-2.rs b/src/test/ui/parser/pat-ranges-2.rs index 9f736ed328c5c..1593222acca1b 100644 --- a/src/test/ui/parser/pat-ranges-2.rs +++ b/src/test/ui/parser/pat-ranges-2.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` + let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, `=`, or `|`, found `!` } diff --git a/src/test/ui/parser/pat-ranges-2.stderr b/src/test/ui/parser/pat-ranges-2.stderr index d180bb429110a..64df56f5a61b1 100644 --- a/src/test/ui/parser/pat-ranges-2.stderr +++ b/src/test/ui/parser/pat-ranges-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `::`, `:`, `;`, or `=`, found `!` +error: expected one of `::`, `:`, `;`, `=`, or `|`, found `!` --> $DIR/pat-ranges-2.rs:4:26 | LL | let 10 ..= makropulos!() = 12; - | ^ expected one of `::`, `:`, `;`, or `=` here + | ^ expected one of `::`, `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-3.rs b/src/test/ui/parser/pat-ranges-3.rs index 65da55e3bda8c..8976dcf0d90f9 100644 --- a/src/test/ui/parser/pat-ranges-3.rs +++ b/src/test/ui/parser/pat-ranges-3.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` + let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+` } diff --git a/src/test/ui/parser/pat-ranges-3.stderr b/src/test/ui/parser/pat-ranges-3.stderr index aaa85e3c2ddd8..c32c18d98dce7 100644 --- a/src/test/ui/parser/pat-ranges-3.stderr +++ b/src/test/ui/parser/pat-ranges-3.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, or `=`, found `+` +error: expected one of `:`, `;`, `=`, or `|`, found `+` --> $DIR/pat-ranges-3.rs:4:19 | LL | let 10 ..= 10 + 3 = 12; - | ^ expected one of `:`, `;`, or `=` here + | ^ expected one of `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-4.rs b/src/test/ui/parser/pat-ranges-4.rs index 7f4a5f3239e76..61188976b028c 100644 --- a/src/test/ui/parser/pat-ranges-4.rs +++ b/src/test/ui/parser/pat-ranges-4.rs @@ -2,5 +2,5 @@ fn main() { let 10 - 3 ..= 10 = 8; - //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` + //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` } diff --git a/src/test/ui/parser/pat-ranges-4.stderr b/src/test/ui/parser/pat-ranges-4.stderr index 0a1d7a1f6b8ab..53e38bc670beb 100644 --- a/src/test/ui/parser/pat-ranges-4.stderr +++ b/src/test/ui/parser/pat-ranges-4.stderr @@ -1,8 +1,8 @@ -error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` +error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` --> $DIR/pat-ranges-4.rs:4:12 | LL | let 10 - 3 ..= 10 = 8; - | ^ expected one of `...`, `..=`, `..`, `:`, `;`, or `=` here + | ^ expected one of 7 possible tokens here error: aborting due to previous error From 5f6bec8ecf5a9018bb368becc0aaea703334795a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 22:57:34 +0200 Subject: [PATCH 25/45] parser: drive-by: simplify `parse_arg_general`. --- src/libsyntax/parse/parser.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 89725d8b3395c..002e9bccec72a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -971,15 +971,12 @@ impl<'a> Parser<'a> { /// Skips unexpected attributes and doc comments in this position and emits an appropriate /// error. /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general( + fn parse_arg_general( &mut self, is_trait_item: bool, allow_c_variadic: bool, - is_name_required: F, - ) -> PResult<'a, Arg> - where - F: Fn(&token::Token) -> bool - { + is_name_required: impl Fn(&token::Token) -> bool, + ) -> PResult<'a, Arg> { let lo = self.token.span; let attrs = self.parse_arg_attributes()?; if let Some(mut arg) = self.parse_self_arg()? { From a9af18bed544ede37b6b817cca1d4613aad4696f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 23:07:21 +0200 Subject: [PATCH 26/45] move `ui/or-pattern-mismatch` -> `ui/or-patterns/`. --- src/test/ui/{ => or-patterns}/or-pattern-mismatch.rs | 0 src/test/ui/{ => or-patterns}/or-pattern-mismatch.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => or-patterns}/or-pattern-mismatch.rs (100%) rename src/test/ui/{ => or-patterns}/or-pattern-mismatch.stderr (100%) diff --git a/src/test/ui/or-pattern-mismatch.rs b/src/test/ui/or-patterns/or-pattern-mismatch.rs similarity index 100% rename from src/test/ui/or-pattern-mismatch.rs rename to src/test/ui/or-patterns/or-pattern-mismatch.rs diff --git a/src/test/ui/or-pattern-mismatch.stderr b/src/test/ui/or-patterns/or-pattern-mismatch.stderr similarity index 100% rename from src/test/ui/or-pattern-mismatch.stderr rename to src/test/ui/or-patterns/or-pattern-mismatch.stderr From f35432e1889a4361388adf514634b122aefa746b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 23:53:08 +0200 Subject: [PATCH 27/45] or-patterns: add syntactic tests. --- .../or-patterns/or-patterns-syntactic-fail.rs | 56 +++++++++++++ .../or-patterns-syntactic-fail.stderr | 75 ++++++++++++++++++ .../or-patterns/or-patterns-syntactic-pass.rs | 78 +++++++++++++++++++ .../or-patterns-syntactic-pass.stderr | 8 ++ 4 files changed, 217 insertions(+) create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs new file mode 100644 index 0000000000000..43c9214bd98f7 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -0,0 +1,56 @@ +// Test some cases where or-patterns may ostensibly be allowed but are in fact not. +// This is not a semantic test. We only test parsing. + +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash + +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::*; + +fn no_top_level_or_patterns() { + // We do *not* allow or-patterns at the top level of lambdas... + let _ = |A | B: E| (); //~ ERROR binary operation `|` cannot be applied to type `E` + // -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`. + + // ...and for now neither do we allow or-patterns at the top level of functions. + fn fun(A | B: E) {} //~ ERROR expected one of `:` or `@`, found `|` +} + +// We also do not allow a leading `|` when not in a top level position: + +#[cfg(FALSE)] +fn no_leading_parens() { + let ( | A | B); //~ ERROR expected pattern, found `|` +} + +#[cfg(FALSE)] +fn no_leading_tuple() { + let ( | A | B,); //~ ERROR expected pattern, found `|` +} + +#[cfg(FALSE)] +fn no_leading_slice() { + let [ | A | B ]; //~ ERROR expected pattern, found `|` +} + +#[cfg(FALSE)] +fn no_leading_tuple_struct() { + let TS( | A | B ); //~ ERROR expected pattern, found `|` +} + +#[cfg(FALSE)] +fn no_leading_struct() { + let NS { f: | A | B }; //~ ERROR expected pattern, found `|` +} diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr new file mode 100644 index 0000000000000..809ff272f6204 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -0,0 +1,75 @@ +error: expected one of `:` or `@`, found `|` + --> $DIR/or-patterns-syntactic-fail.rs:28:14 + | +LL | fn fun(A | B: E) {} + | ^ expected one of `:` or `@` here + +error: expected pattern, found `|` + --> $DIR/or-patterns-syntactic-fail.rs:35:11 + | +LL | let ( | A | B); + | ^ expected pattern + +error: expected pattern, found `|` + --> $DIR/or-patterns-syntactic-fail.rs:40:11 + | +LL | let ( | A | B,); + | ^ expected pattern + +error: expected pattern, found `|` + --> $DIR/or-patterns-syntactic-fail.rs:45:11 + | +LL | let [ | A | B ]; + | ^ expected pattern + +error: expected pattern, found `|` + --> $DIR/or-patterns-syntactic-fail.rs:50:13 + | +LL | let TS( | A | B ); + | ^ expected pattern + +error: expected pattern, found `|` + --> $DIR/or-patterns-syntactic-fail.rs:55:17 + | +LL | let NS { f: | A | B }; + | ^ expected pattern + +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail.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.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 + +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/or-patterns-syntactic-fail.rs:4:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0369]: binary operation `|` cannot be applied to type `E` + --> $DIR/or-patterns-syntactic-fail.rs:24:22 + | +LL | let _ = |A | B: E| (); + | ----^ -- () + | | + | E + | + = note: an implementation of `std::ops::BitOr` might be missing for `E` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs new file mode 100644 index 0000000000000..5fe72caf9c1ff --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -0,0 +1,78 @@ +// Here we test all the places `|` is *syntactically* allowed. +// This is not a semantic test. We only test parsing. + +// check-pass + +#![feature(or_patterns)] + +fn main() {} + +// Test the `pat` macro fragment parser: +macro_rules! accept_pat { + ($p:pat) => {} +} + +accept_pat!((p | q)); +accept_pat!((p | q,)); +accept_pat!(TS(p | q)); +accept_pat!(NS { f: p | q }); +accept_pat!([p | q]); + +// Non-macro tests: + +#[cfg(FALSE)] +fn or_patterns() { + // Top level of `let`: + let | A | B; + let A | B; + let A | B: u8; + let A | B = 0; + let A | B: u8 = 0; + + // Top level of `for`: + for | A | B in 0 {} + for A | B in 0 {} + + // Top level of `while`: + while let | A | B = 0 {} + while let A | B = 0 {} + + // Top level of `if`: + if let | A | B = 0 {} + if let A | B = 0 {} + + // Top level of `match` arms: + match 0 { + | A | B => {}, + A | B => {}, + } + + // Functions: + fn fun((A | B): _) {} + + // Lambdas: + let _ = |(A | B): u8| (); + + // Parenthesis and tuple patterns: + let (A | B); + let (A | B,); + + // Tuple struct patterns: + let A(B | C); + let E::V(B | C); + + // Struct patterns: + let S { f1: B | C, f2 }; + let E::V { f1: B | C, f2 }; + + // Slice patterns: + let [A | B, .. | ..]; + + // These bind as `(prefix p) | q` as opposed to `prefix (p | q)`: + let box 0 | 1; // Unstable; we *can* the precedence if we want. + let &0 | 1; + let &mut 0 | 1; + let x @ 0 | 1; + let ref x @ 0 | 1; + let ref mut x @ 0 | 1; +} diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr new file mode 100644 index 0000000000000..3145a2e9f2a6e --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr @@ -0,0 +1,8 @@ +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/or-patterns-syntactic-pass.rs:6:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + From d3b3bceffb1f0fa7727c4d63aa37ecb9444e88c5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 23:57:43 +0200 Subject: [PATCH 28/45] move `feature-gate-or_patterns.*` -> `ui/or-patterns/` --- .../ui/{feature-gate => or-patterns}/feature-gate-or_patterns.rs | 0 .../{feature-gate => or-patterns}/feature-gate-or_patterns.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{feature-gate => or-patterns}/feature-gate-or_patterns.rs (100%) rename src/test/ui/{feature-gate => or-patterns}/feature-gate-or_patterns.stderr (100%) diff --git a/src/test/ui/feature-gate/feature-gate-or_patterns.rs b/src/test/ui/or-patterns/feature-gate-or_patterns.rs similarity index 100% rename from src/test/ui/feature-gate/feature-gate-or_patterns.rs rename to src/test/ui/or-patterns/feature-gate-or_patterns.rs diff --git a/src/test/ui/feature-gate/feature-gate-or_patterns.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr similarity index 100% rename from src/test/ui/feature-gate/feature-gate-or_patterns.stderr rename to src/test/ui/or-patterns/feature-gate-or_patterns.stderr From 1ffea18ddbe9ebaba4ff301a3c42e44a55741355 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 19 Aug 2019 00:19:40 +0200 Subject: [PATCH 29/45] or-patterns: harden feature gating tests. --- .../or-patterns/feature-gate-or_patterns.rs | 47 ++++- .../feature-gate-or_patterns.stderr | 182 +++++++++++++++++- 2 files changed, 227 insertions(+), 2 deletions(-) diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.rs b/src/test/ui/or-patterns/feature-gate-or_patterns.rs index 036a6095965bd..560db20e66862 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns.rs +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.rs @@ -1,4 +1,4 @@ -#![crate_type="lib"] +fn main() {} pub fn example(x: Option) { match x { @@ -7,3 +7,48 @@ pub fn example(x: Option) { _ => {} } } + +// Test the `pat` macro fragment parser: +macro_rules! accept_pat { + ($p:pat) => {} +} + +accept_pat!((p | q)); //~ ERROR or-patterns syntax is experimental +accept_pat!((p | q,)); //~ ERROR or-patterns syntax is experimental +accept_pat!(TS(p | q)); //~ ERROR or-patterns syntax is experimental +accept_pat!(NS { f: p | q }); //~ ERROR or-patterns syntax is experimental +accept_pat!([p | q]); //~ ERROR or-patterns syntax is experimental + +// Non-macro tests: + +#[cfg(FALSE)] +fn or_patterns() { + // Gated: + + let | A | B; //~ ERROR or-patterns syntax is experimental + //~^ ERROR or-patterns syntax is experimental + let A | B; //~ ERROR or-patterns syntax is experimental + for | A | B in 0 {} //~ ERROR or-patterns syntax is experimental + //~^ ERROR or-patterns syntax is experimental + for A | B in 0 {} //~ ERROR or-patterns syntax is experimental + fn fun((A | B): _) {} //~ ERROR or-patterns syntax is experimental + let _ = |(A | B): u8| (); //~ ERROR or-patterns syntax is experimental + let (A | B); //~ ERROR or-patterns syntax is experimental + let (A | B,); //~ ERROR or-patterns syntax is experimental + let A(B | C); //~ ERROR or-patterns syntax is experimental + let E::V(B | C); //~ ERROR or-patterns syntax is experimental + let S { f1: B | C, f2 }; //~ ERROR or-patterns syntax is experimental + let E::V { f1: B | C, f2 }; //~ ERROR or-patterns syntax is experimental + let [A | B]; //~ ERROR or-patterns syntax is experimental + + // Top level of `while`, `if`, and `match` arms are allowed: + + while let | A = 0 {} + while let A | B = 0 {} + if let | A = 0 {} + if let A | B = 0 {} + match 0 { + | A => {}, + A | B => {}, + } +} diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr index aaabb54c1f017..e2abfbfd5254d 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr @@ -7,6 +7,186 @@ LL | Some(0 | 1 | 2) => {} = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:28:9 + | +LL | let | A | B; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:28:11 + | +LL | let | A | B; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:30:9 + | +LL | let A | B; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:31:9 + | +LL | for | A | B in 0 {} + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:31:11 + | +LL | for | A | B in 0 {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:33:9 + | +LL | for A | B in 0 {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:34:13 + | +LL | fn fun((A | B): _) {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:35:15 + | +LL | let _ = |(A | B): u8| (); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:36:10 + | +LL | let (A | B); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:37:10 + | +LL | let (A | B,); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:38:11 + | +LL | let A(B | C); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:39:14 + | +LL | let E::V(B | C); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:40:17 + | +LL | let S { f1: B | C, f2 }; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:41:20 + | +LL | let E::V { f1: B | C, f2 }; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:42:10 + | +LL | let [A | B]; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:16:14 + | +LL | accept_pat!((p | q)); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:17:14 + | +LL | accept_pat!((p | q,)); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:18:16 + | +LL | accept_pat!(TS(p | q)); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:19:21 + | +LL | accept_pat!(NS { f: p | q }); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:20:14 + | +LL | accept_pat!([p | q]); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to 21 previous errors For more information about this error, try `rustc --explain E0658`. From b205055c7bc92c0f873755996e6fac3e694c7e72 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 19 Aug 2019 02:40:24 +0200 Subject: [PATCH 30/45] parser: better recovery for || in inner pats. --- src/libsyntax/parse/parser/pat.rs | 27 ++++++- .../or-patterns/or-patterns-syntactic-fail.rs | 39 ++++------ .../or-patterns-syntactic-fail.stderr | 77 ++++++++++++++----- 3 files changed, 96 insertions(+), 47 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index e77d9120bce78..b9871be229ce5 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -155,6 +155,25 @@ impl<'a> Parser<'a> { Ok(()) } + /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. + /// See `parse_pat_with_or` for details on parsing or-patterns. + fn parse_pat_with_or_inner(&mut self, expected: Expected) -> PResult<'a, P> { + // Recover if `|` or `||` is here. + // The user is thinking that a leading `|` is allowed in this position. + if let token::BinOp(token::Or) | token::OrOr = self.token.kind { + let span = self.token.span; + let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); + + self.struct_span_err(span, "a leading `|` is only allowed in a top-level pattern") + .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable) + .emit(); + + self.bump(); + } + + self.parse_pat_with_or(expected, true, false) + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -173,7 +192,7 @@ impl<'a> Parser<'a> { // Parse `[pat, pat,...]` as a slice pattern. let (pats, _) = self.parse_delim_comma_seq( token::Bracket, - |p| p.parse_pat_with_or(None, true, false), + |p| p.parse_pat_with_or_inner(None), )?; PatKind::Slice(pats) } @@ -303,7 +322,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or(None, true, false) + p.parse_pat_with_or_inner(None) })?; // Here, `(pat,)` is a tuple pattern. @@ -547,7 +566,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true, false))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner(None))?; Ok(PatKind::TupleStruct(path, fields)) } @@ -691,7 +710,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or(None, true, false)?; + let pat = self.parse_pat_with_or_inner(None)?; hi = pat.span; (pat, fieldname, false) } else { 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 43c9214bd98f7..7959812f5b39c 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -30,27 +30,20 @@ fn no_top_level_or_patterns() { // We also do not allow a leading `|` when not in a top level position: -#[cfg(FALSE)] -fn no_leading_parens() { - let ( | A | B); //~ ERROR expected pattern, found `|` -} - -#[cfg(FALSE)] -fn no_leading_tuple() { - let ( | A | B,); //~ ERROR expected pattern, found `|` -} - -#[cfg(FALSE)] -fn no_leading_slice() { - let [ | A | B ]; //~ ERROR expected pattern, found `|` -} - -#[cfg(FALSE)] -fn no_leading_tuple_struct() { - let TS( | A | B ); //~ ERROR expected pattern, found `|` -} - -#[cfg(FALSE)] -fn no_leading_struct() { - let NS { f: | A | B }; //~ ERROR expected pattern, found `|` +fn no_leading_inner() { + struct TS(E); + struct NS { f: E } + + let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern + + let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern + + let recovery_witness: String = 0; //~ ERROR mismatched types } 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 809ff272f6204..dd4c309ce85a3 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -4,35 +4,59 @@ error: expected one of `:` or `@`, found `|` LL | fn fun(A | B: E) {} | ^ expected one of `:` or `@` here -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:35:11 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:37:11 | -LL | let ( | A | B); - | ^ expected pattern +LL | let ( | A | B) = E::A; + | ^ help: remove the `|` -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:40:11 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:38:11 | -LL | let ( | A | B,); - | ^ expected pattern +LL | let ( | A | B,) = (E::B,); + | ^ help: remove the `|` -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:45:11 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:39:11 | -LL | let [ | A | B ]; - | ^ expected pattern +LL | let [ | A | B ] = [E::A]; + | ^ help: remove the `|` -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:50:13 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:40:13 | LL | let TS( | A | B ); - | ^ expected pattern + | ^ help: remove the `|` -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:55:17 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:41:17 | LL | let NS { f: | A | B }; - | ^ expected pattern + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:43: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:44: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:45: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:46:17 + | +LL | let NS { f: || A | B }; + | ^^ help: remove the `||` error: no rules expected the token `|` --> $DIR/or-patterns-syntactic-fail.rs:14:15 @@ -70,6 +94,19 @@ LL | let _ = |A | B: E| (); | = note: an implementation of `std::ops::BitOr` might be missing for `E` -error: aborting due to 9 previous errors +error[E0308]: mismatched types + --> $DIR/or-patterns-syntactic-fail.rs:48:36 + | +LL | let recovery_witness: String = 0; + | ^ + | | + | expected struct `std::string::String`, found integer + | help: try using a conversion method: `0.to_string()` + | + = note: expected type `std::string::String` + found type `{integer}` + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0369`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. From b2966e651de3bf83ab9c712a1afaeba84162cab1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 21:43:28 +0200 Subject: [PATCH 31/45] parser: bool -> GateOr. --- src/libsyntax/parse/parser/expr.rs | 7 ++++--- src/libsyntax/parse/parser/pat.rs | 16 ++++++++++------ src/libsyntax/parse/parser/stmt.rs | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 25a858b47353f..83e5a84a8c6ae 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1,6 +1,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle}; use super::{BlockMode, SemiColonMode}; use super::{SeqSep, TokenExpectType}; +use super::pat::GateOr; use crate::maybe_recover_from_interpolated_ty_qpath; use crate::ptr::P; @@ -1246,7 +1247,7 @@ impl<'a> Parser<'a> { fn parse_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. - let pat = self.parse_top_pat_unpack(false)?; + let pat = self.parse_top_pat_unpack(GateOr::No)?; self.expect(&token::Eq)?; let expr = self.with_res( Restrictions::NO_STRUCT_LITERAL, @@ -1284,7 +1285,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_pat(true)?; + let pat = self.parse_top_pat(GateOr::Yes)?; if !self.eat_keyword(kw::In) { let in_span = self.prev_span.between(self.token.span); self.struct_span_err(in_span, "missing `in` in `for` loop") @@ -1389,7 +1390,7 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. - let pat = self.parse_top_pat_unpack(false)?; + let pat = self.parse_top_pat_unpack(GateOr::No)?; let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index b9871be229ce5..3d89ec56ffafa 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -14,6 +14,10 @@ use errors::{Applicability, DiagnosticBuilder}; type Expected = Option<&'static str>; +/// Whether or not an or-pattern should be gated when occurring in the current context. +#[derive(PartialEq)] +pub enum GateOr { Yes, No } + impl<'a> Parser<'a> { /// Parses a pattern. /// @@ -26,7 +30,7 @@ impl<'a> Parser<'a> { // FIXME(or_patterns, Centril | dlrobertson): // remove this and use `parse_top_pat` everywhere it is used instead. - pub(super) fn parse_top_pat_unpack(&mut self, gate_or: bool) -> PResult<'a, Vec>> { + pub(super) fn parse_top_pat_unpack(&mut self, gate_or: GateOr) -> PResult<'a, Vec>> { self.parse_top_pat(gate_or) .map(|pat| pat.and_then(|pat| match pat.node { PatKind::Or(pats) => pats, @@ -36,9 +40,9 @@ 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: bool) -> PResult<'a, P> { + pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - if self.eat_or_separator() && gate_or { + if self.eat_or_separator() && gate_or == GateOr::Yes { self.sess.gated_spans.or_patterns.borrow_mut().push(self.prev_span); } @@ -50,7 +54,7 @@ impl<'a> Parser<'a> { fn parse_pat_with_or( &mut self, expected: Expected, - gate_or: bool, + gate_or: GateOr, top_level: bool ) -> PResult<'a, P> { // Parse the first pattern. @@ -73,7 +77,7 @@ impl<'a> Parser<'a> { let or_pattern_span = lo.to(self.prev_span); // Feature gate the or-pattern if instructed: - if gate_or { + if gate_or == GateOr::Yes { self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); } @@ -171,7 +175,7 @@ impl<'a> Parser<'a> { self.bump(); } - self.parse_pat_with_or(expected, true, false) + self.parse_pat_with_or(expected, GateOr::Yes, false) } /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index 3c8cb4ea5a582..651ebf6342e71 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -1,6 +1,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, SemiColonMode, BlockMode}; use super::expr::LhsExpr; use super::path::PathStyle; +use super::pat::GateOr; use crate::ptr::P; use crate::{maybe_whole, ThinVec}; @@ -207,7 +208,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; - let pat = self.parse_top_pat(true)?; + let pat = self.parse_top_pat(GateOr::Yes)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` From a9ef8592e47808539ffd9237c22ce5518aa7b188 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 22:12:19 +0200 Subject: [PATCH 32/45] parser: bool -> TopLevel. --- src/libsyntax/parse/parser/pat.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 3d89ec56ffafa..c168d03378133 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -18,6 +18,10 @@ type Expected = Option<&'static str>; #[derive(PartialEq)] pub enum GateOr { Yes, No } +/// Whether or not this is the top level pattern context. +#[derive(PartialEq, Copy, Clone)] +enum TopLevel { Yes, No } + impl<'a> Parser<'a> { /// Parses a pattern. /// @@ -46,7 +50,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.or_patterns.borrow_mut().push(self.prev_span); } - self.parse_pat_with_or(None, gate_or, true) + self.parse_pat_with_or(None, gate_or, TopLevel::Yes) } /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). @@ -55,7 +59,7 @@ impl<'a> Parser<'a> { &mut self, expected: Expected, gate_or: GateOr, - top_level: bool + top_level: TopLevel, ) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; @@ -112,8 +116,8 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: bool) -> PResult<'a, ()> { - if !top_level || self.token != token::Comma { + fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: TopLevel) -> PResult<'a, ()> { + if top_level == TopLevel::No || self.token != token::Comma { return Ok(()); } @@ -175,7 +179,7 @@ impl<'a> Parser<'a> { self.bump(); } - self.parse_pat_with_or(expected, GateOr::Yes, false) + self.parse_pat_with_or(expected, GateOr::Yes, TopLevel::No) } /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are From 3a405421e7c1437416e225ea8d2f0fdfb501df7b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 22:46:17 +0200 Subject: [PATCH 33/45] parse_top_pat: silence leading vert gating sometimes. --- src/libsyntax/parse/parser/pat.rs | 18 ++++++-- .../feature-gate-or_patterns-leading-for.rs | 8 ++++ ...eature-gate-or_patterns-leading-for.stderr | 12 +++++ .../feature-gate-or_patterns-leading-let.rs | 8 ++++ ...eature-gate-or_patterns-leading-let.stderr | 12 +++++ .../feature-gate-or_patterns-leading.stderr | 12 +++++ .../or-patterns/feature-gate-or_patterns.rs | 2 - .../feature-gate-or_patterns.stderr | 44 ++++++------------- 8 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index c168d03378133..724edbcfaed79 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -46,11 +46,23 @@ impl<'a> Parser<'a> { /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - if self.eat_or_separator() && gate_or == GateOr::Yes { - self.sess.gated_spans.or_patterns.borrow_mut().push(self.prev_span); + let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; + + // Parse the possibly-or-pattern. + let pat = self.parse_pat_with_or(None, gate_or, TopLevel::Yes)?; + + // If we parsed a leading `|` which should be gated, + // and no other gated or-pattern has been parsed thus far, + // then we should really gate the leading `|`. + // This complicated procedure is done purely for diagnostics UX. + if gated_leading_vert { + let mut or_pattern_spans = self.sess.gated_spans.or_patterns.borrow_mut(); + if or_pattern_spans.is_empty() { + or_pattern_spans.push(self.prev_span); + } } - self.parse_pat_with_or(None, gate_or, TopLevel::Yes) + Ok(pat) } /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs new file mode 100644 index 0000000000000..de8e1bba5576c --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs @@ -0,0 +1,8 @@ +// Test feature gating for a sole leading `|` in `let`. + +fn main() {} + +#[cfg(FALSE)] +fn gated_leading_vert_in_let() { + for | A in 0 {} //~ ERROR or-patterns syntax is experimental +} diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr new file mode 100644 index 0000000000000..83804d564f3e4 --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr @@ -0,0 +1,12 @@ +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns-leading-for.rs:7:11 + | +LL | for | A in 0 {} + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs new file mode 100644 index 0000000000000..a4ea4e25d861e --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs @@ -0,0 +1,8 @@ +// Test feature gating for a sole leading `|` in `let`. + +fn main() {} + +#[cfg(FALSE)] +fn gated_leading_vert_in_let() { + let | A; //~ ERROR or-patterns syntax is experimental +} diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr new file mode 100644 index 0000000000000..f7954ad7a8ce1 --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr @@ -0,0 +1,12 @@ +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns-leading-let.rs:7:11 + | +LL | let | A; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr new file mode 100644 index 0000000000000..8b18082fca7df --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr @@ -0,0 +1,12 @@ +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns-leading.rs:7:11 + | +LL | let | A; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.rs b/src/test/ui/or-patterns/feature-gate-or_patterns.rs index 560db20e66862..e638838147a4d 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns.rs +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.rs @@ -26,10 +26,8 @@ fn or_patterns() { // Gated: let | A | B; //~ ERROR or-patterns syntax is experimental - //~^ ERROR or-patterns syntax is experimental let A | B; //~ ERROR or-patterns syntax is experimental for | A | B in 0 {} //~ ERROR or-patterns syntax is experimental - //~^ ERROR or-patterns syntax is experimental for A | B in 0 {} //~ ERROR or-patterns syntax is experimental fn fun((A | B): _) {} //~ ERROR or-patterns syntax is experimental let _ = |(A | B): u8| (); //~ ERROR or-patterns syntax is experimental diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr index e2abfbfd5254d..aae6644dac2e0 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr @@ -7,15 +7,6 @@ LL | Some(0 | 1 | 2) => {} = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable -error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:28:9 - | -LL | let | A | B; - | ^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54883 - = help: add `#![feature(or_patterns)]` to the crate attributes to enable - error[E0658]: or-patterns syntax is experimental --> $DIR/feature-gate-or_patterns.rs:28:11 | @@ -26,7 +17,7 @@ LL | let | A | B; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:30:9 + --> $DIR/feature-gate-or_patterns.rs:29:9 | LL | let A | B; | ^^^^^ @@ -35,16 +26,7 @@ LL | let A | B; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:31:9 - | -LL | for | A | B in 0 {} - | ^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54883 - = help: add `#![feature(or_patterns)]` to the crate attributes to enable - -error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:31:11 + --> $DIR/feature-gate-or_patterns.rs:30:11 | LL | for | A | B in 0 {} | ^^^^^ @@ -53,7 +35,7 @@ LL | for | A | B in 0 {} = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:33:9 + --> $DIR/feature-gate-or_patterns.rs:31:9 | LL | for A | B in 0 {} | ^^^^^ @@ -62,7 +44,7 @@ LL | for A | B in 0 {} = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:34:13 + --> $DIR/feature-gate-or_patterns.rs:32:13 | LL | fn fun((A | B): _) {} | ^^^^^ @@ -71,7 +53,7 @@ LL | fn fun((A | B): _) {} = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:35:15 + --> $DIR/feature-gate-or_patterns.rs:33:15 | LL | let _ = |(A | B): u8| (); | ^^^^^ @@ -80,7 +62,7 @@ LL | let _ = |(A | B): u8| (); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:36:10 + --> $DIR/feature-gate-or_patterns.rs:34:10 | LL | let (A | B); | ^^^^^ @@ -89,7 +71,7 @@ LL | let (A | B); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:37:10 + --> $DIR/feature-gate-or_patterns.rs:35:10 | LL | let (A | B,); | ^^^^^ @@ -98,7 +80,7 @@ LL | let (A | B,); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:38:11 + --> $DIR/feature-gate-or_patterns.rs:36:11 | LL | let A(B | C); | ^^^^^ @@ -107,7 +89,7 @@ LL | let A(B | C); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:39:14 + --> $DIR/feature-gate-or_patterns.rs:37:14 | LL | let E::V(B | C); | ^^^^^ @@ -116,7 +98,7 @@ LL | let E::V(B | C); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:40:17 + --> $DIR/feature-gate-or_patterns.rs:38:17 | LL | let S { f1: B | C, f2 }; | ^^^^^ @@ -125,7 +107,7 @@ LL | let S { f1: B | C, f2 }; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:41:20 + --> $DIR/feature-gate-or_patterns.rs:39:20 | LL | let E::V { f1: B | C, f2 }; | ^^^^^ @@ -134,7 +116,7 @@ LL | let E::V { f1: B | C, f2 }; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:42:10 + --> $DIR/feature-gate-or_patterns.rs:40:10 | LL | let [A | B]; | ^^^^^ @@ -187,6 +169,6 @@ LL | accept_pat!([p | q]); = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable -error: aborting due to 21 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0658`. From e3747722fbb8a44f9053922e4c39338a3a1f9597 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 23:10:46 +0200 Subject: [PATCH 34/45] parser: extract recover_inner_leading_vert. --- src/libsyntax/parse/parser/pat.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 724edbcfaed79..dc6632cf10da9 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -178,8 +178,13 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self, expected: Expected) -> PResult<'a, P> { - // Recover if `|` or `||` is here. - // The user is thinking that a leading `|` is allowed in this position. + self.recover_inner_leading_vert(); + self.parse_pat_with_or(expected, GateOr::Yes, TopLevel::No) + } + + /// Recover if `|` or `||` is here. + /// The user is thinking that a leading `|` is allowed in this position. + fn recover_inner_leading_vert(&mut self) { if let token::BinOp(token::Or) | token::OrOr = self.token.kind { let span = self.token.span; let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); @@ -190,8 +195,6 @@ impl<'a> Parser<'a> { self.bump(); } - - self.parse_pat_with_or(expected, GateOr::Yes, TopLevel::No) } /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are From 0ab84303326fff65d5d0a168fd47448e05135c9f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 23:44:28 +0200 Subject: [PATCH 35/45] parser: reword || recovery. --- src/libsyntax/parse/parser/pat.rs | 2 +- .../ui/or-patterns/multiple-pattern-typo.stderr | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index dc6632cf10da9..0b3de57fd6f30 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -119,7 +119,7 @@ impl<'a> Parser<'a> { self.struct_span_err(self.token.span, "unexpected token `||` after pattern") .span_suggestion( self.token.span, - "use a single `|` to specify multiple patterns", + "use a single `|` to separate multiple alternative patterns", "|".to_owned(), Applicability::MachineApplicable ) diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index 765c7879b12ca..c61b5cb208251 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -2,43 +2,43 @@ error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:8:15 | LL | 1 | 2 || 3 => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:13:16 | LL | (1 | 2 || 3) => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:18:16 | LL | (1 | 2 || 3,) => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:25:18 | LL | TS(1 | 2 || 3) => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:32:23 | LL | NS { f: 1 | 2 || 3 } => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:37:16 | LL | [1 | 2 || 3] => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:42:9 | LL | || 1 | 2 | 3 => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` warning: the feature `or_patterns` is incomplete and may cause the compiler to crash --> $DIR/multiple-pattern-typo.rs:1:12 From 1202cb0e2b168b0a913b33e3cb3c1d9339683e28 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 01:00:19 +0200 Subject: [PATCH 36/45] parser: simplify parse_pat_with_or_{inner} --- src/libsyntax/parse/parser/pat.rs | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 0b3de57fd6f30..7c09dc4e56634 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -49,7 +49,7 @@ impl<'a> Parser<'a> { let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, TopLevel::Yes)?; + let pat = self.parse_pat_with_or(gate_or, TopLevel::Yes)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, @@ -67,14 +67,9 @@ impl<'a> Parser<'a> { /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). /// Corresponds to `pat` in RFC 2535. - fn parse_pat_with_or( - &mut self, - expected: Expected, - gate_or: GateOr, - top_level: TopLevel, - ) -> PResult<'a, P> { + fn parse_pat_with_or(&mut self, gate_or: GateOr, top_level: TopLevel) -> PResult<'a, P> { // Parse the first pattern. - let first_pat = self.parse_pat(expected)?; + let first_pat = self.parse_pat(None)?; self.maybe_recover_unexpected_comma(first_pat.span, top_level)?; // If the next token is not a `|`, @@ -86,7 +81,7 @@ impl<'a> Parser<'a> { let lo = first_pat.span; let mut pats = vec![first_pat]; while self.eat_or_separator() { - let pat = self.parse_pat(expected)?; + let pat = self.parse_pat(None)?; self.maybe_recover_unexpected_comma(pat.span, top_level)?; pats.push(pat); } @@ -177,9 +172,9 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. - fn parse_pat_with_or_inner(&mut self, expected: Expected) -> PResult<'a, P> { + fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { self.recover_inner_leading_vert(); - self.parse_pat_with_or(expected, GateOr::Yes, TopLevel::No) + self.parse_pat_with_or(GateOr::Yes, TopLevel::No) } /// Recover if `|` or `||` is here. @@ -215,7 +210,7 @@ impl<'a> Parser<'a> { // Parse `[pat, pat,...]` as a slice pattern. let (pats, _) = self.parse_delim_comma_seq( token::Bracket, - |p| p.parse_pat_with_or_inner(None), + |p| p.parse_pat_with_or_inner(), )?; PatKind::Slice(pats) } @@ -344,9 +339,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { - let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or_inner(None) - })?; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. @@ -589,7 +582,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner(None))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; Ok(PatKind::TupleStruct(path, fields)) } @@ -733,7 +726,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or_inner(None)?; + let pat = self.parse_pat_with_or_inner()?; hi = pat.span; (pat, fieldname, false) } else { From 083963e58c752f1a51b67d65dc6a207bf69f1d64 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 01:50:21 +0200 Subject: [PATCH 37/45] parser: 'while parsing this or-pattern...' --- src/libsyntax/parse/parser/pat.rs | 5 ++++- .../ui/or-patterns/while-parsing-this-or-pattern.rs | 9 +++++++++ .../or-patterns/while-parsing-this-or-pattern.stderr | 10 ++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/or-patterns/while-parsing-this-or-pattern.rs create mode 100644 src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 7c09dc4e56634..a0278fa407765 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -81,7 +81,10 @@ impl<'a> Parser<'a> { let lo = first_pat.span; let mut pats = vec![first_pat]; while self.eat_or_separator() { - let pat = self.parse_pat(None)?; + let pat = self.parse_pat(None).map_err(|mut err| { + err.span_label(lo, "while parsing this or-pattern staring here"); + err + })?; self.maybe_recover_unexpected_comma(pat.span, top_level)?; pats.push(pat); } diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs new file mode 100644 index 0000000000000..4a9fae1406af7 --- /dev/null +++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs @@ -0,0 +1,9 @@ +// Test the parser for the "while parsing this or-pattern..." label here. + +fn main() { + match Some(42) { + Some(42) | .=. => {} //~ ERROR expected pattern, found `.` + //~^ while parsing this or-pattern staring here + //~| NOTE expected pattern + } +} diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr new file mode 100644 index 0000000000000..21fece6c64fe5 --- /dev/null +++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr @@ -0,0 +1,10 @@ +error: expected pattern, found `.` + --> $DIR/while-parsing-this-or-pattern.rs:5:20 + | +LL | Some(42) | .=. => {} + | -------- ^ expected pattern + | | + | while parsing this or-pattern staring here + +error: aborting due to previous error + From 1caaa40768fecb91b322b1e1befc91c54b56817c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 04:39:28 +0200 Subject: [PATCH 38/45] parser: gracefully handle `fn foo(A | B: type)`. --- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/parse/parser/expr.rs | 4 +- src/libsyntax/parse/parser/pat.rs | 46 +++++++++++++++---- src/test/ui/anon-params-denied-2018.rs | 2 +- src/test/ui/anon-params-denied-2018.stderr | 16 +++---- .../feature-gate-or_patterns-leading.stderr | 12 ----- .../or-patterns/or-patterns-syntactic-fail.rs | 6 ++- .../or-patterns-syntactic-fail.stderr | 42 +++++++++++------ src/test/ui/parser/inverted-parameters.rs | 12 ++--- src/test/ui/parser/inverted-parameters.stderr | 24 +++++----- src/test/ui/parser/issue-33413.rs | 2 +- src/test/ui/parser/issue-33413.stderr | 4 +- src/test/ui/parser/issue-63135.rs | 2 +- src/test/ui/parser/issue-63135.stderr | 12 ++--- src/test/ui/parser/omitted-arg-in-item-fn.rs | 2 +- .../ui/parser/omitted-arg-in-item-fn.stderr | 4 +- src/test/ui/parser/pat-lt-bracket-2.rs | 2 +- src/test/ui/parser/pat-lt-bracket-2.stderr | 4 +- src/test/ui/parser/removed-syntax-mode.rs | 2 +- src/test/ui/parser/removed-syntax-mode.stderr | 4 +- .../rfc-2565-param-attrs/param-attrs-2018.rs | 2 +- .../param-attrs-2018.stderr | 4 +- src/test/ui/span/issue-34264.stderr | 12 ++--- 23 files changed, 125 insertions(+), 97 deletions(-) delete mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 002e9bccec72a..25ad2d4404cac 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -988,7 +988,7 @@ impl<'a> Parser<'a> { let (pat, ty) = if is_name_required || self.is_named_argument() { debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required); - let pat = self.parse_pat(Some("argument name"))?; + let pat = self.parse_fn_param_pat()?; if let Err(mut err) = self.expect(&token::Colon) { if let Some(ident) = self.argument_without_type( &mut err, diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 83e5a84a8c6ae..f7c090b5135e9 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1,7 +1,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle}; use super::{BlockMode, SemiColonMode}; use super::{SeqSep, TokenExpectType}; -use super::pat::GateOr; +use super::pat::{GateOr, PARAM_EXPECTED}; use crate::maybe_recover_from_interpolated_ty_qpath; use crate::ptr::P; @@ -1176,7 +1176,7 @@ impl<'a> Parser<'a> { fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { let lo = self.token.span; let attrs = self.parse_arg_attributes()?; - let pat = self.parse_pat(Some("argument name"))?; + let pat = self.parse_pat(PARAM_EXPECTED)?; let t = if self.eat(&token::Colon) { self.parse_ty()? } else { diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index a0278fa407765..1541031ec2539 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -14,6 +14,9 @@ use errors::{Applicability, DiagnosticBuilder}; type Expected = Option<&'static str>; +/// `Expected` for function and lambda parameter patterns. +pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); + /// Whether or not an or-pattern should be gated when occurring in the current context. #[derive(PartialEq)] pub enum GateOr { Yes, No } @@ -49,7 +52,7 @@ impl<'a> Parser<'a> { let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(gate_or, TopLevel::Yes)?; + let pat = self.parse_pat_with_or(None, gate_or, TopLevel::Yes)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, @@ -65,11 +68,38 @@ impl<'a> Parser<'a> { Ok(pat) } + /// Parse the pattern for a function or function pointer parameter. + /// Special recovery is provided for or-patterns and leading `|`. + pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { + self.recover_leading_vert("not allowed in a parameter pattern"); + let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, TopLevel::No)?; + + if let PatKind::Or(..) = &pat.node { + self.ban_illegal_fn_param_or_pat(&pat); + } + + Ok(pat) + } + + /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. + fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) { + let msg = "wrap the pattern in parenthesis"; + let fix = format!("({})", pprust::pat_to_string(pat)); + self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parenthesis") + .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable) + .emit(); + } + /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). /// Corresponds to `pat` in RFC 2535. - fn parse_pat_with_or(&mut self, gate_or: GateOr, top_level: TopLevel) -> PResult<'a, P> { + fn parse_pat_with_or( + &mut self, + expected: Expected, + gate_or: GateOr, + top_level: TopLevel, + ) -> PResult<'a, P> { // Parse the first pattern. - let first_pat = self.parse_pat(None)?; + let first_pat = self.parse_pat(expected)?; self.maybe_recover_unexpected_comma(first_pat.span, top_level)?; // If the next token is not a `|`, @@ -81,7 +111,7 @@ impl<'a> Parser<'a> { let lo = first_pat.span; let mut pats = vec![first_pat]; while self.eat_or_separator() { - let pat = self.parse_pat(None).map_err(|mut err| { + let pat = self.parse_pat(expected).map_err(|mut err| { err.span_label(lo, "while parsing this or-pattern staring here"); err })?; @@ -176,18 +206,18 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { - self.recover_inner_leading_vert(); - self.parse_pat_with_or(GateOr::Yes, TopLevel::No) + self.recover_leading_vert("only allowed in a top-level pattern"); + self.parse_pat_with_or(None, GateOr::Yes, TopLevel::No) } /// Recover if `|` or `||` is here. /// The user is thinking that a leading `|` is allowed in this position. - fn recover_inner_leading_vert(&mut self) { + fn recover_leading_vert(&mut self, ctx: &str) { if let token::BinOp(token::Or) | token::OrOr = self.token.kind { let span = self.token.span; let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); - self.struct_span_err(span, "a leading `|` is only allowed in a top-level pattern") + self.struct_span_err(span, &format!("a leading `|` is {}", ctx)) .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable) .emit(); diff --git a/src/test/ui/anon-params-denied-2018.rs b/src/test/ui/anon-params-denied-2018.rs index abff8275064e2..5721f5d235783 100644 --- a/src/test/ui/anon-params-denied-2018.rs +++ b/src/test/ui/anon-params-denied-2018.rs @@ -3,7 +3,7 @@ // edition:2018 trait T { - fn foo(i32); //~ expected one of `:` or `@`, found `)` + fn foo(i32); //~ expected one of `:`, `@`, or `|`, found `)` fn bar_with_default_impl(String, String) {} //~^ ERROR expected one of `:` diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params-denied-2018.stderr index 438bcf4274daa..a58998e4891e0 100644 --- a/src/test/ui/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params-denied-2018.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:6:15 | LL | fn foo(i32); - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -14,11 +14,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn foo(_: i32); | ^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:8:36 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -30,11 +30,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar_with_default_impl(_: String, String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:8:44 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -46,11 +46,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar_with_default_impl(String, _: String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:13:22 | LL | fn baz(a:usize, b, c: usize) -> usize { - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr deleted file mode 100644 index 8b18082fca7df..0000000000000 --- a/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns-leading.rs:7:11 - | -LL | let | A; - | ^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54883 - = help: add `#![feature(or_patterns)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. 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 7959812f5b39c..b676ea851a3ba 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -25,7 +25,11 @@ fn no_top_level_or_patterns() { // -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`. // ...and for now neither do we allow or-patterns at the top level of functions. - fn fun(A | B: E) {} //~ ERROR expected one of `:` or `@`, found `|` + fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis + + fn fun2(| A | B: E) {} + //~^ ERROR a leading `|` is not allowed in a parameter pattern + //~| ERROR an or-pattern parameter must be wrapped in parenthesis } // We also do not allow a leading `|` when not in a top level position: 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 dd4c309ce85a3..2a3a6abfb7b62 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -1,59 +1,71 @@ -error: expected one of `:` or `@`, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:28:14 +error: an or-pattern parameter must be wrapped in parenthesis + --> $DIR/or-patterns-syntactic-fail.rs:28:13 | -LL | fn fun(A | B: E) {} - | ^ expected one of `:` or `@` here +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:30: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:30: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:37:11 + --> $DIR/or-patterns-syntactic-fail.rs:41: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:38:11 + --> $DIR/or-patterns-syntactic-fail.rs:42: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:39:11 + --> $DIR/or-patterns-syntactic-fail.rs:43: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:40:13 + --> $DIR/or-patterns-syntactic-fail.rs:44: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:41:17 + --> $DIR/or-patterns-syntactic-fail.rs:45: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:43:11 + --> $DIR/or-patterns-syntactic-fail.rs:47: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:44:11 + --> $DIR/or-patterns-syntactic-fail.rs:48: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:45:13 + --> $DIR/or-patterns-syntactic-fail.rs:49: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:46:17 + --> $DIR/or-patterns-syntactic-fail.rs:50:17 | LL | let NS { f: || A | B }; | ^^ help: remove the `||` @@ -95,7 +107,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:48:36 + --> $DIR/or-patterns-syntactic-fail.rs:52:36 | LL | let recovery_witness: String = 0; | ^ @@ -106,7 +118,7 @@ LL | let recovery_witness: String = 0; = note: expected type `std::string::String` found type `{integer}` -error: aborting due to 14 previous errors +error: aborting due to 16 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/parser/inverted-parameters.rs b/src/test/ui/parser/inverted-parameters.rs index f06b951041731..d6efc8be072bd 100644 --- a/src/test/ui/parser/inverted-parameters.rs +++ b/src/test/ui/parser/inverted-parameters.rs @@ -2,29 +2,29 @@ struct S; impl S { fn foo(&self, &str bar) {} - //~^ ERROR expected one of `:` or `@` + //~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : } fn baz(S quux, xyzzy: i32) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : fn one(i32 a b) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` fn pattern((i32, i32) (a, b)) {} -//~^ ERROR expected `:` +//~^ ERROR expected one of `:` fn fizz(i32) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP if this was a parameter name, give it a type //~| HELP if this is a type, explicitly ignore the parameter name fn missing_colon(quux S) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : diff --git a/src/test/ui/parser/inverted-parameters.stderr b/src/test/ui/parser/inverted-parameters.stderr index fb48bd1fe9383..2bda4460031a0 100644 --- a/src/test/ui/parser/inverted-parameters.stderr +++ b/src/test/ui/parser/inverted-parameters.stderr @@ -1,38 +1,38 @@ -error: expected one of `:` or `@`, found `bar` +error: expected one of `:`, `@`, or `|`, found `bar` --> $DIR/inverted-parameters.rs:4:24 | LL | fn foo(&self, &str bar) {} | -----^^^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` -error: expected one of `:` or `@`, found `quux` +error: expected one of `:`, `@`, or `|`, found `quux` --> $DIR/inverted-parameters.rs:10:10 | LL | fn baz(S quux, xyzzy: i32) {} | --^^^^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` -error: expected one of `:` or `@`, found `a` +error: expected one of `:`, `@`, or `|`, found `a` --> $DIR/inverted-parameters.rs:15:12 | LL | fn one(i32 a b) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here -error: expected `:`, found `(` +error: expected one of `:` or `|`, found `(` --> $DIR/inverted-parameters.rs:18:23 | LL | fn pattern((i32, i32) (a, b)) {} - | ^ expected `:` + | ^ expected one of `:` or `|` here -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/inverted-parameters.rs:21:12 | LL | fn fizz(i32) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -44,13 +44,13 @@ help: if this is a type, explicitly ignore the parameter name LL | fn fizz(_: i32) {} | ^^^^^^ -error: expected one of `:` or `@`, found `S` +error: expected one of `:`, `@`, or `|`, found `S` --> $DIR/inverted-parameters.rs:26:23 | LL | fn missing_colon(quux S) {} | -----^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/issue-33413.rs b/src/test/ui/parser/issue-33413.rs index 2ec86958174a4..22f80a8aae866 100644 --- a/src/test/ui/parser/issue-33413.rs +++ b/src/test/ui/parser/issue-33413.rs @@ -2,7 +2,7 @@ struct S; impl S { fn f(*, a: u8) -> u8 {} - //~^ ERROR expected argument name, found `*` + //~^ ERROR expected parameter name, found `*` } fn main() {} diff --git a/src/test/ui/parser/issue-33413.stderr b/src/test/ui/parser/issue-33413.stderr index f6f096b1b9a44..9e1178e8ac1f3 100644 --- a/src/test/ui/parser/issue-33413.stderr +++ b/src/test/ui/parser/issue-33413.stderr @@ -1,8 +1,8 @@ -error: expected argument name, found `*` +error: expected parameter name, found `*` --> $DIR/issue-33413.rs:4:10 | LL | fn f(*, a: u8) -> u8 {} - | ^ expected argument name + | ^ expected parameter name error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63135.rs b/src/test/ui/parser/issue-63135.rs index d5f5f1469f35a..a5a8de85466bb 100644 --- a/src/test/ui/parser/issue-63135.rs +++ b/src/test/ui/parser/issue-63135.rs @@ -1,3 +1,3 @@ -// error-pattern: aborting due to 6 previous errors +// error-pattern: aborting due to 5 previous errors fn i(n{...,f # diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index c0286d90af744..a077ad454a9df 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -28,17 +28,11 @@ error: expected `[`, found `}` LL | fn i(n{...,f # | ^ expected `[` -error: expected `:`, found `)` +error: expected one of `:` or `|`, found `)` --> $DIR/issue-63135.rs:3:15 | LL | fn i(n{...,f # - | ^ expected `:` + | ^ expected one of `:` or `|` here -error: expected one of `->`, `where`, or `{`, found `` - --> $DIR/issue-63135.rs:3:15 - | -LL | fn i(n{...,f # - | ^ expected one of `->`, `where`, or `{` here - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.rs b/src/test/ui/parser/omitted-arg-in-item-fn.rs index 5ee9daf464055..49cbc4d6bf40f 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.rs +++ b/src/test/ui/parser/omitted-arg-in-item-fn.rs @@ -1,4 +1,4 @@ -fn foo(x) { //~ ERROR expected one of `:` or `@`, found `)` +fn foo(x) { //~ ERROR expected one of `:`, `@`, or `|`, found `)` } fn main() {} diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.stderr b/src/test/ui/parser/omitted-arg-in-item-fn.stderr index e501f235d6d3b..7feb15592c54f 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.stderr +++ b/src/test/ui/parser/omitted-arg-in-item-fn.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/omitted-arg-in-item-fn.rs:1:9 | LL | fn foo(x) { - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/parser/pat-lt-bracket-2.rs b/src/test/ui/parser/pat-lt-bracket-2.rs index 6eb01c1c93337..3a778ed14f637 100644 --- a/src/test/ui/parser/pat-lt-bracket-2.rs +++ b/src/test/ui/parser/pat-lt-bracket-2.rs @@ -1,4 +1,4 @@ fn a(B<) {} - //~^ error: expected one of `:` or `@`, found `<` + //~^ error: expected one of `:`, `@`, or `|`, found `<` fn main() {} diff --git a/src/test/ui/parser/pat-lt-bracket-2.stderr b/src/test/ui/parser/pat-lt-bracket-2.stderr index cce1a17e9e8df..dbc8d0f5865c6 100644 --- a/src/test/ui/parser/pat-lt-bracket-2.stderr +++ b/src/test/ui/parser/pat-lt-bracket-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/pat-lt-bracket-2.rs:1:7 | LL | fn a(B<) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-mode.rs b/src/test/ui/parser/removed-syntax-mode.rs index 23851b5f70b37..a438db3b0c18b 100644 --- a/src/test/ui/parser/removed-syntax-mode.rs +++ b/src/test/ui/parser/removed-syntax-mode.rs @@ -1,4 +1,4 @@ fn f(+x: isize) {} -//~^ ERROR expected argument name, found `+` +//~^ ERROR expected parameter name, found `+` fn main() {} diff --git a/src/test/ui/parser/removed-syntax-mode.stderr b/src/test/ui/parser/removed-syntax-mode.stderr index 5e7139d6bfd85..d0393b379f06d 100644 --- a/src/test/ui/parser/removed-syntax-mode.stderr +++ b/src/test/ui/parser/removed-syntax-mode.stderr @@ -1,8 +1,8 @@ -error: expected argument name, found `+` +error: expected parameter name, found `+` --> $DIR/removed-syntax-mode.rs:1:6 | LL | fn f(+x: isize) {} - | ^ expected argument name + | ^ expected parameter name error: aborting due to previous error diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs index e900ccab4fd83..d71711336b06e 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs @@ -3,6 +3,6 @@ #![feature(param_attrs)] trait Trait2015 { fn foo(#[allow(C)] i32); } -//~^ ERROR expected one of `:` or `@`, found `)` +//~^ ERROR expected one of `:`, `@`, or `|`, found `)` fn main() {} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr index d0ed65f288011..26b414e426805 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/param-attrs-2018.rs:5:41 | LL | trait Trait2015 { fn foo(#[allow(C)] i32); } - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 5dd9895c6e4f4..cc0eccd37a26f 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -1,14 +1,14 @@ -error: expected one of `:` or `@`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-34264.rs:1:14 | LL | fn foo(Option, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/issue-34264.rs:1:27 | LL | fn foo(Option, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -20,11 +20,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn foo(Option, _: String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/issue-34264.rs:3:9 | LL | fn bar(x, y: usize) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type From 6a73199da6c06c0b71ed6eeca578b00925137664 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 05:45:51 +0200 Subject: [PATCH 39/45] or_patterns: add run-rustfix tests. --- .../ui/or-patterns/fn-param-wrap-parens.fixed | 14 ++++ .../ui/or-patterns/fn-param-wrap-parens.rs | 14 ++++ .../or-patterns/fn-param-wrap-parens.stderr | 8 +++ .../ui/or-patterns/remove-leading-vert.fixed | 23 +++++++ .../ui/or-patterns/remove-leading-vert.rs | 23 +++++++ .../ui/or-patterns/remove-leading-vert.stderr | 68 +++++++++++++++++++ 6 files changed, 150 insertions(+) create mode 100644 src/test/ui/or-patterns/fn-param-wrap-parens.fixed create mode 100644 src/test/ui/or-patterns/fn-param-wrap-parens.rs create mode 100644 src/test/ui/or-patterns/fn-param-wrap-parens.stderr create mode 100644 src/test/ui/or-patterns/remove-leading-vert.fixed create mode 100644 src/test/ui/or-patterns/remove-leading-vert.rs create mode 100644 src/test/ui/or-patterns/remove-leading-vert.stderr diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.fixed b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed new file mode 100644 index 0000000000000..08730fe8b07b7 --- /dev/null +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed @@ -0,0 +1,14 @@ +// Test the suggestion to wrap an or-pattern as a function parameter in parens. + +// run-rustfix + +#![feature(or_patterns)] +#![allow(warnings)] + +fn main() {} + +enum E { A, B } +use E::*; + +#[cfg(FALSE)] +fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.rs b/src/test/ui/or-patterns/fn-param-wrap-parens.rs new file mode 100644 index 0000000000000..ed667e0e66067 --- /dev/null +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.rs @@ -0,0 +1,14 @@ +// Test the suggestion to wrap an or-pattern as a function parameter in parens. + +// run-rustfix + +#![feature(or_patterns)] +#![allow(warnings)] + +fn main() {} + +enum E { A, B } +use E::*; + +#[cfg(FALSE)] +fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.stderr b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr new file mode 100644 index 0000000000000..2c6e4d9838ddc --- /dev/null +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr @@ -0,0 +1,8 @@ +error: an or-pattern parameter must be wrapped in parenthesis + --> $DIR/fn-param-wrap-parens.rs:14:9 + | +LL | fn fun1(A | B: E) {} + | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + +error: aborting due to previous error + diff --git a/src/test/ui/or-patterns/remove-leading-vert.fixed b/src/test/ui/or-patterns/remove-leading-vert.fixed new file mode 100644 index 0000000000000..e96d76061ac28 --- /dev/null +++ b/src/test/ui/or-patterns/remove-leading-vert.fixed @@ -0,0 +1,23 @@ +// Test the suggestion to remove a leading `|`. + +// run-rustfix + +#![feature(or_patterns)] +#![allow(warnings)] + +fn main() {} + +#[cfg(FALSE)] +fn leading_vert() { + fn fun1( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern + fn fun2( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern + let ( A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern +} diff --git a/src/test/ui/or-patterns/remove-leading-vert.rs b/src/test/ui/or-patterns/remove-leading-vert.rs new file mode 100644 index 0000000000000..3790b17553fe3 --- /dev/null +++ b/src/test/ui/or-patterns/remove-leading-vert.rs @@ -0,0 +1,23 @@ +// Test the suggestion to remove a leading `|`. + +// run-rustfix + +#![feature(or_patterns)] +#![allow(warnings)] + +fn main() {} + +#[cfg(FALSE)] +fn leading_vert() { + fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern + fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern + let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( || A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( | A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ | A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ || A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( | A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( || A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern +} diff --git a/src/test/ui/or-patterns/remove-leading-vert.stderr b/src/test/ui/or-patterns/remove-leading-vert.stderr new file mode 100644 index 0000000000000..cbe06f997296a --- /dev/null +++ b/src/test/ui/or-patterns/remove-leading-vert.stderr @@ -0,0 +1,68 @@ +error: a leading `|` is not allowed in a parameter pattern + --> $DIR/remove-leading-vert.rs:12:14 + | +LL | fn fun1( | A: E) {} + | ^ help: remove the `|` + +error: a leading `|` is not allowed in a parameter pattern + --> $DIR/remove-leading-vert.rs:13:14 + | +LL | fn fun2( || A: E) {} + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:14:11 + | +LL | let ( | A): E; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:15:11 + | +LL | let ( || A): (E); + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:16:11 + | +LL | let ( | A,): (E,); + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:17:11 + | +LL | let [ | A ]: [E; 1]; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:18:11 + | +LL | let [ || A ]: [E; 1]; + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:19:13 + | +LL | let TS( | A ): TS; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:20:13 + | +LL | let TS( || A ): TS; + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:21:17 + | +LL | let NS { f: | A }: NS; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:22:17 + | +LL | let NS { f: || A }: NS; + | ^^ help: remove the `||` + +error: aborting due to 11 previous errors + From acb11305e8d7298750797d45324c0ecb3cc6c256 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 06:15:11 +0200 Subject: [PATCH 40/45] parser: TopLevel -> RecoverComma. --- src/libsyntax/parse/parser/pat.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 1541031ec2539..f2e269e03baf9 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -21,9 +21,9 @@ pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); #[derive(PartialEq)] pub enum GateOr { Yes, No } -/// Whether or not this is the top level pattern context. +/// Whether or not to recover a `,` when parsing or-patterns. #[derive(PartialEq, Copy, Clone)] -enum TopLevel { Yes, No } +enum RecoverComma { Yes, No } impl<'a> Parser<'a> { /// Parses a pattern. @@ -52,7 +52,7 @@ impl<'a> Parser<'a> { let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, TopLevel::Yes)?; + let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, @@ -72,7 +72,7 @@ impl<'a> Parser<'a> { /// Special recovery is provided for or-patterns and leading `|`. pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { self.recover_leading_vert("not allowed in a parameter pattern"); - let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, TopLevel::No)?; + let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; if let PatKind::Or(..) = &pat.node { self.ban_illegal_fn_param_or_pat(&pat); @@ -96,11 +96,11 @@ impl<'a> Parser<'a> { &mut self, expected: Expected, gate_or: GateOr, - top_level: TopLevel, + rc: RecoverComma, ) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; - self.maybe_recover_unexpected_comma(first_pat.span, top_level)?; + self.maybe_recover_unexpected_comma(first_pat.span, rc)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -115,7 +115,7 @@ impl<'a> Parser<'a> { err.span_label(lo, "while parsing this or-pattern staring here"); err })?; - self.maybe_recover_unexpected_comma(pat.span, top_level)?; + self.maybe_recover_unexpected_comma(pat.span, rc)?; pats.push(pat); } let or_pattern_span = lo.to(self.prev_span); @@ -156,8 +156,8 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: TopLevel) -> PResult<'a, ()> { - if top_level == TopLevel::No || self.token != token::Comma { + fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> { + if rc == RecoverComma::No || self.token != token::Comma { return Ok(()); } @@ -207,7 +207,7 @@ impl<'a> Parser<'a> { /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { self.recover_leading_vert("only allowed in a top-level pattern"); - self.parse_pat_with_or(None, GateOr::Yes, TopLevel::No) + self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No) } /// Recover if `|` or `||` is here. From c9d9616e825fecd4301beaf7bcd9115d5d7d393f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 24 Aug 2019 17:50:21 +0200 Subject: [PATCH 41/45] Introduce and use `Feature` type for feature gates This replaces the ad-hoc tuples used in the different feature gate files and unifies their content into a common type, leading to more readable matches and other good stuff that comes from having named fields. It also contains the description of each feature as extracted from the doc comment. --- src/libsyntax/feature_gate/accepted.rs | 16 ++++++++++--- src/libsyntax/feature_gate/active.rs | 10 ++++++++ src/libsyntax/feature_gate/check.rs | 33 ++++++++++++++------------ src/libsyntax/feature_gate/mod.rs | 33 ++++++++++++++++++++++++++ src/libsyntax/feature_gate/removed.rs | 29 ++++++++++++++++++---- 5 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs index 28e4d2c073c7c..6c0b271c6c5e9 100644 --- a/src/libsyntax/feature_gate/accepted.rs +++ b/src/libsyntax/feature_gate/accepted.rs @@ -1,14 +1,24 @@ //! List of the accepted feature gates. -use crate::symbol::{Symbol, sym}; +use crate::symbol::sym; +use super::{State, Feature}; macro_rules! declare_features { ($( $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None), )+) => { /// Those language feature has since been Accepted (it was once Active) - pub const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ + pub const ACCEPTED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Accepted, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ ]; } } diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 4008b79b141eb..c947b09fdcb57 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -65,6 +65,16 @@ macro_rules! declare_features { }; } +impl Feature { + /// Set this feature in `Features`. Panics if called on a non-active feature. + pub fn set(&self, features: &mut Features, span: Span) { + match self.state { + State::Active { set } => set(features, span), + _ => panic!("Called `set` on feature `{}` which is not `active`", self.name) + } + } +} + // If you change this, please modify `src/doc/unstable-book` as well. // // Don't ever remove anything from this list; move them to `removed.rs`. diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index d82b287b6fb05..344e5fd6e46c2 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -1,4 +1,4 @@ -use super::active::{ACTIVE_FEATURES, Features}; +use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState}; use super::accepted::ACCEPTED_FEATURES; use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use super::builtin_attrs::{AttributeGate, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; @@ -127,17 +127,16 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: } fn find_lang_feature_issue(feature: Symbol) -> Option { - if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { - let issue = info.2; + if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { // FIXME (#28244): enforce that active features have issue numbers - // assert!(issue.is_some()) - issue + // assert!(info.issue.is_some()) + info.issue } else { // search in Accepted, Removed, or Stable Removed features let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) - .find(|t| t.0 == feature); + .find(|t| t.name == feature); match found { - Some(&(_, _, issue, _)) => issue, + Some(&Feature { issue, .. }) => issue, None => panic!("Feature `{}` is not declared anywhere", feature), } } @@ -829,14 +828,18 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], continue; } - let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); - let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); - if let Some((.., reason)) = removed.or(stable_removed) { - feature_removed(span_handler, mi.span(), *reason); - continue; + let removed = REMOVED_FEATURES.iter().find(|f| name == f.name); + let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name); + if let Some(Feature { state, .. }) = removed.or(stable_removed) { + if let FeatureState::Removed { reason } + | FeatureState::Stabilized { reason } = state + { + feature_removed(span_handler, mi.span(), *reason); + continue; + } } - if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { + if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { let since = Some(Symbol::intern(since)); features.declared_lang_features.push((name, mi.span(), since)); continue; @@ -851,8 +854,8 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } } - if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { - set(&mut features, mi.span()); + if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { + f.set(&mut features, mi.span()); features.declared_lang_features.push((name, mi.span(), None)); continue; } diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs index 97793bca1f589..1e41667ea411e 100644 --- a/src/libsyntax/feature_gate/mod.rs +++ b/src/libsyntax/feature_gate/mod.rs @@ -18,6 +18,39 @@ mod active; mod builtin_attrs; mod check; +use std::fmt; +use crate::{edition::Edition, symbol::Symbol}; +use syntax_pos::Span; + +#[derive(Clone, Copy)] +pub enum State { + Accepted, + Active { set: fn(&mut Features, Span) }, + Removed { reason: Option<&'static str> }, + Stabilized { reason: Option<&'static str> }, +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + State::Accepted { .. } => write!(f, "accepted"), + State::Active { .. } => write!(f, "active"), + State::Removed { .. } => write!(f, "removed"), + State::Stabilized { .. } => write!(f, "stabilized"), + } + } +} + +#[derive(Debug, Clone)] +pub struct Feature { + state: State, + name: Symbol, + since: &'static str, + issue: Option, + edition: Option, + description: &'static str, +} + pub use active::{Features, INCOMPLETE_FEATURES}; pub use builtin_attrs::{ AttributeGate, AttributeType, GatedCfg, diff --git a/src/libsyntax/feature_gate/removed.rs b/src/libsyntax/feature_gate/removed.rs index 6494c82e1228b..ad7d69b3e7372 100644 --- a/src/libsyntax/feature_gate/removed.rs +++ b/src/libsyntax/feature_gate/removed.rs @@ -1,14 +1,24 @@ //! List of the removed feature gates. -use crate::symbol::{Symbol, sym}; +use crate::symbol::sym; +use super::{State, Feature}; macro_rules! declare_features { ($( $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), )+) => { /// Represents unstable features which have since been removed (it was once Active) - pub const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, $reason)),+ + pub const REMOVED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Removed { reason: $reason }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ ]; }; @@ -16,8 +26,17 @@ macro_rules! declare_features { $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None), )+) => { /// Represents stable features which have since been removed (it was once Accepted) - pub const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ + pub const STABLE_REMOVED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Stabilized { reason: None }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ ]; }; } From 94e8ff4f0b94c788ec9e9a28d3aa6f87062e2966 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 24 Aug 2019 17:50:21 +0200 Subject: [PATCH 42/45] Refactor feature gate checking code Tries to clarify the filtering of active features and make the code more expressive. --- src/libsyntax/feature_gate/check.rs | 40 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 344e5fd6e46c2..f3a9d135125ae 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -732,13 +732,9 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } } - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= crate_edition { - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, crate_edition); - } - } + for feature in active_features_up_to(crate_edition) { + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, crate_edition); } // Process the edition umbrella feature-gates first, to ensure @@ -760,20 +756,17 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], let name = mi.name_or_empty(); - if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) { - if *edition <= crate_edition { + let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); + if let Some(edition) = edition { + if edition <= crate_edition { continue; } - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= *edition { - // FIXME(Manishearth) there is currently no way to set - // lib features by edition - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, *edition); - } - } + for feature in active_features_up_to(edition) { + // FIXME(Manishearth) there is currently no way to set + // lib features by edition + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, edition); } } } @@ -867,6 +860,17 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], features } +fn active_features_up_to(edition: Edition) -> impl Iterator { + ACTIVE_FEATURES.iter() + .filter(move |feature| { + if let Some(feature_edition) = feature.edition { + feature_edition <= edition + } else { + false + } + }) +} + pub fn check_crate(krate: &ast::Crate, sess: &ParseSess, features: &Features, From 633f67ad74179ee51aaaf913d14d3d9ab65f4a65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Aug 2019 20:40:30 +0200 Subject: [PATCH 43/45] add link to FileCheck docs --- src/test/codegen/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/test/codegen/README.md diff --git a/src/test/codegen/README.md b/src/test/codegen/README.md new file mode 100644 index 0000000000000..00de55eeab1f4 --- /dev/null +++ b/src/test/codegen/README.md @@ -0,0 +1,2 @@ +The files here use the LLVM FileCheck framework, documented at +. From 2bd27fbdfe309f3f6abd76f72f379247d49048b7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 26 Aug 2019 22:14:31 +0200 Subject: [PATCH 44/45] parser: fix span for leading vert. --- src/libsyntax/parse/parser/pat.rs | 3 ++- .../or-patterns/feature-gate-or_patterns-leading-for.stderr | 4 ++-- .../or-patterns/feature-gate-or_patterns-leading-let.stderr | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index f2e269e03baf9..78c9a289b3702 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -50,6 +50,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; + let leading_vert_span = self.prev_span; // Parse the possibly-or-pattern. let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; @@ -61,7 +62,7 @@ impl<'a> Parser<'a> { if gated_leading_vert { let mut or_pattern_spans = self.sess.gated_spans.or_patterns.borrow_mut(); if or_pattern_spans.is_empty() { - or_pattern_spans.push(self.prev_span); + or_pattern_spans.push(leading_vert_span); } } diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr index 83804d564f3e4..f520409e8bad6 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr @@ -1,8 +1,8 @@ error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns-leading-for.rs:7:11 + --> $DIR/feature-gate-or_patterns-leading-for.rs:7:9 | LL | for | A in 0 {} - | ^ + | ^ | = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr index f7954ad7a8ce1..30fd6a1a95eff 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr @@ -1,8 +1,8 @@ error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns-leading-let.rs:7:11 + --> $DIR/feature-gate-or_patterns-leading-let.rs:7:9 | LL | let | A; - | ^ + | ^ | = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable From 7def99af8a311139c43c961e13872ff27dd235c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 26 Aug 2019 13:25:27 -0700 Subject: [PATCH 45/45] review comment --- src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs | 2 +- src/test/ui/lint/lint-dead-code-unused-variant-pub.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs b/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs index 2b06fcb69ceee..15b04496ba7b1 100644 --- a/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs +++ b/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs @@ -1,4 +1,4 @@ -// run-pass +// build-pass #![deny(unused)] pub enum E {} diff --git a/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs b/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs index 918300ba79354..3a9061340eb81 100644 --- a/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs +++ b/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs @@ -1,4 +1,4 @@ -// run-pass +// build-pass #![deny(unused)] pub struct F;