diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index f1ec3371c3b..b78f2ca676d 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -261,6 +261,19 @@ let result = loop { // ok! ``` "##, +E0642: r##" +Trait methods currently cannot take patterns as arguments. + +Example of erroneous code: + +```compile_fail,E0642 +trait Foo { + fn foo((x, y): (i32, i32)); // error: patterns aren't allowed + // in methods without bodies +} +``` +"##, + E0695: r##" A `break` statement without a label appeared inside a labeled block. @@ -306,7 +319,6 @@ register_diagnostics! { E0561, // patterns aren't allowed in function pointer types E0567, // auto traits can not have generic parameters E0568, // auto traits can not have super traits - E0642, // patterns aren't allowed in methods without bodies E0666, // nested `impl Trait` is illegal E0667, // `impl Trait` in projections E0696, // `continue` pointing to a labeled block diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index c8e60620248..76035a73d1a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -26,6 +26,7 @@ #![feature(slice_sort_by_cached_key)] #![feature(str_escape)] #![feature(unicode_internals)] +#![feature(catch_expr)] #![recursion_limit="256"] diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9011b6e48b9..5a2fd5f0145 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1371,7 +1371,7 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ + let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1744,30 +1744,43 @@ impl<'a> Parser<'a> { fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> { maybe_whole!(self, NtArg, |x| x); - let (pat, ty) = if require_name || self.is_named_argument() { - debug!("parse_arg_general parse_pat (require_name:{})", - require_name); - let pat = self.parse_pat()?; + let parser_snapshot_before_pat = self.clone(); + // We're going to try parsing the argument as a pattern (even if it's not + // allowed, such as for trait methods without bodies). This way we can provide + // better errors to the user. + let pat_arg: PResult<'a, (P, P)> = do catch { + let pat = self.parse_pat()?; self.expect(&token::Colon)?; (pat, self.parse_ty()?) - } else { - debug!("parse_arg_general ident_to_pat"); - let ident = Ident::new(keywords::Invalid.name(), self.prev_span); - let ty = self.parse_ty()?; - let pat = P(Pat { - id: ast::DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), - span: ty.span, - }); - (pat, ty) }; - Ok(Arg { - ty, - pat, - id: ast::DUMMY_NODE_ID, - }) + let is_named_argument = self.is_named_argument(); + match pat_arg { + Ok((pat, ty)) => { + Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) + } + Err(mut err) => { + if require_name || is_named_argument { + Err(err) + } else { + err.cancel(); + // Recover from attempting to parse the argument as a pattern. This means + // the type is alone, with no name, e.g. `fn foo(u32)`. + mem::replace(self, parser_snapshot_before_pat); + debug!("parse_arg_general ident_to_pat"); + let ident = Ident::new(keywords::Invalid.name(), self.prev_span); + let ty = self.parse_ty()?; + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident( + BindingMode::ByValue(Mutability::Immutable), ident, None), + span: ty.span, + }); + Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) + } + } + } } /// Parse a single function argument diff --git a/src/test/ui/E0642.rs b/src/test/ui/E0642.rs new file mode 100644 index 00000000000..a09846cb3a1 --- /dev/null +++ b/src/test/ui/E0642.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies +} + +fn main() {} diff --git a/src/test/ui/E0642.stderr b/src/test/ui/E0642.stderr new file mode 100644 index 00000000000..edc430d578b --- /dev/null +++ b/src/test/ui/E0642.stderr @@ -0,0 +1,9 @@ +error[E0642]: patterns aren't allowed in methods without bodies + --> $DIR/E0642.rs:12:12 + | +LL | fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0642`.