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
|
UnsafeFn, // u
|
||||||
StaticMethod, // F
|
StaticMethod, // F
|
||||||
UnsafeStaticMethod, // U
|
UnsafeStaticMethod, // U
|
||||||
ForeignFn, // e
|
|
||||||
Type, // y
|
Type, // y
|
||||||
ForeignType, // T
|
ForeignType, // T
|
||||||
Mod, // m
|
Mod, // m
|
||||||
@ -134,7 +133,6 @@ fn item_family(item: ebml::Doc) -> Family {
|
|||||||
'u' => UnsafeFn,
|
'u' => UnsafeFn,
|
||||||
'F' => StaticMethod,
|
'F' => StaticMethod,
|
||||||
'U' => UnsafeStaticMethod,
|
'U' => UnsafeStaticMethod,
|
||||||
'e' => ForeignFn,
|
|
||||||
'y' => Type,
|
'y' => Type,
|
||||||
'T' => ForeignType,
|
'T' => ForeignType,
|
||||||
'm' => Mod,
|
'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)),
|
Struct => DlDef(ast::DefStruct(did)),
|
||||||
UnsafeFn => DlDef(ast::DefFn(did, ast::UnsafeFn)),
|
UnsafeFn => DlDef(ast::DefFn(did, ast::UnsafeFn)),
|
||||||
Fn => DlDef(ast::DefFn(did, ast::NormalFn)),
|
Fn => DlDef(ast::DefFn(did, ast::NormalFn)),
|
||||||
ForeignFn => DlDef(ast::DefFn(did, ast::ExternFn)),
|
|
||||||
StaticMethod | UnsafeStaticMethod => {
|
StaticMethod | UnsafeStaticMethod => {
|
||||||
let fn_style = if fam == UnsafeStaticMethod { ast::UnsafeFn } else
|
let fn_style = if fam == UnsafeStaticMethod { ast::UnsafeFn } else
|
||||||
{ ast::NormalFn };
|
{ ast::NormalFn };
|
||||||
|
@ -787,7 +787,6 @@ fn style_fn_family(s: FnStyle) -> char {
|
|||||||
match s {
|
match s {
|
||||||
UnsafeFn => 'u',
|
UnsafeFn => 'u',
|
||||||
NormalFn => 'f',
|
NormalFn => 'f',
|
||||||
ExternFn => 'e'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,7 +794,6 @@ fn fn_style_static_method_family(s: FnStyle) -> char {
|
|||||||
match s {
|
match s {
|
||||||
UnsafeFn => 'U',
|
UnsafeFn => 'U',
|
||||||
NormalFn => 'F',
|
NormalFn => 'F',
|
||||||
_ => fail!("extern fn can't be static")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,7 +441,6 @@ fn parse_fn_style(c: char) -> FnStyle {
|
|||||||
match c {
|
match c {
|
||||||
'u' => UnsafeFn,
|
'u' => UnsafeFn,
|
||||||
'n' => NormalFn,
|
'n' => NormalFn,
|
||||||
'c' => ExternFn,
|
|
||||||
_ => fail!("parse_fn_style: bad fn_style {}", c)
|
_ => fail!("parse_fn_style: bad fn_style {}", c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,6 @@ fn enc_fn_style(w: &mut MemWriter, p: FnStyle) {
|
|||||||
match p {
|
match p {
|
||||||
NormalFn => mywrite!(w, "n"),
|
NormalFn => mywrite!(w, "n"),
|
||||||
UnsafeFn => mywrite!(w, "u"),
|
UnsafeFn => mywrite!(w, "u"),
|
||||||
ExternFn => mywrite!(w, "c")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ use middle::privacy;
|
|||||||
use util::nodemap::NodeSet;
|
use util::nodemap::NodeSet;
|
||||||
|
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
|
use syntax::abi;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ast_map;
|
use syntax::ast_map;
|
||||||
use syntax::ast_util::{def_id_of_def, is_local};
|
use syntax::ast_util::{def_id_of_def, is_local};
|
||||||
@ -250,8 +251,10 @@ impl<'a> ReachableContext<'a> {
|
|||||||
match *node {
|
match *node {
|
||||||
ast_map::NodeItem(item) => {
|
ast_map::NodeItem(item) => {
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemFn(_, ast::ExternFn, _, _, _) => {
|
ast::ItemFn(_, _, abi, _, _) => {
|
||||||
self.reachable_symbols.insert(search_item);
|
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) {
|
pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
|
||||||
let _icx = push_ctxt("trans_item");
|
let _icx = push_ctxt("trans_item");
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemFn(decl, fn_style, _abi, ref generics, body) => {
|
ast::ItemFn(decl, _fn_style, abi, ref generics, body) => {
|
||||||
if fn_style == ast::ExternFn {
|
if abi != Rust {
|
||||||
let llfndecl = get_item_val(ccx, item.id);
|
let llfndecl = get_item_val(ccx, item.id);
|
||||||
foreign::trans_rust_fn_with_foreign_abi(
|
foreign::trans_rust_fn_with_foreign_abi(
|
||||||
ccx, decl, body, item.attrs.as_slice(), llfndecl, item.id);
|
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, _, _, _) => {
|
ast::ItemFn(_, _, abi, _, _) => {
|
||||||
let llfn = if fn_style != ast::ExternFn {
|
let llfn = if abi == Rust {
|
||||||
register_fn(ccx, i.span, sym, i.id, ty)
|
register_fn(ccx, i.span, sym, i.id, ty)
|
||||||
} else {
|
} else {
|
||||||
foreign::register_rust_fn_with_foreign_abi(ccx,
|
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 {
|
match fn_style {
|
||||||
ast::UnsafeFn => 1u,
|
ast::UnsafeFn => 1u,
|
||||||
ast::NormalFn => 2u,
|
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::{TypeTrace, Subtype};
|
||||||
use middle::typeck::infer::fold_regions_in_sig;
|
use middle::typeck::infer::fold_regions_in_sig;
|
||||||
use syntax::ast::{Many, Once, MutImmutable, MutMutable};
|
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 syntax::ast::{Onceness, FnStyle};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use util::common::{indenter};
|
use util::common::{indenter};
|
||||||
@ -83,7 +83,6 @@ impl<'f> Combine for Glb<'f> {
|
|||||||
|
|
||||||
fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
|
fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(ExternFn, _) | (_, ExternFn) => Ok(ExternFn),
|
|
||||||
(NormalFn, _) | (_, NormalFn) => Ok(NormalFn),
|
(NormalFn, _) | (_, NormalFn) => Ok(NormalFn),
|
||||||
(UnsafeFn, UnsafeFn) => Ok(UnsafeFn)
|
(UnsafeFn, UnsafeFn) => Ok(UnsafeFn)
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ use middle::typeck::infer::fold_regions_in_sig;
|
|||||||
use middle::typeck::infer::{TypeTrace, Subtype};
|
use middle::typeck::infer::{TypeTrace, Subtype};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use syntax::ast::{Many, Once, NodeId};
|
use syntax::ast::{Many, Once, NodeId};
|
||||||
use syntax::ast::{ExternFn, NormalFn, UnsafeFn};
|
use syntax::ast::{NormalFn, UnsafeFn};
|
||||||
use syntax::ast::{Onceness, FnStyle};
|
use syntax::ast::{Onceness, FnStyle};
|
||||||
use util::ppaux::mt_to_str;
|
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> {
|
fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(UnsafeFn, _) | (_, UnsafeFn) => Ok(UnsafeFn),
|
(UnsafeFn, _) | (_, UnsafeFn) => Ok(UnsafeFn),
|
||||||
(NormalFn, _) | (_, NormalFn) => Ok(NormalFn),
|
(NormalFn, NormalFn) => Ok(NormalFn),
|
||||||
(ExternFn, ExternFn) => Ok(ExternFn),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1200,7 +1200,7 @@ impl Clean<Item> for ast::ForeignItem {
|
|||||||
ForeignFunctionItem(Function {
|
ForeignFunctionItem(Function {
|
||||||
decl: decl.clean(),
|
decl: decl.clean(),
|
||||||
generics: generics.clean(),
|
generics: generics.clean(),
|
||||||
fn_style: ast::ExternFn,
|
fn_style: ast::NormalFn,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ast::ForeignItemStatic(ref ty, mutbl) => {
|
ast::ForeignItemStatic(ref ty, mutbl) => {
|
||||||
|
@ -397,10 +397,10 @@ impl fmt::Show for clean::Type {
|
|||||||
clean::BareFunction(ref decl) => {
|
clean::BareFunction(ref decl) => {
|
||||||
write!(f.buf, "{}{}fn{}{}",
|
write!(f.buf, "{}{}fn{}{}",
|
||||||
FnStyleSpace(decl.fn_style),
|
FnStyleSpace(decl.fn_style),
|
||||||
match decl.abi {
|
match decl.abi.as_slice() {
|
||||||
ref x if "" == *x => "".to_owned(),
|
"" => " extern ".to_owned(),
|
||||||
ref x if "\"Rust\"" == *x => "".to_owned(),
|
"\"Rust\"" => "".to_owned(),
|
||||||
ref s => " " + *s + " ",
|
s => format!(" extern {} ", s)
|
||||||
},
|
},
|
||||||
decl.generics,
|
decl.generics,
|
||||||
decl.decl)
|
decl.decl)
|
||||||
@ -517,7 +517,6 @@ impl fmt::Show for FnStyleSpace {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.get() {
|
match self.get() {
|
||||||
ast::UnsafeFn => write!(f.buf, "unsafe "),
|
ast::UnsafeFn => write!(f.buf, "unsafe "),
|
||||||
ast::ExternFn => write!(f.buf, "extern "),
|
|
||||||
ast::NormalFn => Ok(())
|
ast::NormalFn => Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -876,7 +876,6 @@ pub struct FnDecl {
|
|||||||
pub enum FnStyle {
|
pub enum FnStyle {
|
||||||
UnsafeFn, // declared with "unsafe fn"
|
UnsafeFn, // declared with "unsafe fn"
|
||||||
NormalFn, // declared with "fn"
|
NormalFn, // declared with "fn"
|
||||||
ExternFn, // declared with "extern fn"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Show for FnStyle {
|
impl fmt::Show for FnStyle {
|
||||||
@ -884,7 +883,6 @@ impl fmt::Show for FnStyle {
|
|||||||
match *self {
|
match *self {
|
||||||
NormalFn => "normal".fmt(f),
|
NormalFn => "normal".fmt(f),
|
||||||
UnsafeFn => "unsafe".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::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
||||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
|
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
|
||||||
use ast::{ExprVec, ExprVstore, ExprVstoreSlice};
|
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::{ExprVstoreUniq, Once, Many};
|
||||||
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
|
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
|
||||||
use ast::{Ident, NormalFn, Inherited, Item, Item_, ItemStatic};
|
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_ {
|
pub fn parse_ty_bare_fn(&mut self) -> Ty_ {
|
||||||
/*
|
/*
|
||||||
|
|
||||||
[extern "ABI"] [unsafe] fn <'lt> (S) -> T
|
[unsafe] [extern "ABI"] fn <'lt> (S) -> T
|
||||||
^~~~^ ^~~~~~~^ ^~~~^ ^~^ ^
|
^~~~^ ^~~~^ ^~~~^ ^~^ ^
|
||||||
| | | | |
|
| | | | |
|
||||||
| | | | Return type
|
| | | | Return type
|
||||||
| | | Argument types
|
| | | Argument types
|
||||||
| | Lifetimes
|
| | Lifetimes
|
||||||
| |
|
| ABI
|
||||||
| Function Style
|
Function Style
|
||||||
ABI
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
let fn_style = self.parse_unsafety();
|
||||||
let abi = if self.eat_keyword(keywords::Extern) {
|
let abi = if self.eat_keyword(keywords::Extern) {
|
||||||
self.parse_opt_abi().unwrap_or(abi::C)
|
self.parse_opt_abi().unwrap_or(abi::C)
|
||||||
} else {
|
} else {
|
||||||
abi::Rust
|
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);
|
self.expect_keyword(keywords::Fn);
|
||||||
let (decl, lifetimes) = self.parse_ty_fn_decl(true);
|
let (decl, lifetimes) = self.parse_ty_fn_decl(true);
|
||||||
return TyBareFn(@BareFnTy {
|
return TyBareFn(@BareFnTy {
|
||||||
@ -1245,6 +1249,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.expect_and();
|
self.expect_and();
|
||||||
self.parse_borrowed_pointee()
|
self.parse_borrowed_pointee()
|
||||||
} else if self.is_keyword(keywords::Extern) ||
|
} else if self.is_keyword(keywords::Extern) ||
|
||||||
|
self.is_keyword(keywords::Unsafe) ||
|
||||||
self.token_is_bare_fn_keyword() {
|
self.token_is_bare_fn_keyword() {
|
||||||
// BARE FUNCTION
|
// BARE FUNCTION
|
||||||
self.parse_ty_bare_fn()
|
self.parse_ty_bare_fn()
|
||||||
@ -4551,7 +4556,7 @@ impl<'a> Parser<'a> {
|
|||||||
// EXTERN FUNCTION ITEM
|
// EXTERN FUNCTION ITEM
|
||||||
let abi = opt_abi.unwrap_or(abi::C);
|
let abi = opt_abi.unwrap_or(abi::C);
|
||||||
let (ident, item_, extra_attrs) =
|
let (ident, item_, extra_attrs) =
|
||||||
self.parse_item_fn(ExternFn, abi);
|
self.parse_item_fn(NormalFn, abi);
|
||||||
let item = self.mk_item(lo,
|
let item = self.mk_item(lo,
|
||||||
self.last_span.hi,
|
self.last_span.hi,
|
||||||
ident,
|
ident,
|
||||||
@ -4605,9 +4610,14 @@ impl<'a> Parser<'a> {
|
|||||||
&& self.look_ahead(1u, |t| *t != token::LBRACE) {
|
&& self.look_ahead(1u, |t| *t != token::LBRACE) {
|
||||||
// UNSAFE FUNCTION ITEM
|
// UNSAFE FUNCTION ITEM
|
||||||
self.bump();
|
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);
|
self.expect_keyword(keywords::Fn);
|
||||||
let (ident, item_, extra_attrs) =
|
let (ident, item_, extra_attrs) =
|
||||||
self.parse_item_fn(UnsafeFn, abi::Rust);
|
self.parse_item_fn(UnsafeFn, abi);
|
||||||
let item = self.mk_item(lo,
|
let item = self.mk_item(lo,
|
||||||
self.last_span.hi,
|
self.last_span.hi,
|
||||||
ident,
|
ident,
|
||||||
|
@ -2372,16 +2372,10 @@ impl<'a> State<'a> {
|
|||||||
abi: abi::Abi,
|
abi: abi::Abi,
|
||||||
vis: ast::Visibility) -> IoResult<()> {
|
vis: ast::Visibility) -> IoResult<()> {
|
||||||
try!(word(&mut self.s, visibility_qualified(vis, "")));
|
try!(word(&mut self.s, visibility_qualified(vis, "")));
|
||||||
|
try!(self.print_opt_fn_style(opt_fn_style));
|
||||||
if abi != abi::Rust {
|
if abi != abi::Rust {
|
||||||
try!(self.word_nbsp("extern"));
|
try!(self.word_nbsp("extern"));
|
||||||
try!(self.word_nbsp(abi.to_str()));
|
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")
|
word(&mut self.s, "fn")
|
||||||
@ -2391,7 +2385,6 @@ impl<'a> State<'a> {
|
|||||||
match s {
|
match s {
|
||||||
ast::NormalFn => Ok(()),
|
ast::NormalFn => Ok(()),
|
||||||
ast::UnsafeFn => self.word_nbsp("unsafe"),
|
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