From 63553a10adc8b507edee1fce43f868d93628ce34 Mon Sep 17 00:00:00 2001 From: P1start Date: Sun, 30 Nov 2014 21:33:04 +1300 Subject: [PATCH] Fix the ordering of `unsafe` and `extern` in methods This breaks code that looks like this: trait Foo { extern "C" unsafe fn foo(); } impl Foo for Bar { extern "C" unsafe fn foo() { ... } } Change such code to look like this: trait Foo { unsafe extern "C" fn foo(); } impl Foo for Bar { unsafe extern "C" fn foo() { ... } } Fixes #19398. [breaking-change] --- src/libsyntax/parse/parser.rs | 15 ++++++++------- src/test/compile-fail/issue-19398.rs | 15 +++++++++++++++ .../compile-fail/removed-syntax-static-fn.rs | 2 +- src/test/run-pass/issue-19398.rs | 19 +++++++++++++++++++ 4 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/issue-19398.rs create mode 100644 src/test/run-pass/issue-19398.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 447f2a376e1..c76d9edf635 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1296,13 +1296,14 @@ impl<'a> Parser<'a> { let lo = p.span.lo; let vis = p.parse_visibility(); + let style = p.parse_fn_style(); let abi = if p.eat_keyword(keywords::Extern) { p.parse_opt_abi().unwrap_or(abi::C) } else { abi::Rust }; + p.expect_keyword(keywords::Fn); - let style = p.parse_fn_style(); let ident = p.parse_ident(); let mut generics = p.parse_generics(); @@ -4458,12 +4459,13 @@ impl<'a> Parser<'a> { self.span.hi) }; (ast::MethMac(m), self.span.hi, attrs) } else { + let fn_style = self.parse_fn_style(); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi().unwrap_or(abi::C) } else { abi::Rust }; - let fn_style = self.parse_fn_style(); + self.expect_keyword(keywords::Fn); let ident = self.parse_ident(); let mut generics = self.parse_generics(); let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { @@ -5009,14 +5011,13 @@ impl<'a> Parser<'a> { }) } - /// Parse safe/unsafe and fn + /// Parse unsafe or not fn parse_fn_style(&mut self) -> FnStyle { - if self.eat_keyword(keywords::Fn) { NormalFn } - else if self.eat_keyword(keywords::Unsafe) { - self.expect_keyword(keywords::Fn); + if self.eat_keyword(keywords::Unsafe) { UnsafeFn + } else { + NormalFn } - else { self.unexpected(); } } diff --git a/src/test/compile-fail/issue-19398.rs b/src/test/compile-fail/issue-19398.rs new file mode 100644 index 00000000000..3a6d15e0086 --- /dev/null +++ b/src/test/compile-fail/issue-19398.rs @@ -0,0 +1,15 @@ +// Copyright 2014 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 T { + extern "Rust" unsafe fn foo(); //~ ERROR expected `fn`, found `unsafe` +} + +fn main() {} diff --git a/src/test/compile-fail/removed-syntax-static-fn.rs b/src/test/compile-fail/removed-syntax-static-fn.rs index f6455608fdc..e3e1cb0f3ca 100644 --- a/src/test/compile-fail/removed-syntax-static-fn.rs +++ b/src/test/compile-fail/removed-syntax-static-fn.rs @@ -11,5 +11,5 @@ struct S; impl S { - static fn f() {} //~ ERROR unexpected token: `static` + static fn f() {} //~ ERROR expected `fn`, found `static` } diff --git a/src/test/run-pass/issue-19398.rs b/src/test/run-pass/issue-19398.rs new file mode 100644 index 00000000000..1196162568a --- /dev/null +++ b/src/test/run-pass/issue-19398.rs @@ -0,0 +1,19 @@ +// Copyright 2014 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 T { + unsafe extern "Rust" fn foo(); +} + +impl T for () { + unsafe extern "Rust" fn foo() {} +} + +fn main() {}