Skip to content

Commit

Permalink
auto merge of #14005 : alexcrichton/rust/extern-unsafe, r=pcwalton
Browse files Browse the repository at this point in the history
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]
  • Loading branch information
bors committed May 7, 2014
2 parents 828ffab + 08237ca commit c217a84
Show file tree
Hide file tree
Showing 15 changed files with 59 additions and 49 deletions.
3 changes: 0 additions & 3 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ enum Family {
UnsafeFn, // u
StaticMethod, // F
UnsafeStaticMethod, // U
ForeignFn, // e
Type, // y
ForeignType, // T
Mod, // m
Expand All @@ -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,
Expand Down Expand Up @@ -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 };
Expand Down
2 changes: 0 additions & 2 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,15 +788,13 @@ fn style_fn_family(s: FnStyle) -> char {
match s {
UnsafeFn => 'u',
NormalFn => 'f',
ExternFn => 'e'
}
}

fn fn_style_static_method_family(s: FnStyle) -> char {
match s {
UnsafeFn => 'U',
NormalFn => 'F',
_ => fail!("extern fn can't be static")
}
}

Expand Down
1 change: 0 additions & 1 deletion src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
1 change: 0 additions & 1 deletion src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ fn enc_fn_style(w: &mut MemWriter, p: FnStyle) {
match p {
NormalFn => mywrite!(w, "n"),
UnsafeFn => mywrite!(w, "u"),
ExternFn => mywrite!(w, "c")
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/librustc/middle/reachable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
}
}
_ => {}
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion src/librustc/middle/trans/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
3 changes: 1 addition & 2 deletions src/librustc/middle/typeck/infer/glb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)
}
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/middle/typeck/infer/lub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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),
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,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) => {
Expand Down
9 changes: 4 additions & 5 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(())
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,15 +876,13 @@ 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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
NormalFn => "normal".fmt(f),
UnsafeFn => "unsafe".fmt(f),
ExternFn => "extern".fmt(f),
}
}
}
Expand Down
38 changes: 24 additions & 14 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -884,25 +884,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 {
Expand Down Expand Up @@ -1256,6 +1260,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()
Expand Down Expand Up @@ -4563,7 +4568,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,
Expand Down Expand Up @@ -4617,9 +4622,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,
Expand Down
9 changes: 1 addition & 8 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/test/run-pass/issue-10025.rs
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit c217a84

Please sign in to comment.