rustc: Enable writing "unsafe extern fn() {}"
Previously, the parser would not allow you to simultaneously implement a function with a different abi as well as being unsafe at the same time. This extends the parser to allow functions of the form: unsafe extern fn foo() { // ... } The closure type grammar was also changed to reflect this reversal, types previously written as "extern unsafe fn()" must now be written as "unsafe extern fn()". The parser currently has a hack which allows the old style, but this will go away once a snapshot has landed. Closes #10025 [breaking-change]
This commit is contained in:
parent
cf6857b9e9
commit
08237cad8d
@ -110,7 +110,6 @@ enum Family {
|
||||
UnsafeFn, // u
|
||||
StaticMethod, // F
|
||||
UnsafeStaticMethod, // U
|
||||
ForeignFn, // e
|
||||
Type, // y
|
||||
ForeignType, // T
|
||||
Mod, // m
|
||||
@ -134,7 +133,6 @@ fn item_family(item: ebml::Doc) -> Family {
|
||||
'u' => UnsafeFn,
|
||||
'F' => StaticMethod,
|
||||
'U' => UnsafeStaticMethod,
|
||||
'e' => ForeignFn,
|
||||
'y' => Type,
|
||||
'T' => ForeignType,
|
||||
'm' => Mod,
|
||||
@ -339,7 +337,6 @@ fn item_to_def_like(item: ebml::Doc, did: ast::DefId, cnum: ast::CrateNum)
|
||||
Struct => DlDef(ast::DefStruct(did)),
|
||||
UnsafeFn => DlDef(ast::DefFn(did, ast::UnsafeFn)),
|
||||
Fn => DlDef(ast::DefFn(did, ast::NormalFn)),
|
||||
ForeignFn => DlDef(ast::DefFn(did, ast::ExternFn)),
|
||||
StaticMethod | UnsafeStaticMethod => {
|
||||
let fn_style = if fam == UnsafeStaticMethod { ast::UnsafeFn } else
|
||||
{ ast::NormalFn };
|
||||
|
@ -787,7 +787,6 @@ fn style_fn_family(s: FnStyle) -> char {
|
||||
match s {
|
||||
UnsafeFn => 'u',
|
||||
NormalFn => 'f',
|
||||
ExternFn => 'e'
|
||||
}
|
||||
}
|
||||
|
||||
@ -795,7 +794,6 @@ fn fn_style_static_method_family(s: FnStyle) -> char {
|
||||
match s {
|
||||
UnsafeFn => 'U',
|
||||
NormalFn => 'F',
|
||||
_ => fail!("extern fn can't be static")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,7 +441,6 @@ fn parse_fn_style(c: char) -> FnStyle {
|
||||
match c {
|
||||
'u' => UnsafeFn,
|
||||
'n' => NormalFn,
|
||||
'c' => ExternFn,
|
||||
_ => fail!("parse_fn_style: bad fn_style {}", c)
|
||||
}
|
||||
}
|
||||
|
@ -293,7 +293,6 @@ fn enc_fn_style(w: &mut MemWriter, p: FnStyle) {
|
||||
match p {
|
||||
NormalFn => mywrite!(w, "n"),
|
||||
UnsafeFn => mywrite!(w, "u"),
|
||||
ExternFn => mywrite!(w, "c")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ use middle::privacy;
|
||||
use util::nodemap::NodeSet;
|
||||
|
||||
use collections::HashSet;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::{def_id_of_def, is_local};
|
||||
@ -250,8 +251,10 @@ impl<'a> ReachableContext<'a> {
|
||||
match *node {
|
||||
ast_map::NodeItem(item) => {
|
||||
match item.node {
|
||||
ast::ItemFn(_, ast::ExternFn, _, _, _) => {
|
||||
self.reachable_symbols.insert(search_item);
|
||||
ast::ItemFn(_, _, abi, _, _) => {
|
||||
if abi != abi::Rust {
|
||||
self.reachable_symbols.insert(search_item);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -1594,8 +1594,8 @@ impl<'a> Visitor<()> for TransItemVisitor<'a> {
|
||||
pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
|
||||
let _icx = push_ctxt("trans_item");
|
||||
match item.node {
|
||||
ast::ItemFn(decl, fn_style, _abi, ref generics, body) => {
|
||||
if fn_style == ast::ExternFn {
|
||||
ast::ItemFn(decl, _fn_style, abi, ref generics, body) => {
|
||||
if abi != Rust {
|
||||
let llfndecl = get_item_val(ccx, item.id);
|
||||
foreign::trans_rust_fn_with_foreign_abi(
|
||||
ccx, decl, body, item.attrs.as_slice(), llfndecl, item.id);
|
||||
@ -1939,8 +1939,8 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
||||
}
|
||||
}
|
||||
|
||||
ast::ItemFn(_, fn_style, _, _, _) => {
|
||||
let llfn = if fn_style != ast::ExternFn {
|
||||
ast::ItemFn(_, _, abi, _, _) => {
|
||||
let llfn = if abi == Rust {
|
||||
register_fn(ccx, i.span, sym, i.id, ty)
|
||||
} else {
|
||||
foreign::register_rust_fn_with_foreign_abi(ccx,
|
||||
|
@ -403,6 +403,5 @@ pub fn ast_fn_style_constant(fn_style: ast::FnStyle) -> uint {
|
||||
match fn_style {
|
||||
ast::UnsafeFn => 1u,
|
||||
ast::NormalFn => 2u,
|
||||
ast::ExternFn => 3u
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ use middle::typeck::infer::{cres, InferCtxt};
|
||||
use middle::typeck::infer::{TypeTrace, Subtype};
|
||||
use middle::typeck::infer::fold_regions_in_sig;
|
||||
use syntax::ast::{Many, Once, MutImmutable, MutMutable};
|
||||
use syntax::ast::{ExternFn, NormalFn, UnsafeFn, NodeId};
|
||||
use syntax::ast::{NormalFn, UnsafeFn, NodeId};
|
||||
use syntax::ast::{Onceness, FnStyle};
|
||||
use collections::HashMap;
|
||||
use util::common::{indenter};
|
||||
@ -83,7 +83,6 @@ impl<'f> Combine for Glb<'f> {
|
||||
|
||||
fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
|
||||
match (a, b) {
|
||||
(ExternFn, _) | (_, ExternFn) => Ok(ExternFn),
|
||||
(NormalFn, _) | (_, NormalFn) => Ok(NormalFn),
|
||||
(UnsafeFn, UnsafeFn) => Ok(UnsafeFn)
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use middle::typeck::infer::fold_regions_in_sig;
|
||||
use middle::typeck::infer::{TypeTrace, Subtype};
|
||||
use collections::HashMap;
|
||||
use syntax::ast::{Many, Once, NodeId};
|
||||
use syntax::ast::{ExternFn, NormalFn, UnsafeFn};
|
||||
use syntax::ast::{NormalFn, UnsafeFn};
|
||||
use syntax::ast::{Onceness, FnStyle};
|
||||
use util::ppaux::mt_to_str;
|
||||
|
||||
@ -78,8 +78,7 @@ impl<'f> Combine for Lub<'f> {
|
||||
fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
|
||||
match (a, b) {
|
||||
(UnsafeFn, _) | (_, UnsafeFn) => Ok(UnsafeFn),
|
||||
(NormalFn, _) | (_, NormalFn) => Ok(NormalFn),
|
||||
(ExternFn, ExternFn) => Ok(ExternFn),
|
||||
(NormalFn, NormalFn) => Ok(NormalFn),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1200,7 +1200,7 @@ impl Clean<Item> for ast::ForeignItem {
|
||||
ForeignFunctionItem(Function {
|
||||
decl: decl.clean(),
|
||||
generics: generics.clean(),
|
||||
fn_style: ast::ExternFn,
|
||||
fn_style: ast::NormalFn,
|
||||
})
|
||||
}
|
||||
ast::ForeignItemStatic(ref ty, mutbl) => {
|
||||
|
@ -397,10 +397,10 @@ impl fmt::Show for clean::Type {
|
||||
clean::BareFunction(ref decl) => {
|
||||
write!(f.buf, "{}{}fn{}{}",
|
||||
FnStyleSpace(decl.fn_style),
|
||||
match decl.abi {
|
||||
ref x if "" == *x => "".to_owned(),
|
||||
ref x if "\"Rust\"" == *x => "".to_owned(),
|
||||
ref s => " " + *s + " ",
|
||||
match decl.abi.as_slice() {
|
||||
"" => " extern ".to_owned(),
|
||||
"\"Rust\"" => "".to_owned(),
|
||||
s => format!(" extern {} ", s)
|
||||
},
|
||||
decl.generics,
|
||||
decl.decl)
|
||||
@ -517,7 +517,6 @@ impl fmt::Show for FnStyleSpace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.get() {
|
||||
ast::UnsafeFn => write!(f.buf, "unsafe "),
|
||||
ast::ExternFn => write!(f.buf, "extern "),
|
||||
ast::NormalFn => Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -876,7 +876,6 @@ pub struct FnDecl {
|
||||
pub enum FnStyle {
|
||||
UnsafeFn, // declared with "unsafe fn"
|
||||
NormalFn, // declared with "fn"
|
||||
ExternFn, // declared with "extern fn"
|
||||
}
|
||||
|
||||
impl fmt::Show for FnStyle {
|
||||
@ -884,7 +883,6 @@ impl fmt::Show for FnStyle {
|
||||
match *self {
|
||||
NormalFn => "normal".fmt(f),
|
||||
UnsafeFn => "unsafe".fmt(f),
|
||||
ExternFn => "extern".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use ast::{ExprLit, ExprLoop, ExprMac};
|
||||
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
|
||||
use ast::{ExprVec, ExprVstore, ExprVstoreSlice};
|
||||
use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, ExternFn, Field, FnDecl};
|
||||
use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl};
|
||||
use ast::{ExprVstoreUniq, Once, Many};
|
||||
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
|
||||
use ast::{Ident, NormalFn, Inherited, Item, Item_, ItemStatic};
|
||||
@ -881,25 +881,29 @@ impl<'a> Parser<'a> {
|
||||
pub fn parse_ty_bare_fn(&mut self) -> Ty_ {
|
||||
/*
|
||||
|
||||
[extern "ABI"] [unsafe] fn <'lt> (S) -> T
|
||||
^~~~^ ^~~~~~~^ ^~~~^ ^~^ ^
|
||||
| | | | |
|
||||
| | | | Return type
|
||||
| | | Argument types
|
||||
| | Lifetimes
|
||||
| |
|
||||
| Function Style
|
||||
ABI
|
||||
|
||||
[unsafe] [extern "ABI"] fn <'lt> (S) -> T
|
||||
^~~~^ ^~~~^ ^~~~^ ^~^ ^
|
||||
| | | | |
|
||||
| | | | Return type
|
||||
| | | Argument types
|
||||
| | Lifetimes
|
||||
| ABI
|
||||
Function Style
|
||||
*/
|
||||
|
||||
let fn_style = self.parse_unsafety();
|
||||
let abi = if self.eat_keyword(keywords::Extern) {
|
||||
self.parse_opt_abi().unwrap_or(abi::C)
|
||||
} else {
|
||||
abi::Rust
|
||||
};
|
||||
|
||||
let fn_style = self.parse_unsafety();
|
||||
// NOTE: remove after a stage0 snapshot
|
||||
let fn_style = match self.parse_unsafety() {
|
||||
UnsafeFn => UnsafeFn,
|
||||
NormalFn => fn_style,
|
||||
};
|
||||
|
||||
self.expect_keyword(keywords::Fn);
|
||||
let (decl, lifetimes) = self.parse_ty_fn_decl(true);
|
||||
return TyBareFn(@BareFnTy {
|
||||
@ -1245,6 +1249,7 @@ impl<'a> Parser<'a> {
|
||||
self.expect_and();
|
||||
self.parse_borrowed_pointee()
|
||||
} else if self.is_keyword(keywords::Extern) ||
|
||||
self.is_keyword(keywords::Unsafe) ||
|
||||
self.token_is_bare_fn_keyword() {
|
||||
// BARE FUNCTION
|
||||
self.parse_ty_bare_fn()
|
||||
@ -4551,7 +4556,7 @@ impl<'a> Parser<'a> {
|
||||
// EXTERN FUNCTION ITEM
|
||||
let abi = opt_abi.unwrap_or(abi::C);
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(ExternFn, abi);
|
||||
self.parse_item_fn(NormalFn, abi);
|
||||
let item = self.mk_item(lo,
|
||||
self.last_span.hi,
|
||||
ident,
|
||||
@ -4605,9 +4610,14 @@ impl<'a> Parser<'a> {
|
||||
&& self.look_ahead(1u, |t| *t != token::LBRACE) {
|
||||
// UNSAFE FUNCTION ITEM
|
||||
self.bump();
|
||||
let abi = if self.eat_keyword(keywords::Extern) {
|
||||
self.parse_opt_abi().unwrap_or(abi::C)
|
||||
} else {
|
||||
abi::Rust
|
||||
};
|
||||
self.expect_keyword(keywords::Fn);
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(UnsafeFn, abi::Rust);
|
||||
self.parse_item_fn(UnsafeFn, abi);
|
||||
let item = self.mk_item(lo,
|
||||
self.last_span.hi,
|
||||
ident,
|
||||
|
@ -2372,16 +2372,10 @@ impl<'a> State<'a> {
|
||||
abi: abi::Abi,
|
||||
vis: ast::Visibility) -> IoResult<()> {
|
||||
try!(word(&mut self.s, visibility_qualified(vis, "")));
|
||||
|
||||
try!(self.print_opt_fn_style(opt_fn_style));
|
||||
if abi != abi::Rust {
|
||||
try!(self.word_nbsp("extern"));
|
||||
try!(self.word_nbsp(abi.to_str()));
|
||||
|
||||
if opt_fn_style != Some(ast::ExternFn) {
|
||||
try!(self.print_opt_fn_style(opt_fn_style));
|
||||
}
|
||||
} else {
|
||||
try!(self.print_opt_fn_style(opt_fn_style));
|
||||
}
|
||||
|
||||
word(&mut self.s, "fn")
|
||||
@ -2391,7 +2385,6 @@ impl<'a> State<'a> {
|
||||
match s {
|
||||
ast::NormalFn => Ok(()),
|
||||
ast::UnsafeFn => self.word_nbsp("unsafe"),
|
||||
ast::ExternFn => self.word_nbsp("extern")
|
||||
}
|
||||
}
|
||||
|
||||
|
17
src/test/run-pass/issue-10025.rs
Normal file
17
src/test/run-pass/issue-10025.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
unsafe extern fn foo() {}
|
||||
unsafe extern "C" fn bar() {}
|
||||
|
||||
fn main() {
|
||||
let _a: unsafe extern fn() = foo;
|
||||
let _a: unsafe extern "C" fn() = foo;
|
||||
}
|
Loading…
Reference in New Issue
Block a user