Add AbiSet and integrate it into the AST.
I believe this patch incorporates all expected syntax changes from extern function reform (#3678). You can now write things like: extern "<abi>" fn foo(s: S) -> T { ... } extern "<abi>" mod { ... } extern "<abi>" fn(S) -> T The ABI for foreign functions is taken from this syntax (rather than from an annotation). We support the full ABI specification I described on the mailing list. The correct ABI is chosen based on the target architecture. Calls by pointer to C functions are not yet supported, and the Rust type of crust fns is still *u8.
This commit is contained in:
parent
f864934f54
commit
6965fe4bce
72 changed files with 879 additions and 352 deletions
|
@ -13,7 +13,7 @@
|
|||
pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
#[link_name = "rusti"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
fn forget<T>(+x: T);
|
||||
fn reinterpret_cast<T, U>(&&e: T) -> U;
|
||||
}
|
||||
|
|
|
@ -1617,7 +1617,7 @@ pub mod funcs {
|
|||
use libc::types::os::arch::extra::{HANDLE};
|
||||
|
||||
#[abi = "stdcall"]
|
||||
pub extern {
|
||||
pub extern "stdcall" {
|
||||
unsafe fn GetEnvironmentVariableW(n: LPCWSTR,
|
||||
v: LPWSTR,
|
||||
nsize: DWORD)
|
||||
|
|
|
@ -942,7 +942,7 @@ pub fn errno() -> uint {
|
|||
|
||||
#[link_name = "kernel32"]
|
||||
#[abi = "stdcall"]
|
||||
extern {
|
||||
extern "stdcall" {
|
||||
unsafe fn GetLastError() -> DWORD;
|
||||
}
|
||||
|
||||
|
@ -1004,7 +1004,7 @@ pub fn last_os_error() -> ~str {
|
|||
|
||||
#[link_name = "kernel32"]
|
||||
#[abi = "stdcall"]
|
||||
extern {
|
||||
extern "stdcall" {
|
||||
unsafe fn FormatMessageA(flags: DWORD, lpSrc: LPVOID,
|
||||
msgId: DWORD, langId: DWORD,
|
||||
buf: LPSTR, nsize: DWORD,
|
||||
|
@ -1118,7 +1118,7 @@ type LPCWSTR = *u16;
|
|||
#[cfg(windows)]
|
||||
#[link_name="kernel32"]
|
||||
#[abi="stdcall"]
|
||||
extern {
|
||||
extern "stdcall" {
|
||||
fn GetCommandLineW() -> LPCWSTR;
|
||||
fn LocalFree(ptr: *c_void);
|
||||
}
|
||||
|
@ -1126,7 +1126,7 @@ extern {
|
|||
#[cfg(windows)]
|
||||
#[link_name="shell32"]
|
||||
#[abi="stdcall"]
|
||||
extern {
|
||||
extern "stdcall" {
|
||||
fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ pub mod libc_ {
|
|||
|
||||
pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
fn addr_of<T>(&&val: T) -> *T;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ pub unsafe fn get(key: Key) -> *mut c_void {
|
|||
|
||||
#[cfg(windows)]
|
||||
#[abi = "stdcall"]
|
||||
extern {
|
||||
extern "stdcall" {
|
||||
fn TlsAlloc() -> DWORD;
|
||||
fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
|
||||
fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
|
||||
|
|
|
@ -94,7 +94,7 @@ pub mod rustrt {
|
|||
|
||||
pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn frame_address(f: &once fn(x: *u8));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ pub struct Closure {
|
|||
|
||||
pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
fn get_tydesc<T>() -> *();
|
||||
fn size_of<T>() -> uint;
|
||||
fn pref_align_of<T>() -> uint;
|
||||
|
|
|
@ -15,7 +15,7 @@ The intrinsics are defined in librustc/middle/trans/foreign.rs.
|
|||
*/
|
||||
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
|
||||
pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
|
||||
pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;
|
||||
|
|
|
@ -97,7 +97,7 @@ pub mod jit {
|
|||
pub mod rusti {
|
||||
#[nolink]
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn morestack_addr() -> *();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ use std::getopts::groups::{optopt, optmulti, optflag, optflagopt, getopts};
|
|||
use std::getopts::{opt_present};
|
||||
use std::getopts;
|
||||
use syntax::ast;
|
||||
use syntax::abi;
|
||||
use syntax::attr;
|
||||
use syntax::codemap;
|
||||
use syntax::diagnostic;
|
||||
|
@ -85,10 +86,10 @@ pub fn default_configuration(sess: Session, +argv0: ~str, input: input) ->
|
|||
// ARM is bi-endian, however using NDK seems to default
|
||||
// to little-endian unless a flag is provided.
|
||||
let (end,arch,wordsz) = match sess.targ_cfg.arch {
|
||||
session::arch_x86 => (~"little",~"x86",~"32"),
|
||||
session::arch_x86_64 => (~"little",~"x86_64",~"64"),
|
||||
session::arch_arm => (~"little",~"arm",~"32"),
|
||||
session::arch_mips => (~"little",~"arm",~"32")
|
||||
abi::X86 => (~"little",~"x86",~"32"),
|
||||
abi::X86_64 => (~"little",~"x86_64",~"64"),
|
||||
abi::Arm => (~"little",~"arm",~"32"),
|
||||
abi::Mips => (~"little",~"arm",~"32")
|
||||
};
|
||||
|
||||
return ~[ // Target bindings.
|
||||
|
@ -308,7 +309,7 @@ pub fn compile_rest(sess: Session, cfg: ast::crate_cfg,
|
|||
};
|
||||
|
||||
// NOTE: Android hack
|
||||
if sess.targ_cfg.arch == session::arch_arm &&
|
||||
if sess.targ_cfg.arch == abi::Arm &&
|
||||
(sess.opts.output_type == link::output_type_object ||
|
||||
sess.opts.output_type == link::output_type_exe) {
|
||||
let output_type = link::output_type_assembly;
|
||||
|
@ -453,20 +454,20 @@ pub fn get_os(triple: &str) -> Option<session::os> {
|
|||
} else { None }
|
||||
}
|
||||
|
||||
pub fn get_arch(triple: &str) -> Option<session::arch> {
|
||||
pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
|
||||
if str::contains(triple, ~"i386") ||
|
||||
str::contains(triple, ~"i486") ||
|
||||
str::contains(triple, ~"i586") ||
|
||||
str::contains(triple, ~"i686") ||
|
||||
str::contains(triple, ~"i786") {
|
||||
Some(session::arch_x86)
|
||||
Some(abi::X86)
|
||||
} else if str::contains(triple, ~"x86_64") {
|
||||
Some(session::arch_x86_64)
|
||||
Some(abi::X86_64)
|
||||
} else if str::contains(triple, ~"arm") ||
|
||||
str::contains(triple, ~"xscale") {
|
||||
Some(session::arch_arm)
|
||||
Some(abi::Arm)
|
||||
} else if str::contains(triple, ~"mips") {
|
||||
Some(session::arch_mips)
|
||||
Some(abi::Mips)
|
||||
} else { None }
|
||||
}
|
||||
|
||||
|
@ -483,16 +484,16 @@ pub fn build_target_config(sopts: @session::options,
|
|||
~"unknown architecture: " + sopts.target_triple)
|
||||
};
|
||||
let (int_type, uint_type, float_type) = match arch {
|
||||
session::arch_x86 => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
|
||||
session::arch_x86_64 => (ast::ty_i64, ast::ty_u64, ast::ty_f64),
|
||||
session::arch_arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
|
||||
session::arch_mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
|
||||
abi::X86 => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
|
||||
abi::X86_64 => (ast::ty_i64, ast::ty_u64, ast::ty_f64),
|
||||
abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
|
||||
abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
|
||||
};
|
||||
let target_strs = match arch {
|
||||
session::arch_x86 => x86::get_target_strs(os),
|
||||
session::arch_x86_64 => x86_64::get_target_strs(os),
|
||||
session::arch_arm => arm::get_target_strs(os),
|
||||
session::arch_mips => mips::get_target_strs(os)
|
||||
abi::X86 => x86::get_target_strs(os),
|
||||
abi::X86_64 => x86_64::get_target_strs(os),
|
||||
abi::Arm => arm::get_target_strs(os),
|
||||
abi::Mips => mips::get_target_strs(os)
|
||||
};
|
||||
let target_cfg = @session::config {
|
||||
os: os,
|
||||
|
|
|
@ -25,19 +25,17 @@ use syntax::codemap::span;
|
|||
use syntax::diagnostic;
|
||||
use syntax::parse::ParseSess;
|
||||
use syntax::{ast, codemap};
|
||||
use syntax::abi;
|
||||
use syntax;
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum os { os_win32, os_macos, os_linux, os_android, os_freebsd, }
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum arch { arch_x86, arch_x86_64, arch_arm, arch_mips, }
|
||||
|
||||
pub enum crate_type { bin_crate, lib_crate, unknown_crate, }
|
||||
|
||||
pub struct config {
|
||||
os: os,
|
||||
arch: arch,
|
||||
arch: abi::Architecture,
|
||||
target_strs: target_strs::t,
|
||||
int_type: int_ty,
|
||||
uint_type: uint_ty,
|
||||
|
|
|
@ -92,7 +92,7 @@ fn fold_foreign_mod(
|
|||
nm.view_items.filter_mapped(|a| filter_view_item(cx, *a));
|
||||
ast::foreign_mod {
|
||||
sort: nm.sort,
|
||||
abi: nm.abi,
|
||||
abis: nm.abis,
|
||||
view_items: vec::map(filtered_view_items, |x| fld.fold_view_item(*x)),
|
||||
items: filtered_items
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ pub mod intrinsic {
|
|||
use super::{TyDesc, TyVisitor};
|
||||
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn get_tydesc<T>() -> *();
|
||||
pub fn visit_tydesc(++td: *TyDesc, &&tv: @TyVisitor);
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ fn fold_item(cx: @mut TestCtxt, &&i: @ast::item, fld: @fold::ast_fold)
|
|||
|
||||
if is_test_fn(i) || is_bench_fn(i) {
|
||||
match i.node {
|
||||
ast::item_fn(_, purity, _, _) if purity == ast::unsafe_fn => {
|
||||
ast::item_fn(_, purity, _, _, _) if purity == ast::unsafe_fn => {
|
||||
let sess = cx.sess;
|
||||
sess.span_fatal(
|
||||
i.span,
|
||||
|
@ -178,7 +178,7 @@ fn is_test_fn(i: @ast::item) -> bool {
|
|||
|
||||
fn has_test_signature(i: @ast::item) -> bool {
|
||||
match &i.node {
|
||||
&ast::item_fn(ref decl, _, ref generics, _) => {
|
||||
&ast::item_fn(ref decl, _, _, ref generics, _) => {
|
||||
let no_output = match decl.output.node {
|
||||
ast::ty_nil => true,
|
||||
_ => false
|
||||
|
@ -200,7 +200,7 @@ fn is_bench_fn(i: @ast::item) -> bool {
|
|||
|
||||
fn has_test_signature(i: @ast::item) -> bool {
|
||||
match i.node {
|
||||
ast::item_fn(ref decl, _, ref generics, _) => {
|
||||
ast::item_fn(ref decl, _, _, ref generics, _) => {
|
||||
let input_cnt = vec::len(decl.inputs);
|
||||
let no_output = match decl.output.node {
|
||||
ast::ty_nil => true,
|
||||
|
|
|
@ -156,12 +156,8 @@ fn visit_view_item(e: @mut Env, i: @ast::view_item) {
|
|||
fn visit_item(e: @mut Env, i: @ast::item) {
|
||||
match i.node {
|
||||
ast::item_foreign_mod(ref fm) => {
|
||||
match attr::foreign_abi(i.attrs) {
|
||||
either::Right(abi) => {
|
||||
if abi != ast::foreign_abi_cdecl &&
|
||||
abi != ast::foreign_abi_stdcall { return; }
|
||||
}
|
||||
either::Left(ref msg) => e.diag.span_fatal(i.span, (*msg))
|
||||
if fm.abis.is_rust() || fm.abis.is_intrinsic() {
|
||||
return;
|
||||
}
|
||||
|
||||
let cstore = e.cstore;
|
||||
|
|
|
@ -35,6 +35,7 @@ use core::uint;
|
|||
use core::vec;
|
||||
use std::serialize::Encodable;
|
||||
use std;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::ast::*;
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
|
@ -653,7 +654,7 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
|
|||
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
item_fn(_, purity, ref generics, _) => {
|
||||
item_fn(_, purity, _, ref generics, _) => {
|
||||
add_to_index();
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, local_def(item.id));
|
||||
|
@ -979,7 +980,7 @@ fn encode_info_for_foreign_item(ecx: @EncodeContext,
|
|||
nitem: @foreign_item,
|
||||
index: @mut ~[entry<int>],
|
||||
+path: ast_map::path,
|
||||
abi: foreign_abi) {
|
||||
abi: AbiSet) {
|
||||
if !reachable(ecx, nitem.id) { return; }
|
||||
index.push(entry { val: nitem.id, pos: ebml_w.writer.tell() });
|
||||
|
||||
|
@ -990,7 +991,7 @@ fn encode_info_for_foreign_item(ecx: @EncodeContext,
|
|||
encode_family(ebml_w, purity_fn_family(purity));
|
||||
encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
|
||||
encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
|
||||
if abi == foreign_abi_rust_intrinsic {
|
||||
if abi.is_intrinsic() {
|
||||
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem));
|
||||
} else {
|
||||
encode_symbol(ecx, ebml_w, nitem.id);
|
||||
|
|
|
@ -21,6 +21,8 @@ use middle::ty;
|
|||
use core::str;
|
||||
use core::uint;
|
||||
use core::vec;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast::*;
|
||||
use syntax::codemap::dummy_sp;
|
||||
|
@ -76,6 +78,20 @@ fn next_byte(st: @mut PState) -> u8 {
|
|||
return b;
|
||||
}
|
||||
|
||||
fn scan<R>(st: &mut PState, is_last: &fn(char) -> bool,
|
||||
op: &fn(&[u8]) -> R) -> R
|
||||
{
|
||||
let start_pos = st.pos;
|
||||
debug!("scan: '%c' (start)", st.data[st.pos] as char);
|
||||
while !is_last(st.data[st.pos] as char) {
|
||||
st.pos += 1;
|
||||
debug!("scan: '%c'", st.data[st.pos] as char);
|
||||
}
|
||||
let end_pos = st.pos;
|
||||
st.pos += 1;
|
||||
return op(st.data.slice(start_pos, end_pos));
|
||||
}
|
||||
|
||||
pub fn parse_ident(st: @mut PState, last: char) -> ast::ident {
|
||||
fn is_last(b: char, c: char) -> bool { return c == b; }
|
||||
return parse_ident_(st, |a| is_last(last, a) );
|
||||
|
@ -83,10 +99,7 @@ pub fn parse_ident(st: @mut PState, last: char) -> ast::ident {
|
|||
|
||||
fn parse_ident_(st: @mut PState, is_last: @fn(char) -> bool) ->
|
||||
ast::ident {
|
||||
let mut rslt = ~"";
|
||||
while !is_last(peek(st)) {
|
||||
rslt += str::from_byte(next_byte(st));
|
||||
}
|
||||
let rslt = scan(st, is_last, str::from_bytes);
|
||||
return st.tcx.sess.ident_of(rslt);
|
||||
}
|
||||
|
||||
|
@ -417,11 +430,17 @@ fn parse_purity(c: char) -> purity {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_abi(c: char) -> Abi {
|
||||
match c {
|
||||
'r' => ast::RustAbi,
|
||||
_ => fail!(fmt!("parse_abi: bad ABI '%c'", c))
|
||||
fn parse_abi_set(st: @mut PState) -> AbiSet {
|
||||
assert!(next(st) == '[');
|
||||
let mut abis = AbiSet::empty();
|
||||
while peek(st) != ']' {
|
||||
// FIXME(#5422) str API should not force this copy
|
||||
let abi_str = scan(st, |c| c == ',', str::from_bytes);
|
||||
let abi = abi::lookup(abi_str).expect(abi_str);
|
||||
abis.add(abi);
|
||||
}
|
||||
assert!(next(st) == ']');
|
||||
return abis;
|
||||
}
|
||||
|
||||
fn parse_onceness(c: char) -> ast::Onceness {
|
||||
|
@ -462,11 +481,11 @@ fn parse_closure_ty(st: @mut PState, conv: conv_did) -> ty::ClosureTy {
|
|||
|
||||
fn parse_bare_fn_ty(st: @mut PState, conv: conv_did) -> ty::BareFnTy {
|
||||
let purity = parse_purity(next(st));
|
||||
let abi = parse_abi(next(st));
|
||||
let abi = parse_abi_set(st);
|
||||
let sig = parse_sig(st, conv);
|
||||
ty::BareFnTy {
|
||||
purity: purity,
|
||||
abi: abi,
|
||||
abis: abi,
|
||||
sig: sig
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ use core::io::WriterUtil;
|
|||
use core::io;
|
||||
use core::uint;
|
||||
use core::vec;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::ast::*;
|
||||
use syntax::diagnostic::span_handler;
|
||||
use syntax::print::pprust::*;
|
||||
|
@ -367,10 +368,13 @@ fn enc_purity(w: @io::Writer, p: purity) {
|
|||
}
|
||||
}
|
||||
|
||||
fn enc_abi(w: @io::Writer, a: Abi) {
|
||||
match a {
|
||||
RustAbi => w.write_char('r'),
|
||||
fn enc_abi_set(w: @io::Writer, abis: AbiSet) {
|
||||
w.write_char('[');
|
||||
for abis.each |abi| {
|
||||
w.write_str(abi.name());
|
||||
w.write_char(',');
|
||||
}
|
||||
w.write_char(']')
|
||||
}
|
||||
|
||||
fn enc_onceness(w: @io::Writer, o: Onceness) {
|
||||
|
@ -382,7 +386,7 @@ fn enc_onceness(w: @io::Writer, o: Onceness) {
|
|||
|
||||
fn enc_bare_fn_ty(w: @io::Writer, cx: @ctxt, ft: &ty::BareFnTy) {
|
||||
enc_purity(w, ft.purity);
|
||||
enc_abi(w, ft.abi);
|
||||
enc_abi_set(w, ft.abis);
|
||||
enc_fn_sig(w, cx, &ft.sig);
|
||||
}
|
||||
|
||||
|
|
|
@ -762,9 +762,7 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) {
|
|||
}
|
||||
|
||||
match it.node {
|
||||
ast::item_foreign_mod(ref nmod)
|
||||
if attr::foreign_abi(it.attrs) !=
|
||||
either::Right(ast::foreign_abi_rust_intrinsic) => {
|
||||
ast::item_foreign_mod(ref nmod) if !nmod.abis.is_intrinsic() => {
|
||||
for nmod.items.each |ni| {
|
||||
match ni.node {
|
||||
ast::foreign_item_fn(ref decl, _, _) => {
|
||||
|
|
|
@ -1139,7 +1139,7 @@ pub impl Resolver {
|
|||
name_bindings.define_value
|
||||
(privacy, def_const(local_def(item.id)), sp);
|
||||
}
|
||||
item_fn(_, purity, _, _) => {
|
||||
item_fn(_, purity, _, _, _) => {
|
||||
let (name_bindings, new_parent) =
|
||||
self.add_child(ident, parent, ForbidDuplicateValues, sp);
|
||||
|
||||
|
@ -3530,7 +3530,7 @@ pub impl Resolver {
|
|||
}
|
||||
}
|
||||
|
||||
item_fn(ref fn_decl, _, ref generics, ref block) => {
|
||||
item_fn(ref fn_decl, _, _, ref generics, ref block) => {
|
||||
// If this is the main function, we must record it in the
|
||||
// session.
|
||||
// FIXME #4404 android JNI hacks
|
||||
|
|
|
@ -82,6 +82,7 @@ use syntax::parse::token::special_idents;
|
|||
use syntax::print::pprust::stmt_to_str;
|
||||
use syntax::visit;
|
||||
use syntax::{ast, ast_util, codemap, ast_map};
|
||||
use syntax::abi::{X86, X86_64, Arm, Mips};
|
||||
|
||||
pub struct icx_popper {
|
||||
ccx: @CrateContext,
|
||||
|
@ -1455,10 +1456,12 @@ pub fn call_memcpy(cx: block, dst: ValueRef, src: ValueRef,
|
|||
let _icx = cx.insn_ctxt("call_memcpy");
|
||||
let ccx = cx.ccx();
|
||||
let key = match ccx.sess.targ_cfg.arch {
|
||||
session::arch_x86
|
||||
| session::arch_arm
|
||||
| session::arch_mips => ~"llvm.memcpy.p0i8.p0i8.i32",
|
||||
session::arch_x86_64 => ~"llvm.memcpy.p0i8.p0i8.i64"
|
||||
X86 | Arm | Mips => {
|
||||
~"llvm.memcpy.p0i8.p0i8.i32"
|
||||
}
|
||||
X86_64 => {
|
||||
~"llvm.memcpy.p0i8.p0i8.i64"
|
||||
}
|
||||
};
|
||||
let memcpy = *ccx.intrinsics.get(&key);
|
||||
let src_ptr = PointerCast(cx, src, T_ptr(T_i8()));
|
||||
|
@ -1499,12 +1502,10 @@ pub fn memzero(cx: block, llptr: ValueRef, llty: TypeRef) {
|
|||
|
||||
let intrinsic_key;
|
||||
match ccx.sess.targ_cfg.arch {
|
||||
session::arch_x86
|
||||
| session::arch_arm
|
||||
| session::arch_mips => {
|
||||
X86 | Arm | Mips => {
|
||||
intrinsic_key = ~"llvm.memset.p0i8.i32";
|
||||
}
|
||||
session::arch_x86_64 => {
|
||||
X86_64 => {
|
||||
intrinsic_key = ~"llvm.memset.p0i8.i64";
|
||||
}
|
||||
}
|
||||
|
@ -2063,7 +2064,7 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) {
|
|||
_ => fail!(~"trans_item"),
|
||||
};
|
||||
match item.node {
|
||||
ast::item_fn(ref decl, purity, ref generics, ref body) => {
|
||||
ast::item_fn(ref decl, purity, _abis, ref generics, ref body) => {
|
||||
if purity == ast::extern_fn {
|
||||
let llfndecl = get_item_val(ccx, item.id);
|
||||
foreign::trans_foreign_fn(ccx,
|
||||
|
@ -2105,11 +2106,7 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) {
|
|||
}
|
||||
ast::item_const(_, expr) => consts::trans_const(ccx, expr, item.id),
|
||||
ast::item_foreign_mod(ref foreign_mod) => {
|
||||
let abi = match attr::foreign_abi(item.attrs) {
|
||||
Right(abi_) => abi_,
|
||||
Left(msg) => ccx.sess.span_fatal(item.span, msg)
|
||||
};
|
||||
foreign::trans_foreign_mod(ccx, foreign_mod, abi);
|
||||
foreign::trans_foreign_mod(ccx, path, foreign_mod);
|
||||
}
|
||||
ast::item_struct(struct_def, ref generics) => {
|
||||
if !generics.is_type_parameterized() {
|
||||
|
@ -2405,7 +2402,7 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef {
|
|||
g
|
||||
}
|
||||
}
|
||||
ast::item_fn(_, purity, _, _) => {
|
||||
ast::item_fn(_, purity, _, _, _) => {
|
||||
let llfn = if purity != ast::extern_fn {
|
||||
register_fn(ccx, i.span, my_path, i.id, i.attrs)
|
||||
} else {
|
||||
|
|
|
@ -269,11 +269,8 @@ pub fn trans_fn_ref_with_vtables(
|
|||
|| fmt!("local item should be in ast map"));
|
||||
|
||||
match *map_node {
|
||||
ast_map::node_foreign_item(_,
|
||||
ast::foreign_abi_rust_intrinsic,
|
||||
_,
|
||||
_) => {
|
||||
must_monomorphise = true;
|
||||
ast_map::node_foreign_item(_, abis, _, _) => {
|
||||
must_monomorphise = abis.is_intrinsic()
|
||||
}
|
||||
_ => {
|
||||
must_monomorphise = false;
|
||||
|
|
|
@ -57,6 +57,7 @@ use syntax::ast_map::{path, path_elt};
|
|||
use syntax::codemap::span;
|
||||
use syntax::parse::token::ident_interner;
|
||||
use syntax::{ast, ast_map};
|
||||
use syntax::abi::{X86, X86_64, Arm, Mips};
|
||||
|
||||
pub type namegen = @fn(+s: ~str) -> ident;
|
||||
pub fn new_namegen(intr: @ident_interner) -> namegen {
|
||||
|
@ -777,10 +778,10 @@ pub fn T_bool() -> TypeRef { return T_i8(); }
|
|||
|
||||
pub fn T_int(targ_cfg: @session::config) -> TypeRef {
|
||||
return match targ_cfg.arch {
|
||||
session::arch_x86 => T_i32(),
|
||||
session::arch_x86_64 => T_i64(),
|
||||
session::arch_arm => T_i32(),
|
||||
session::arch_mips => T_i32()
|
||||
X86 => T_i32(),
|
||||
X86_64 => T_i64(),
|
||||
Arm => T_i32(),
|
||||
Mips => T_i32()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -815,10 +816,10 @@ pub fn T_float_ty(cx: @CrateContext, t: ast::float_ty) -> TypeRef {
|
|||
|
||||
pub fn T_float(targ_cfg: @session::config) -> TypeRef {
|
||||
return match targ_cfg.arch {
|
||||
session::arch_x86 => T_f64(),
|
||||
session::arch_x86_64 => T_f64(),
|
||||
session::arch_arm => T_f64(),
|
||||
session::arch_mips => T_f64()
|
||||
X86 => T_f64(),
|
||||
X86_64 => T_f64(),
|
||||
Arm => T_f64(),
|
||||
Mips => T_f64()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -852,7 +852,7 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata<SubProgramMetadata> {
|
|||
let (ident, ret_ty, id) = match *cx.tcx.items.get(&fcx.id) {
|
||||
ast_map::node_item(item, _) => {
|
||||
match item.node {
|
||||
ast::item_fn(ref decl, _, _, _) => {
|
||||
ast::item_fn(ref decl, _, _, _, _) => {
|
||||
(item.ident, decl.output, item.id)
|
||||
}
|
||||
_ => fcx.ccx.sess.span_bug(item.span, ~"create_function: item \
|
||||
|
|
|
@ -12,9 +12,6 @@ use core::prelude::*;
|
|||
|
||||
use back::{link, abi};
|
||||
use driver::session;
|
||||
use driver::session::arch_x86_64;
|
||||
use driver::session::arch_arm;
|
||||
use driver::session::arch_mips;
|
||||
use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
|
||||
use lib::llvm::{TypeRef, ValueRef};
|
||||
use lib;
|
||||
|
@ -42,13 +39,16 @@ use syntax::{ast, ast_util};
|
|||
use syntax::{attr, ast_map};
|
||||
use syntax::opt_vec;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::abi::{Architecture, X86, X86_64, Arm, Mips};
|
||||
use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall,
|
||||
Cdecl, Aapcs, C};
|
||||
|
||||
fn abi_info(arch: session::arch) -> @cabi::ABIInfo {
|
||||
fn abi_info(arch: Architecture) -> @cabi::ABIInfo {
|
||||
return match arch {
|
||||
arch_x86_64 => x86_64_abi_info(),
|
||||
arch_arm => cabi_arm::abi_info(),
|
||||
arch_mips => mips_abi_info(),
|
||||
_ => cabi::llvm_abi_info()
|
||||
X86_64 => x86_64_abi_info(),
|
||||
Arm => cabi_arm::abi_info(),
|
||||
Mips => mips_abi_info(),
|
||||
X86 => cabi::llvm_abi_info()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,37 +239,66 @@ fn build_wrap_fn_(ccx: @CrateContext,
|
|||
// unnecessary). We used to do this, in fact, and will perhaps do so
|
||||
// in the future.
|
||||
pub fn trans_foreign_mod(ccx: @CrateContext,
|
||||
foreign_mod: &ast::foreign_mod,
|
||||
abi: ast::foreign_abi)
|
||||
path: &ast_map::path,
|
||||
foreign_mod: &ast::foreign_mod)
|
||||
{
|
||||
let _icx = ccx.insn_ctxt("foreign::trans_foreign_mod");
|
||||
|
||||
let mut cc = match abi {
|
||||
ast::foreign_abi_rust_intrinsic |
|
||||
ast::foreign_abi_cdecl => lib::llvm::CCallConv,
|
||||
ast::foreign_abi_stdcall => lib::llvm::X86StdcallCallConv
|
||||
let arch = ccx.sess.targ_cfg.arch;
|
||||
let abi = match foreign_mod.abis.for_arch(arch) {
|
||||
None => {
|
||||
ccx.sess.fatal(
|
||||
fmt!("No suitable ABI for target architecture \
|
||||
in module %s",
|
||||
ast_map::path_to_str(*path,
|
||||
ccx.sess.intr())));
|
||||
}
|
||||
|
||||
Some(abi) => abi,
|
||||
};
|
||||
|
||||
for vec::each(foreign_mod.items) |foreign_item| {
|
||||
for vec::each(foreign_mod.items) |&foreign_item| {
|
||||
match foreign_item.node {
|
||||
ast::foreign_item_fn(*) => {
|
||||
let id = foreign_item.id;
|
||||
if abi != ast::foreign_abi_rust_intrinsic {
|
||||
let llwrapfn = get_item_val(ccx, id);
|
||||
let tys = shim_types(ccx, id);
|
||||
if attr::attrs_contains_name(
|
||||
foreign_item.attrs, "rust_stack")
|
||||
{
|
||||
build_direct_fn(ccx, llwrapfn, *foreign_item,
|
||||
&tys, cc);
|
||||
} else {
|
||||
let llshimfn = build_shim_fn(ccx, *foreign_item,
|
||||
&tys, cc);
|
||||
build_wrap_fn(ccx, &tys, llshimfn, llwrapfn);
|
||||
}
|
||||
} else {
|
||||
match abi {
|
||||
RustIntrinsic => {
|
||||
// Intrinsics are emitted by monomorphic fn
|
||||
}
|
||||
|
||||
Rust => {
|
||||
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
|
||||
ccx.sess.unimpl(
|
||||
fmt!("Foreign functions with Rust ABI"));
|
||||
}
|
||||
|
||||
Stdcall => {
|
||||
build_foreign_fn(ccx, id, foreign_item,
|
||||
lib::llvm::X86StdcallCallConv);
|
||||
}
|
||||
|
||||
Fastcall => {
|
||||
build_foreign_fn(ccx, id, foreign_item,
|
||||
lib::llvm::X86FastcallCallConv);
|
||||
}
|
||||
|
||||
Cdecl => {
|
||||
// FIXME(#3678) should really be more specific
|
||||
build_foreign_fn(ccx, id, foreign_item,
|
||||
lib::llvm::CCallConv);
|
||||
}
|
||||
|
||||
Aapcs => {
|
||||
// FIXME(#3678) should really be more specific
|
||||
build_foreign_fn(ccx, id, foreign_item,
|
||||
lib::llvm::CCallConv);
|
||||
}
|
||||
|
||||
C => {
|
||||
build_foreign_fn(ccx, id, foreign_item,
|
||||
lib::llvm::CCallConv);
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::foreign_item_const(*) => {
|
||||
let ident = ccx.sess.parse_sess.interner.get(
|
||||
|
@ -279,6 +308,25 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
|
|||
}
|
||||
}
|
||||
|
||||
fn build_foreign_fn(ccx: @CrateContext,
|
||||
id: ast::node_id,
|
||||
foreign_item: @ast::foreign_item,
|
||||
cc: lib::llvm::CallConv)
|
||||
{
|
||||
let llwrapfn = get_item_val(ccx, id);
|
||||
let tys = shim_types(ccx, id);
|
||||
if attr::attrs_contains_name(
|
||||
foreign_item.attrs, "rust_stack")
|
||||
{
|
||||
build_direct_fn(ccx, llwrapfn, foreign_item,
|
||||
&tys, cc);
|
||||
} else {
|
||||
let llshimfn = build_shim_fn(ccx, foreign_item,
|
||||
&tys, cc);
|
||||
build_wrap_fn(ccx, &tys, llshimfn, llwrapfn);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_shim_fn(ccx: @CrateContext,
|
||||
foreign_item: @ast::foreign_item,
|
||||
tys: &ShimTypes,
|
||||
|
@ -1080,20 +1128,3 @@ pub fn register_foreign_fn(ccx: @CrateContext,
|
|||
t, lib::llvm::CCallConv, fnty)
|
||||
}
|
||||
}
|
||||
|
||||
fn abi_of_foreign_fn(ccx: @CrateContext, i: @ast::foreign_item)
|
||||
-> ast::foreign_abi {
|
||||
match attr::first_attr_value_str_by_name(i.attrs, ~"abi") {
|
||||
None => match *ccx.tcx.items.get(&i.id) {
|
||||
ast_map::node_foreign_item(_, abi, _, _) => abi,
|
||||
// ??
|
||||
_ => fail!(~"abi_of_foreign_fn: not foreign")
|
||||
},
|
||||
Some(_) => match attr::foreign_abi(i.attrs) {
|
||||
either::Right(abi) => abi,
|
||||
either::Left(ref msg) => {
|
||||
ccx.sess.span_fatal(i.span, (/*bad*/copy *msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ use syntax::ast_map::path_name;
|
|||
use syntax::ast_util::local_def;
|
||||
use syntax::opt_vec;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::abi::AbiSet;
|
||||
|
||||
pub fn monomorphic_fn(ccx: @CrateContext,
|
||||
fn_id: ast::def_id,
|
||||
|
@ -97,7 +98,7 @@ pub fn monomorphic_fn(ccx: @CrateContext,
|
|||
ast_map::node_item(i, pt) => (pt, i.ident, i.span),
|
||||
ast_map::node_variant(ref v, enm, pt) => (pt, (*v).node.name, enm.span),
|
||||
ast_map::node_method(m, _, pt) => (pt, m.ident, m.span),
|
||||
ast_map::node_foreign_item(i, ast::foreign_abi_rust_intrinsic, _, pt)
|
||||
ast_map::node_foreign_item(i, abis, _, pt) if abis.is_intrinsic()
|
||||
=> (pt, i.ident, i.span),
|
||||
ast_map::node_foreign_item(*) => {
|
||||
// Foreign externs don't have to be monomorphized.
|
||||
|
@ -174,8 +175,7 @@ pub fn monomorphic_fn(ccx: @CrateContext,
|
|||
|
||||
let lldecl = match *map_node {
|
||||
ast_map::node_item(i@@ast::item {
|
||||
// XXX: Bad copy.
|
||||
node: ast::item_fn(ref decl, _, _, ref body),
|
||||
node: ast::item_fn(ref decl, _, _, _, ref body),
|
||||
_
|
||||
}, _) => {
|
||||
let d = mk_lldecl();
|
||||
|
@ -280,7 +280,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
|
|||
tcx,
|
||||
ty::BareFnTy {
|
||||
purity: ast::impure_fn,
|
||||
abi: ast::RustAbi,
|
||||
abis: AbiSet::Rust(),
|
||||
sig: FnSig {bound_lifetime_names: opt_vec::Empty,
|
||||
inputs: ~[],
|
||||
output: ty::mk_nil(tcx)}}))
|
||||
|
|
|
@ -108,7 +108,7 @@ fn traverse_public_item(cx: ctx, item: @item) {
|
|||
}
|
||||
}
|
||||
}
|
||||
item_fn(_, _, ref generics, ref blk) => {
|
||||
item_fn(_, _, _, ref generics, ref blk) => {
|
||||
if generics.ty_params.len() > 0u ||
|
||||
attr::find_inline_attr(item.attrs) != attr::ia_none {
|
||||
traverse_inline_body(cx, blk);
|
||||
|
|
|
@ -102,7 +102,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
|
|||
fn_id_loc))
|
||||
};
|
||||
match map_node {
|
||||
ast_map::node_item(@ast::item { node: item_fn(_, _, _, ref body),
|
||||
ast_map::node_item(@ast::item { node: item_fn(_, _, _, _, ref body),
|
||||
_ }, _) |
|
||||
ast_map::node_method(@ast::method {body: ref body, _}, _, _) => {
|
||||
handle_body(cx, body);
|
||||
|
@ -121,7 +121,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
|
|||
abi,
|
||||
_,
|
||||
_) => {
|
||||
if abi == foreign_abi_rust_intrinsic {
|
||||
if abi.is_intrinsic() {
|
||||
let flags = match *cx.ccx.sess.str_of(i.ident) {
|
||||
~"size_of" | ~"pref_align_of" | ~"min_align_of" |
|
||||
~"init" | ~"reinterpret_cast" |
|
||||
|
|
|
@ -47,6 +47,7 @@ use syntax::print::pprust;
|
|||
use syntax::{ast, ast_map};
|
||||
use syntax::opt_vec::OptVec;
|
||||
use syntax::opt_vec;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax;
|
||||
|
||||
// Data types
|
||||
|
@ -349,7 +350,7 @@ pub fn type_id(t: t) -> uint { get(t).id }
|
|||
#[deriving(Eq)]
|
||||
pub struct BareFnTy {
|
||||
purity: ast::purity,
|
||||
abi: Abi,
|
||||
abis: AbiSet,
|
||||
sig: FnSig
|
||||
}
|
||||
|
||||
|
@ -378,7 +379,7 @@ pub struct FnSig {
|
|||
|
||||
impl to_bytes::IterBytes for BareFnTy {
|
||||
fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
|
||||
to_bytes::iter_bytes_3(&self.purity, &self.abi, &self.sig, lsb0, f)
|
||||
to_bytes::iter_bytes_3(&self.purity, &self.abis, &self.sig, lsb0, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,7 +547,7 @@ pub enum type_err {
|
|||
terr_mismatch,
|
||||
terr_purity_mismatch(expected_found<purity>),
|
||||
terr_onceness_mismatch(expected_found<Onceness>),
|
||||
terr_abi_mismatch(expected_found<ast::Abi>),
|
||||
terr_abi_mismatch(expected_found<AbiSet>),
|
||||
terr_mutability,
|
||||
terr_sigil_mismatch(expected_found<ast::Sigil>),
|
||||
terr_box_mutability,
|
||||
|
@ -1056,7 +1057,7 @@ pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t {
|
|||
mk_bare_fn(cx,
|
||||
BareFnTy {
|
||||
purity: ast::pure_fn,
|
||||
abi: ast::RustAbi,
|
||||
abis: AbiSet::Rust(),
|
||||
sig: FnSig {bound_lifetime_names: opt_vec::Empty,
|
||||
inputs: input_args,
|
||||
output: output}})
|
||||
|
@ -1240,7 +1241,7 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty {
|
|||
}
|
||||
ty_bare_fn(ref f) => {
|
||||
let sig = fold_sig(&f.sig, fldop);
|
||||
ty_bare_fn(BareFnTy {sig: sig, abi: f.abi, purity: f.purity})
|
||||
ty_bare_fn(BareFnTy {sig: sig, abis: f.abis, purity: f.purity})
|
||||
}
|
||||
ty_closure(ref f) => {
|
||||
let sig = fold_sig(&f.sig, fldop);
|
||||
|
|
|
@ -64,6 +64,7 @@ use middle::typeck::rscope::RegionParamNames;
|
|||
|
||||
use core::result;
|
||||
use core::vec;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::{ast, ast_util};
|
||||
use syntax::codemap::span;
|
||||
use syntax::opt_vec::OptVec;
|
||||
|
@ -348,7 +349,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + Durable>(
|
|||
}
|
||||
ast::ty_bare_fn(ref bf) => {
|
||||
ty::mk_bare_fn(tcx, ty_of_bare_fn(self, rscope, bf.purity,
|
||||
bf.abi, &bf.lifetimes, &bf.decl))
|
||||
bf.abis, &bf.lifetimes, &bf.decl))
|
||||
}
|
||||
ast::ty_closure(ref f) => {
|
||||
let fn_decl = ty_of_closure(self,
|
||||
|
@ -543,7 +544,7 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
|
|||
self: &AC,
|
||||
rscope: &RS,
|
||||
purity: ast::purity,
|
||||
abi: ast::Abi,
|
||||
abi: AbiSet,
|
||||
lifetimes: &OptVec<ast::Lifetime>,
|
||||
decl: &ast::fn_decl) -> ty::BareFnTy
|
||||
{
|
||||
|
@ -562,7 +563,7 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
|
|||
|
||||
ty::BareFnTy {
|
||||
purity: purity,
|
||||
abi: abi,
|
||||
abis: abi,
|
||||
sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names,
|
||||
inputs: input_tys,
|
||||
output: output_ty}
|
||||
|
|
|
@ -118,7 +118,8 @@ use core::result;
|
|||
use core::str;
|
||||
use core::vec;
|
||||
use std::list::Nil;
|
||||
use syntax::ast::{provided, required};
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::ast::{provided, required, ty_i};
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::local_def;
|
||||
|
@ -567,7 +568,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
|
|||
enum_definition.variants,
|
||||
it.id);
|
||||
}
|
||||
ast::item_fn(ref decl, _, _, ref body) => {
|
||||
ast::item_fn(ref decl, _, _, _, ref body) => {
|
||||
check_bare_fn(ccx, decl, body, it.id, None);
|
||||
}
|
||||
ast::item_impl(ref generics, _, ty, ref ms) => {
|
||||
|
@ -603,8 +604,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
|
|||
check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
|
||||
}
|
||||
ast::item_foreign_mod(ref m) => {
|
||||
if syntax::attr::foreign_abi(it.attrs) ==
|
||||
either::Right(ast::foreign_abi_rust_intrinsic) {
|
||||
if m.abis.is_intrinsic() {
|
||||
for m.items.each |item| {
|
||||
check_intrinsic_type(ccx, *item);
|
||||
}
|
||||
|
@ -1145,6 +1145,19 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
|||
|
||||
let formal_tys;
|
||||
|
||||
// FIXME(#3678) For now, do not permit calls to C abi functions.
|
||||
match structure_of(fcx, sp, in_fty) {
|
||||
ty::ty_bare_fn(ty::BareFnTy {abis, _}) => {
|
||||
if !abis.is_rust() {
|
||||
tcx.sess.span_err(
|
||||
sp,
|
||||
fmt!("Calls to C ABI functions are not (yet) \
|
||||
supported; be patient, dear user"));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// This is subtle: we expect `fty` to be a function type, which
|
||||
// normally introduce a level of binding. In this case, we want to
|
||||
// process the types bound by the function but not by any nested
|
||||
|
@ -3672,7 +3685,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
|
|||
};
|
||||
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
|
||||
purity: ast::unsafe_fn,
|
||||
abi: ast::RustAbi,
|
||||
abis: AbiSet::Rust(),
|
||||
sig: FnSig {bound_lifetime_names: opt_vec::Empty,
|
||||
inputs: inputs,
|
||||
output: output}
|
||||
|
|
|
@ -33,7 +33,7 @@ are represented as `ty_param()` instances.
|
|||
use core::prelude::*;
|
||||
|
||||
use metadata::csearch;
|
||||
use middle::ty::InstantiatedTraitRef;
|
||||
use middle::ty::{InstantiatedTraitRef, arg};
|
||||
use middle::ty::{substs, ty_param_bounds_and_ty, ty_param_substs_and_ty};
|
||||
use middle::ty;
|
||||
use middle::typeck::astconv::{AstConv, ty_of_arg};
|
||||
|
@ -48,6 +48,7 @@ use util::common::{indenter, pluralize};
|
|||
use util::ppaux;
|
||||
|
||||
use core::vec;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
|
@ -707,7 +708,7 @@ pub fn convert_struct(ccx: &CrateCtxt,
|
|||
ccx,
|
||||
&type_rscope(region_parameterization),
|
||||
ast::impure_fn,
|
||||
ast::RustAbi,
|
||||
AbiSet::Rust(),
|
||||
&opt_vec::Empty,
|
||||
&ast_util::dtor_dec()));
|
||||
write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
|
||||
|
@ -776,7 +777,7 @@ pub fn ty_of_method(ccx: &CrateCtxt,
|
|||
fty: astconv::ty_of_bare_fn(ccx,
|
||||
&rscope,
|
||||
m.purity,
|
||||
ast::RustAbi,
|
||||
AbiSet::Rust(),
|
||||
&method_generics.lifetimes,
|
||||
&m.decl),
|
||||
self_ty: m.self_ty.node,
|
||||
|
@ -798,7 +799,7 @@ pub fn ty_of_ty_method(self: &CrateCtxt,
|
|||
fty: astconv::ty_of_bare_fn(self,
|
||||
&rscope,
|
||||
m.purity,
|
||||
ast::RustAbi,
|
||||
AbiSet::Rust(),
|
||||
&m.generics.lifetimes,
|
||||
&m.decl),
|
||||
// assume public, because this is only invoked on trait methods
|
||||
|
@ -859,12 +860,12 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item)
|
|||
tcx.tcache.insert(local_def(it.id), tpt);
|
||||
return tpt;
|
||||
}
|
||||
ast::item_fn(ref decl, purity, ref generics, _) => {
|
||||
ast::item_fn(ref decl, purity, abi, ref generics, _) => {
|
||||
let bounds = ty_param_bounds(ccx, generics);
|
||||
let tofd = astconv::ty_of_bare_fn(ccx,
|
||||
&empty_rscope,
|
||||
purity,
|
||||
ast::RustAbi,
|
||||
AbiSet::Rust(),
|
||||
&generics.lifetimes,
|
||||
decl);
|
||||
let tpt = ty_param_bounds_and_ty {
|
||||
|
@ -1040,7 +1041,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
|
|||
let t_fn = ty::mk_bare_fn(
|
||||
ccx.tcx,
|
||||
ty::BareFnTy {
|
||||
abi: ast::RustAbi,
|
||||
abis: AbiSet::Rust(),
|
||||
purity: ast::unsafe_fn,
|
||||
sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
|
||||
inputs: input_tys,
|
||||
|
|
|
@ -66,9 +66,9 @@ we may want to adjust precisely when coercions occur.
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn};
|
||||
use middle::ty::{AutoDerefRef, AutoRef};
|
||||
use middle::ty::{vstore_slice, vstore_box, vstore_uniq};
|
||||
use middle::ty::{TyVar, AutoPtr, AutoBorrowVec, AutoBorrowFn};
|
||||
use middle::ty::{AutoAdjustment, AutoDerefRef, AutoRef};
|
||||
use middle::ty::{vstore_slice, vstore_box, vstore_uniq, vstore_fixed};
|
||||
use middle::ty::{mt};
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::{CoerceResult, resolve_type};
|
||||
|
@ -76,9 +76,10 @@ use middle::typeck::infer::combine::CombineFields;
|
|||
use middle::typeck::infer::sub::Sub;
|
||||
use middle::typeck::infer::to_str::InferStr;
|
||||
use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
|
||||
use util::common::indenter;
|
||||
use util::common::{indent, indenter};
|
||||
|
||||
use syntax::ast::m_imm;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::ast::{m_const, m_imm, m_mutbl};
|
||||
use syntax::ast;
|
||||
|
||||
// Note: Coerce is not actually a combiner, in that it does not
|
||||
|
@ -334,9 +335,19 @@ pub impl Coerce {
|
|||
b: ty::t,
|
||||
sty_b: &ty::sty) -> CoerceResult
|
||||
{
|
||||
/*!
|
||||
*
|
||||
* Attempts to coerce from a bare Rust function (`extern
|
||||
* "rust" fn`) into a closure.
|
||||
*/
|
||||
|
||||
debug!("coerce_from_bare_fn(a=%s, b=%s)",
|
||||
a.inf_str(self.infcx), b.inf_str(self.infcx));
|
||||
|
||||
if !fn_ty_a.abis.is_rust() {
|
||||
return self.subtype(a, b);
|
||||
}
|
||||
|
||||
let fn_ty_b = match *sty_b {
|
||||
ty::ty_closure(ref f) => {copy *f}
|
||||
_ => {
|
||||
|
@ -344,8 +355,6 @@ pub impl Coerce {
|
|||
}
|
||||
};
|
||||
|
||||
// for now, bare fn and closures have the same
|
||||
// representation
|
||||
let adj = @ty::AutoAddEnv(fn_ty_b.region, fn_ty_b.sigil);
|
||||
let a_closure = ty::mk_closure(
|
||||
self.infcx.tcx,
|
||||
|
|
|
@ -72,6 +72,7 @@ use syntax::ast::{Onceness, purity};
|
|||
use syntax::ast;
|
||||
use syntax::opt_vec;
|
||||
use syntax::codemap::span;
|
||||
use syntax::abi::AbiSet;
|
||||
|
||||
pub trait Combine {
|
||||
fn infcx(&self) -> @mut InferCtxt;
|
||||
|
@ -101,7 +102,7 @@ pub trait Combine {
|
|||
fn args(&self, a: ty::arg, b: ty::arg) -> cres<ty::arg>;
|
||||
fn sigils(&self, p1: ast::Sigil, p2: ast::Sigil) -> cres<ast::Sigil>;
|
||||
fn purities(&self, a: purity, b: purity) -> cres<purity>;
|
||||
fn abis(&self, a: ast::Abi, b: ast::Abi) -> cres<ast::Abi>;
|
||||
fn abis(&self, a: AbiSet, b: AbiSet) -> cres<AbiSet>;
|
||||
fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>;
|
||||
fn contraregions(&self, a: ty::Region, b: ty::Region)
|
||||
-> cres<ty::Region>;
|
||||
|
@ -396,7 +397,7 @@ pub fn super_closure_tys<C:Combine>(
|
|||
}
|
||||
|
||||
pub fn super_abis<C:Combine>(
|
||||
self: &C, a: ast::Abi, b: ast::Abi) -> cres<ast::Abi>
|
||||
self: &C, a: AbiSet, b: AbiSet) -> cres<AbiSet>
|
||||
{
|
||||
if a == b {
|
||||
Ok(a)
|
||||
|
@ -409,10 +410,10 @@ pub fn super_bare_fn_tys<C:Combine>(
|
|||
self: &C, a_f: &ty::BareFnTy, b_f: &ty::BareFnTy) -> cres<ty::BareFnTy>
|
||||
{
|
||||
let purity = if_ok!(self.purities(a_f.purity, b_f.purity));
|
||||
let abi = if_ok!(self.abis(a_f.abi, b_f.abi));
|
||||
let abi = if_ok!(self.abis(a_f.abis, b_f.abis));
|
||||
let sig = if_ok!(self.fn_sigs(&a_f.sig, &b_f.sig));
|
||||
Ok(ty::BareFnTy {purity: purity,
|
||||
abi: abi,
|
||||
abis: abi,
|
||||
sig: sig})
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,9 @@ use middle::typeck::infer::{cres, InferCtxt};
|
|||
use middle::typeck::isr_alist;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl};
|
||||
use syntax::ast::{pure_fn, unsafe_fn, Onceness, purity};
|
||||
use syntax::ast::{noreturn, pure_fn, ret_style, return_val, unsafe_fn};
|
||||
use syntax::ast::{Onceness, purity};
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::codemap::span;
|
||||
use util::common::{indent, indenter};
|
||||
use util::ppaux::mt_to_str;
|
||||
|
@ -283,7 +285,7 @@ impl Combine for Glb {
|
|||
super_sigils(self, p1, p2)
|
||||
}
|
||||
|
||||
fn abis(&self, p1: ast::Abi, p2: ast::Abi) -> cres<ast::Abi> {
|
||||
fn abis(&self, p1: AbiSet, p2: AbiSet) -> cres<AbiSet> {
|
||||
super_abis(self, p1, p2)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ use util::common::indent;
|
|||
use util::ppaux::mt_to_str;
|
||||
|
||||
use std::list;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{Many, Once, extern_fn, m_const, impure_fn};
|
||||
use syntax::ast::{pure_fn, unsafe_fn};
|
||||
|
@ -210,7 +211,7 @@ impl Combine for Lub {
|
|||
super_sigils(self, p1, p2)
|
||||
}
|
||||
|
||||
fn abis(&self, p1: ast::Abi, p2: ast::Abi) -> cres<ast::Abi> {
|
||||
fn abis(&self, p1: AbiSet, p2: AbiSet) -> cres<AbiSet> {
|
||||
super_abis(self, p1, p2)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ use util::ppaux::bound_region_to_str;
|
|||
|
||||
use std::list::Nil;
|
||||
use std::list;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{Onceness, m_const, purity};
|
||||
use syntax::codemap::span;
|
||||
|
@ -216,7 +217,7 @@ impl Combine for Sub {
|
|||
super_sigils(self, p1, p2)
|
||||
}
|
||||
|
||||
fn abis(&self, p1: ast::Abi, p2: ast::Abi) -> cres<ast::Abi> {
|
||||
fn abis(&self, p1: AbiSet, p2: AbiSet) -> cres<AbiSet> {
|
||||
super_abis(self, p1, p2)
|
||||
}
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ fn check_main_fn_ty(ccx: @mut CrateCtxt,
|
|||
match tcx.items.find(&main_id) {
|
||||
Some(&ast_map::node_item(it,_)) => {
|
||||
match it.node {
|
||||
ast::item_fn(_, _, ref ps, _)
|
||||
ast::item_fn(_, _, _, ref ps, _)
|
||||
if ps.is_parameterized() => {
|
||||
tcx.sess.span_err(
|
||||
main_span,
|
||||
|
|
|
@ -30,6 +30,7 @@ use syntax::print::pprust;
|
|||
use syntax::print::pprust::mode_to_str;
|
||||
use syntax::{ast, ast_util};
|
||||
use syntax::ast_map;
|
||||
use syntax::abi::AbiSet;
|
||||
|
||||
use core::str;
|
||||
use core::vec;
|
||||
|
@ -302,15 +303,14 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
|||
}
|
||||
fn bare_fn_to_str(cx: ctxt,
|
||||
purity: ast::purity,
|
||||
abi: ast::Abi,
|
||||
abis: AbiSet,
|
||||
ident: Option<ast::ident>,
|
||||
sig: &ty::FnSig) -> ~str
|
||||
{
|
||||
let mut s = ~"extern ";
|
||||
|
||||
match abi {
|
||||
ast::RustAbi => {}
|
||||
}
|
||||
s.push_str(abis.to_str());
|
||||
s.push_char(' ');
|
||||
|
||||
match purity {
|
||||
ast::impure_fn => {}
|
||||
|
@ -386,7 +386,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
|||
fn method_to_str(cx: ctxt, m: method) -> ~str {
|
||||
bare_fn_to_str(cx,
|
||||
m.fty.purity,
|
||||
m.fty.abi,
|
||||
m.fty.abis,
|
||||
Some(m.ident),
|
||||
&m.fty.sig) + ~";"
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
|||
closure_to_str(cx, f)
|
||||
}
|
||||
ty_bare_fn(ref f) => {
|
||||
bare_fn_to_str(cx, f.purity, f.abi, None, &f.sig)
|
||||
bare_fn_to_str(cx, f.purity, f.abis, None, &f.sig)
|
||||
}
|
||||
ty_infer(infer_ty) => infer_ty.to_str(),
|
||||
ty_err => ~"[type error]",
|
||||
|
|
|
@ -69,7 +69,7 @@ fn get_fn_sig(srv: astsrv::Srv, fn_id: doc::AstId) -> Option<~str> {
|
|||
match *ctxt.ast_map.get(&fn_id) {
|
||||
ast_map::node_item(@ast::item {
|
||||
ident: ident,
|
||||
node: ast::item_fn(ref decl, purity, ref tys, _), _
|
||||
node: ast::item_fn(ref decl, purity, _, ref tys, _), _
|
||||
}, _) |
|
||||
ast_map::node_foreign_item(@ast::foreign_item {
|
||||
ident: ident,
|
||||
|
|
|
@ -159,7 +159,7 @@ fn run(repl: Repl, input: ~str) -> Repl {
|
|||
|
||||
for crate.node.module.items.each |item| {
|
||||
match item.node {
|
||||
ast::item_fn(_, _, _, blk) => {
|
||||
ast::item_fn(_, _, _, _, blk) => {
|
||||
if item.ident == sess.ident_of(~"main") {
|
||||
opt = blk.node.expr;
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ impl PackageScript {
|
|||
// the build API.
|
||||
for crate.node.module.items.each |i| {
|
||||
match i.node {
|
||||
ast::item_fn(_, _, _, _) => {
|
||||
ast::item_fn(*) => {
|
||||
custom = true;
|
||||
|
||||
break;
|
||||
|
|
|
@ -48,7 +48,7 @@ use core::vec;
|
|||
|
||||
pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
fn move_val_init<T>(dst: &mut T, +src: T);
|
||||
fn needs_drop<T>() -> bool;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ use core::ptr::addr_of;
|
|||
use core::vec;
|
||||
|
||||
#[abi = "rust-intrinsic"]
|
||||
extern "C" mod rusti {
|
||||
extern "rust-intrinsic" mod rusti {
|
||||
fn move_val_init<T>(dst: &mut T, +src: T);
|
||||
fn init<T>() -> T;
|
||||
}
|
||||
|
|
427
src/libsyntax/abi.rs
Normal file
427
src/libsyntax/abi.rs
Normal file
|
@ -0,0 +1,427 @@
|
|||
// Copyright 2012-2013 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.
|
||||
|
||||
use core::prelude::*;
|
||||
use core::to_bytes;
|
||||
use core::to_str::ToStr;
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum Abi {
|
||||
// NB: This ordering MUST match the AbiDatas array below.
|
||||
// (This is ensured by the test indices_are_correct().)
|
||||
|
||||
// Single platform ABIs come first (`for_arch()` relies on this)
|
||||
Cdecl,
|
||||
Stdcall,
|
||||
Fastcall,
|
||||
Aapcs,
|
||||
|
||||
// Multiplatform ABIs second
|
||||
Rust,
|
||||
C,
|
||||
RustIntrinsic,
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum Architecture {
|
||||
// NB. You cannot change the ordering of these
|
||||
// constants without adjusting IntelBits below.
|
||||
// (This is ensured by the test indices_are_correct().)
|
||||
X86,
|
||||
X86_64,
|
||||
Arm,
|
||||
Mips
|
||||
}
|
||||
|
||||
// FIXME(#5423) After a snapshot, we can change these constants:
|
||||
// const IntelBits: u32 = (1 << (X86 as uint)) | (1 << X86_64 as uint));
|
||||
// const ArmBits: u32 = (1 << (Arm as uint));
|
||||
static IntelBits: u32 = 1 | 2;
|
||||
static ArmBits: u32 = 4;
|
||||
|
||||
struct AbiData {
|
||||
abi: Abi,
|
||||
|
||||
// Name of this ABI as we like it called.
|
||||
name: &'static str,
|
||||
|
||||
// Is it specific to a platform? If so, which one? Also, what is
|
||||
// the name that LLVM gives it (in case we disagree)
|
||||
abi_arch: AbiArchitecture
|
||||
}
|
||||
|
||||
enum AbiArchitecture {
|
||||
RustArch, // Not a real ABI (e.g., intrinsic)
|
||||
AllArch, // An ABI that specifies cross-platform defaults (e.g., "C")
|
||||
Archs(u32) // Multiple architectures (bitset)
|
||||
}
|
||||
|
||||
#[auto_encode]
|
||||
#[auto_decode]
|
||||
#[deriving(Eq)]
|
||||
pub struct AbiSet {
|
||||
priv bits: u32 // each bit represents one of the abis below
|
||||
}
|
||||
|
||||
static AbiDatas: &'static [AbiData] = &[
|
||||
// Platform-specific ABIs
|
||||
AbiData {abi: Cdecl, name: "cdecl", abi_arch: Archs(IntelBits)},
|
||||
AbiData {abi: Stdcall, name: "stdcall", abi_arch: Archs(IntelBits)},
|
||||
AbiData {abi: Fastcall, name:"fastcall", abi_arch: Archs(IntelBits)},
|
||||
AbiData {abi: Aapcs, name: "aapcs", abi_arch: Archs(ArmBits)},
|
||||
|
||||
// Cross-platform ABIs
|
||||
//
|
||||
// NB: Do not adjust this ordering without
|
||||
// adjusting the indices below.
|
||||
AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
|
||||
AbiData {abi: C, name: "C", abi_arch: AllArch},
|
||||
AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
|
||||
];
|
||||
|
||||
fn each_abi(op: &fn(abi: Abi) -> bool) {
|
||||
/*!
|
||||
*
|
||||
* Iterates through each of the defined ABIs.
|
||||
*/
|
||||
|
||||
for AbiDatas.each |abi_data| {
|
||||
if !op(abi_data.abi) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup(name: &str) -> Option<Abi> {
|
||||
/*!
|
||||
*
|
||||
* Returns the ABI with the given name (if any).
|
||||
*/
|
||||
|
||||
for each_abi |abi| {
|
||||
if name == abi.data().name {
|
||||
return Some(abi);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn all_names() -> ~[&'static str] {
|
||||
AbiDatas.map(|d| d.name)
|
||||
}
|
||||
|
||||
pub impl Abi {
|
||||
#[inline]
|
||||
fn index(&self) -> uint {
|
||||
*self as uint
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn data(&self) -> &'static AbiData {
|
||||
&AbiDatas[self.index()]
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
self.data().name
|
||||
}
|
||||
}
|
||||
|
||||
impl Architecture {
|
||||
fn bit(&self) -> u32 {
|
||||
1 << (*self as u32)
|
||||
}
|
||||
}
|
||||
|
||||
pub impl AbiSet {
|
||||
fn from(abi: Abi) -> AbiSet {
|
||||
AbiSet { bits: (1 << abi.index()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn Rust() -> AbiSet {
|
||||
AbiSet::from(Rust)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn C() -> AbiSet {
|
||||
AbiSet::from(C)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn Intrinsic() -> AbiSet {
|
||||
AbiSet::from(RustIntrinsic)
|
||||
}
|
||||
|
||||
fn default() -> AbiSet {
|
||||
AbiSet::C()
|
||||
}
|
||||
|
||||
fn empty() -> AbiSet {
|
||||
AbiSet { bits: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_rust(&self) -> bool {
|
||||
self.bits == 1 << Rust.index()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_c(&self) -> bool {
|
||||
self.bits == 1 << C.index()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_intrinsic(&self) -> bool {
|
||||
self.bits == 1 << RustIntrinsic.index()
|
||||
}
|
||||
|
||||
fn contains(&self, abi: Abi) -> bool {
|
||||
(self.bits & (1 << abi.index())) != 0
|
||||
}
|
||||
|
||||
fn subset_of(&self, other_abi_set: AbiSet) -> bool {
|
||||
(self.bits & other_abi_set.bits) == self.bits
|
||||
}
|
||||
|
||||
fn add(&mut self, abi: Abi) {
|
||||
self.bits |= (1 << abi.index());
|
||||
}
|
||||
|
||||
fn each(&self, op: &fn(abi: Abi) -> bool) {
|
||||
for each_abi |abi| {
|
||||
if self.contains(abi) {
|
||||
if !op(abi) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.bits == 0
|
||||
}
|
||||
|
||||
fn for_arch(&self, arch: Architecture) -> Option<Abi> {
|
||||
// NB---Single platform ABIs come first
|
||||
for self.each |abi| {
|
||||
let data = abi.data();
|
||||
match data.abi_arch {
|
||||
Archs(a) if (a & arch.bit()) != 0 => { return Some(abi); }
|
||||
Archs(_) => { }
|
||||
RustArch | AllArch => { return Some(abi); }
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn check_valid(&self) -> Option<(Abi, Abi)> {
|
||||
let mut abis = ~[];
|
||||
for self.each |abi| { abis.push(abi); }
|
||||
|
||||
for abis.eachi |i, abi| {
|
||||
let data = abi.data();
|
||||
for abis.slice(0, i).each |other_abi| {
|
||||
let other_data = other_abi.data();
|
||||
debug!("abis=(%?,%?) datas=(%?,%?)",
|
||||
abi, data.abi_arch,
|
||||
other_abi, other_data.abi_arch);
|
||||
match (&data.abi_arch, &other_data.abi_arch) {
|
||||
(&AllArch, &AllArch) => {
|
||||
// Two cross-architecture ABIs
|
||||
return Some((*abi, *other_abi));
|
||||
}
|
||||
(_, &RustArch) |
|
||||
(&RustArch, _) => {
|
||||
// Cannot combine Rust or Rust-Intrinsic with
|
||||
// anything else.
|
||||
return Some((*abi, *other_abi));
|
||||
}
|
||||
(&Archs(is), &Archs(js)) if (is & js) != 0 => {
|
||||
// Two ABIs for same architecture
|
||||
return Some((*abi, *other_abi));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
impl to_bytes::IterBytes for Abi {
|
||||
fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
|
||||
self.index().iter_bytes(lsb0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl to_bytes::IterBytes for AbiSet {
|
||||
fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
|
||||
self.bits.iter_bytes(lsb0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToStr for Abi {
|
||||
fn to_str(&self) -> ~str {
|
||||
self.data().name.to_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToStr for AbiSet {
|
||||
fn to_str(&self) -> ~str {
|
||||
unsafe { // so we can push to strs.
|
||||
let mut strs = ~[];
|
||||
for self.each |abi| {
|
||||
strs.push(abi.data().name);
|
||||
}
|
||||
fmt!("\"%s\"", str::connect_slices(strs, " "))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_Rust() {
|
||||
let abi = lookup("Rust");
|
||||
assert!(abi.is_some() && abi.get().data().name == "Rust");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_cdecl() {
|
||||
let abi = lookup("cdecl");
|
||||
assert!(abi.is_some() && abi.get().data().name == "cdecl");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_baz() {
|
||||
let abi = lookup("baz");
|
||||
assert!(abi.is_none());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn cannot_combine(n: Abi, m: Abi) {
|
||||
let mut set = AbiSet::empty();
|
||||
set.add(n);
|
||||
set.add(m);
|
||||
match set.check_valid() {
|
||||
Some((a, b)) => {
|
||||
assert!((n == a && m == b) ||
|
||||
(m == a && n == b));
|
||||
}
|
||||
None => {
|
||||
fail!(~"Invalid match not detected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn can_combine(n: Abi, m: Abi) {
|
||||
let mut set = AbiSet::empty();
|
||||
set.add(n);
|
||||
set.add(m);
|
||||
match set.check_valid() {
|
||||
Some((_, _)) => {
|
||||
fail!(~"Valid match declared invalid");
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_combine_cdecl_and_stdcall() {
|
||||
cannot_combine(Cdecl, Stdcall);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_combine_c_and_rust() {
|
||||
cannot_combine(C, Rust);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_combine_rust_and_cdecl() {
|
||||
cannot_combine(Rust, Cdecl);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_combine_rust_intrinsic_and_cdecl() {
|
||||
cannot_combine(RustIntrinsic, Cdecl);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_c_and_stdcall() {
|
||||
can_combine(C, Stdcall);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_aapcs_and_stdcall() {
|
||||
can_combine(Aapcs, Stdcall);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn abi_to_str_stdcall_aaps() {
|
||||
let mut set = AbiSet::empty();
|
||||
set.add(Aapcs);
|
||||
set.add(Stdcall);
|
||||
assert!(set.to_str() == ~"\"stdcall aapcs\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn abi_to_str_c_aaps() {
|
||||
let mut set = AbiSet::empty();
|
||||
set.add(Aapcs);
|
||||
set.add(C);
|
||||
debug!("set = %s", set.to_str());
|
||||
assert!(set.to_str() == ~"\"aapcs C\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn abi_to_str_rust() {
|
||||
let mut set = AbiSet::empty();
|
||||
set.add(Rust);
|
||||
debug!("set = %s", set.to_str());
|
||||
assert!(set.to_str() == ~"\"Rust\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indices_are_correct() {
|
||||
for AbiDatas.eachi |i, abi_data| {
|
||||
assert!(i == abi_data.abi.index());
|
||||
}
|
||||
|
||||
let bits = 1 << (X86 as u32);
|
||||
let bits = bits | 1 << (X86_64 as u32);
|
||||
assert!(IntelBits == bits);
|
||||
|
||||
let bits = 1 << (Arm as u32);
|
||||
assert!(ArmBits == bits);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn check_arch(abis: &[Abi], arch: Architecture, expect: Option<Abi>) {
|
||||
let mut set = AbiSet::empty();
|
||||
for abis.each |&abi| {
|
||||
set.add(abi);
|
||||
}
|
||||
let r = set.for_arch(arch);
|
||||
assert!(r == expect);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pick_multiplatform() {
|
||||
check_arch([C, Cdecl], X86, Some(Cdecl));
|
||||
check_arch([C, Cdecl], X86_64, Some(Cdecl));
|
||||
check_arch([C, Cdecl], Arm, Some(C));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pick_uniplatform() {
|
||||
check_arch([Stdcall], X86, Some(Stdcall));
|
||||
check_arch([Stdcall], Arm, None);
|
||||
}
|
|
@ -10,7 +10,9 @@
|
|||
|
||||
// The Rust abstract syntax tree.
|
||||
|
||||
use codemap::{span, spanned};
|
||||
use codemap::{span, FileName, spanned};
|
||||
use abi::AbiSet;
|
||||
use opt_vec::OptVec;
|
||||
|
||||
use core::cast;
|
||||
use core::option::{None, Option, Some};
|
||||
|
@ -19,7 +21,6 @@ use core::to_bytes;
|
|||
use core::to_str::ToStr;
|
||||
use std::serialize::{Encodable, Decodable, Encoder, Decoder};
|
||||
|
||||
use opt_vec::OptVec;
|
||||
|
||||
/* can't import macros yet, so this is copied from token.rs. See its comment
|
||||
* there. */
|
||||
|
@ -325,27 +326,6 @@ impl to_bytes::IterBytes for mutability {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_encode]
|
||||
#[auto_decode]
|
||||
#[deriving(Eq)]
|
||||
pub enum Abi {
|
||||
RustAbi
|
||||
}
|
||||
|
||||
impl to_bytes::IterBytes for Abi {
|
||||
fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
|
||||
(*self as uint).iter_bytes(lsb0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToStr for Abi {
|
||||
fn to_str(&self) -> ~str {
|
||||
match *self {
|
||||
RustAbi => ~"\"rust\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[auto_encode]
|
||||
#[auto_decode]
|
||||
#[deriving(Eq)]
|
||||
|
@ -893,7 +873,7 @@ pub struct TyClosure {
|
|||
#[deriving(Eq)]
|
||||
pub struct TyBareFn {
|
||||
purity: purity,
|
||||
abi: Abi,
|
||||
abis: AbiSet,
|
||||
lifetimes: OptVec<Lifetime>,
|
||||
decl: fn_decl
|
||||
}
|
||||
|
@ -1057,15 +1037,6 @@ pub struct _mod {
|
|||
items: ~[@item],
|
||||
}
|
||||
|
||||
#[auto_encode]
|
||||
#[auto_decode]
|
||||
#[deriving(Eq)]
|
||||
pub enum foreign_abi {
|
||||
foreign_abi_rust_intrinsic,
|
||||
foreign_abi_cdecl,
|
||||
foreign_abi_stdcall,
|
||||
}
|
||||
|
||||
// Foreign mods can be named or anonymous
|
||||
#[auto_encode]
|
||||
#[auto_decode]
|
||||
|
@ -1077,7 +1048,7 @@ pub enum foreign_mod_sort { named, anonymous }
|
|||
#[deriving(Eq)]
|
||||
pub struct foreign_mod {
|
||||
sort: foreign_mod_sort,
|
||||
abi: ident,
|
||||
abis: AbiSet,
|
||||
view_items: ~[@view_item],
|
||||
items: ~[@foreign_item],
|
||||
}
|
||||
|
@ -1267,7 +1238,7 @@ pub struct item {
|
|||
#[deriving(Eq)]
|
||||
pub enum item_ {
|
||||
item_const(@Ty, @expr),
|
||||
item_fn(fn_decl, purity, Generics, blk),
|
||||
item_fn(fn_decl, purity, AbiSet, Generics, blk),
|
||||
item_mod(_mod),
|
||||
item_foreign_mod(foreign_mod),
|
||||
item_ty(@Ty, Generics),
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use abi::AbiSet;
|
||||
use ast::*;
|
||||
use ast;
|
||||
use ast_util::{inlined_item_utils, stmt_id};
|
||||
|
@ -87,7 +88,7 @@ pub fn path_elt_to_str(pe: path_elt, itr: @ident_interner) -> ~str {
|
|||
|
||||
pub enum ast_node {
|
||||
node_item(@item, @path),
|
||||
node_foreign_item(@foreign_item, foreign_abi, visibility, @path),
|
||||
node_foreign_item(@foreign_item, AbiSet, visibility, @path),
|
||||
node_trait_method(@trait_method, def_id /* trait did */,
|
||||
@path /* path to the trait */),
|
||||
node_method(@method, def_id /* impl did */, @path /* path to the impl */),
|
||||
|
@ -171,7 +172,7 @@ pub fn map_decoded_item(diag: @span_handler,
|
|||
ii_item(*) | ii_dtor(*) => { /* fallthrough */ }
|
||||
ii_foreign(i) => {
|
||||
cx.map.insert(i.id, node_foreign_item(i,
|
||||
foreign_abi_rust_intrinsic,
|
||||
AbiSet::Intrinsic(),
|
||||
i.vis, // Wrong but OK
|
||||
@path));
|
||||
}
|
||||
|
@ -274,10 +275,6 @@ pub fn map_item(i: @item, &&cx: @mut Ctx, v: visit::vt<@mut Ctx>) {
|
|||
}
|
||||
}
|
||||
item_foreign_mod(ref nm) => {
|
||||
let abi = match attr::foreign_abi(i.attrs) {
|
||||
Left(ref msg) => cx.diag.span_fatal(i.span, (*msg)),
|
||||
Right(abi) => abi
|
||||
};
|
||||
for nm.items.each |nitem| {
|
||||
// Compute the visibility for this native item.
|
||||
let visibility = match nitem.vis {
|
||||
|
@ -289,7 +286,7 @@ pub fn map_item(i: @item, &&cx: @mut Ctx, v: visit::vt<@mut Ctx>) {
|
|||
cx.map.insert(nitem.id,
|
||||
node_foreign_item(
|
||||
*nitem,
|
||||
abi,
|
||||
nm.abis,
|
||||
visibility,
|
||||
// FIXME (#2543)
|
||||
if nm.sort == ast::named {
|
||||
|
|
|
@ -465,7 +465,7 @@ pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> {
|
|||
vfn(self_id);
|
||||
vfn(parent_id.node);
|
||||
}
|
||||
visit::fk_item_fn(_, generics, _) => {
|
||||
visit::fk_item_fn(_, generics, _, _) => {
|
||||
visit_generics(generics);
|
||||
}
|
||||
visit::fk_method(_, generics, m) => {
|
||||
|
|
|
@ -303,27 +303,6 @@ pub fn find_linkage_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn foreign_abi(attrs: &[ast::attribute])
|
||||
-> Either<~str, ast::foreign_abi> {
|
||||
return match attr::first_attr_value_str_by_name(attrs, ~"abi") {
|
||||
None => {
|
||||
Right(ast::foreign_abi_cdecl)
|
||||
}
|
||||
Some(@~"rust-intrinsic") => {
|
||||
Right(ast::foreign_abi_rust_intrinsic)
|
||||
}
|
||||
Some(@~"cdecl") => {
|
||||
Right(ast::foreign_abi_cdecl)
|
||||
}
|
||||
Some(@~"stdcall") => {
|
||||
Right(ast::foreign_abi_stdcall)
|
||||
}
|
||||
Some(t) => {
|
||||
Left(~"unsupported abi: " + *t)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum inline_attr {
|
||||
ia_none,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use ast::ident;
|
||||
use abi::AbiSet;
|
||||
use ast::{ident, node_id};
|
||||
use ast;
|
||||
use ast_util;
|
||||
use codemap::{span, respan, dummy_sp, spanned};
|
||||
|
@ -272,6 +273,7 @@ impl ext_ctxt_ast_builder for @ext_ctxt {
|
|||
dummy_sp(),
|
||||
ast::item_fn(self.fn_decl(inputs, output),
|
||||
ast::impure_fn,
|
||||
AbiSet::Rust(),
|
||||
generics,
|
||||
body))
|
||||
}
|
||||
|
|
|
@ -236,10 +236,11 @@ fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold)
|
|||
pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ {
|
||||
match *i {
|
||||
item_const(t, e) => item_const(fld.fold_ty(t), fld.fold_expr(e)),
|
||||
item_fn(ref decl, purity, ref generics, ref body) => {
|
||||
item_fn(ref decl, purity, abi, ref generics, ref body) => {
|
||||
item_fn(
|
||||
fold_fn_decl(decl, fld),
|
||||
purity,
|
||||
abi,
|
||||
fold_generics(generics, fld),
|
||||
fld.fold_block(body)
|
||||
)
|
||||
|
@ -612,7 +613,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
|
|||
ty_bare_fn(@TyBareFn {
|
||||
lifetimes: f.lifetimes,
|
||||
purity: f.purity,
|
||||
abi: f.abi,
|
||||
abis: f.abis,
|
||||
decl: fold_fn_decl(&f.decl, fld)
|
||||
})
|
||||
}
|
||||
|
@ -639,7 +640,7 @@ pub fn noop_fold_mod(m: &_mod, fld: @ast_fold) -> _mod {
|
|||
fn noop_fold_foreign_mod(nm: &foreign_mod, fld: @ast_fold) -> foreign_mod {
|
||||
ast::foreign_mod {
|
||||
sort: nm.sort,
|
||||
abi: nm.abi,
|
||||
abis: nm.abis,
|
||||
view_items: vec::map(nm.view_items, |x| fld.fold_view_item(*x)),
|
||||
items: vec::map(nm.items, |x| fld.fold_foreign_item(*x)),
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil, RustAbi};
|
||||
use abi;
|
||||
use abi::AbiSet;
|
||||
use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil};
|
||||
use ast::{CallSugar, NoSugar, DoSugar, ForSugar};
|
||||
use ast::{TyBareFn, TyClosure};
|
||||
use ast::{RegionTyParamBound, TraitTyParamBound};
|
||||
|
@ -361,11 +363,13 @@ pub impl Parser {
|
|||
|
||||
*/
|
||||
|
||||
let opt_abis = self.parse_opt_abis();
|
||||
let abis = opt_abis.get_or_default(AbiSet::Rust());
|
||||
let purity = self.parse_purity();
|
||||
self.expect_keyword(&~"fn");
|
||||
let (decl, lifetimes) = self.parse_ty_fn_decl();
|
||||
return ty_bare_fn(@TyBareFn {
|
||||
abi: RustAbi,
|
||||
abis: abis,
|
||||
purity: purity,
|
||||
lifetimes: lifetimes,
|
||||
decl: decl
|
||||
|
@ -3041,11 +3045,13 @@ pub impl Parser {
|
|||
span: mk_sp(lo, hi) }
|
||||
}
|
||||
|
||||
fn parse_item_fn(&self, purity: purity) -> item_info {
|
||||
fn parse_item_fn(&self, purity: purity, abis: AbiSet) -> item_info {
|
||||
let (ident, generics) = self.parse_fn_header();
|
||||
let decl = self.parse_fn_decl(|p| p.parse_arg());
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block(true);
|
||||
(ident, item_fn(decl, purity, generics, body), Some(inner_attrs))
|
||||
(ident,
|
||||
item_fn(decl, purity, abis, generics, body),
|
||||
Some(inner_attrs))
|
||||
}
|
||||
|
||||
fn parse_method(&self) -> @method {
|
||||
|
@ -3607,7 +3613,7 @@ pub impl Parser {
|
|||
}
|
||||
|
||||
fn parse_foreign_mod_items(&self, sort: ast::foreign_mod_sort,
|
||||
+abi: ast::ident,
|
||||
+abis: AbiSet,
|
||||
+first_item_attrs: ~[attribute])
|
||||
-> foreign_mod {
|
||||
// Shouldn't be any view items since we've already parsed an item attr
|
||||
|
@ -3630,30 +3636,20 @@ pub impl Parser {
|
|||
}
|
||||
ast::foreign_mod {
|
||||
sort: sort,
|
||||
abi: abi,
|
||||
abis: abis,
|
||||
view_items: view_items,
|
||||
items: items
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_item_foreign_mod(&self, lo: BytePos,
|
||||
fn parse_item_foreign_mod(&self,
|
||||
lo: BytePos,
|
||||
opt_abis: Option<AbiSet>,
|
||||
visibility: visibility,
|
||||
attrs: ~[attribute],
|
||||
items_allowed: bool)
|
||||
-> item_or_view_item {
|
||||
|
||||
// Parse the ABI.
|
||||
let abi_opt;
|
||||
match *self.token {
|
||||
token::LIT_STR(copy found_abi) => {
|
||||
self.bump();
|
||||
abi_opt = Some(found_abi);
|
||||
}
|
||||
_ => {
|
||||
abi_opt = None;
|
||||
}
|
||||
}
|
||||
|
||||
-> item_or_view_item
|
||||
{
|
||||
let mut must_be_named_mod = false;
|
||||
if self.is_keyword(&~"mod") {
|
||||
must_be_named_mod = true;
|
||||
|
@ -3688,14 +3684,10 @@ pub impl Parser {
|
|||
|
||||
// extern mod { ... }
|
||||
if items_allowed && self.eat(&token::LBRACE) {
|
||||
let abi;
|
||||
match abi_opt {
|
||||
Some(found_abi) => abi = found_abi,
|
||||
None => abi = special_idents::c_abi,
|
||||
}
|
||||
let abis = opt_abis.get_or_default(AbiSet::C());
|
||||
|
||||
let (inner, next) = self.parse_inner_attrs_and_next();
|
||||
let m = self.parse_foreign_mod_items(sort, abi, next);
|
||||
let m = self.parse_foreign_mod_items(sort, abis, next);
|
||||
self.expect(&token::RBRACE);
|
||||
|
||||
return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
|
||||
|
@ -3704,12 +3696,8 @@ pub impl Parser {
|
|||
Some(inner))));
|
||||
}
|
||||
|
||||
match abi_opt {
|
||||
None => {} // OK.
|
||||
Some(_) => {
|
||||
self.span_err(*self.span, ~"an ABI may not be specified \
|
||||
here");
|
||||
}
|
||||
if opt_abis.is_some() {
|
||||
self.span_err(*self.span, ~"an ABI may not be specified here");
|
||||
}
|
||||
|
||||
// extern mod foo;
|
||||
|
@ -3913,6 +3901,49 @@ pub impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_opt_abis(&self) -> Option<AbiSet> {
|
||||
match *self.token {
|
||||
token::LIT_STR(s) => {
|
||||
self.bump();
|
||||
let the_string = self.id_to_str(s);
|
||||
let mut words = ~[];
|
||||
for str::each_word(*the_string) |s| { words.push(s) }
|
||||
let mut abis = AbiSet::empty();
|
||||
for words.each |word| {
|
||||
match abi::lookup(*word) {
|
||||
Some(abi) => {
|
||||
if abis.contains(abi) {
|
||||
self.span_err(
|
||||
*self.span,
|
||||
fmt!("ABI `%s` appears twice",
|
||||
*word));
|
||||
} else {
|
||||
abis.add(abi);
|
||||
}
|
||||
}
|
||||
|
||||
None => {
|
||||
self.span_err(
|
||||
*self.span,
|
||||
fmt!("illegal ABI: \
|
||||
expected one of [%s], \
|
||||
found `%s`",
|
||||
str::connect_slices(
|
||||
abi::all_names(),
|
||||
", "),
|
||||
*word));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(abis)
|
||||
}
|
||||
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse one of the items or view items allowed by the
|
||||
// flags; on failure, return iovi_none.
|
||||
fn parse_item_or_view_item(
|
||||
|
@ -3961,7 +3992,8 @@ pub impl Parser {
|
|||
self.is_keyword(&~"fn") &&
|
||||
!self.fn_expr_lookahead(self.look_ahead(1u)) {
|
||||
self.bump();
|
||||
let (ident, item_, extra_attrs) = self.parse_item_fn(impure_fn);
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(impure_fn, AbiSet::Rust());
|
||||
return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs)));
|
||||
|
@ -3970,7 +4002,8 @@ pub impl Parser {
|
|||
// PURE FUNCTION ITEM
|
||||
self.obsolete(*self.last_span, ObsoletePurity);
|
||||
self.expect_keyword(&~"fn");
|
||||
let (ident, item_, extra_attrs) = self.parse_item_fn(impure_fn);
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(impure_fn, AbiSet::Rust());
|
||||
return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs)));
|
||||
|
@ -3987,16 +4020,20 @@ pub impl Parser {
|
|||
// UNSAFE FUNCTION ITEM (where items are allowed)
|
||||
self.bump();
|
||||
self.expect_keyword(&~"fn");
|
||||
let (ident, item_, extra_attrs) = self.parse_item_fn(unsafe_fn);
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(unsafe_fn, AbiSet::Rust());
|
||||
return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs)));
|
||||
}
|
||||
if self.eat_keyword(&~"extern") {
|
||||
let opt_abis = self.parse_opt_abis();
|
||||
|
||||
if items_allowed && self.eat_keyword(&~"fn") {
|
||||
// EXTERN FUNCTION ITEM
|
||||
let abis = opt_abis.get_or_default(AbiSet::C());
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(extern_fn);
|
||||
self.parse_item_fn(extern_fn, abis);
|
||||
return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
|
||||
item_, visibility,
|
||||
maybe_append(attrs,
|
||||
|
@ -4004,7 +4041,7 @@ pub impl Parser {
|
|||
}
|
||||
if !foreign_items_allowed {
|
||||
// EXTERN MODULE ITEM
|
||||
return self.parse_item_foreign_mod(lo, visibility, attrs,
|
||||
return self.parse_item_foreign_mod(lo, opt_abis, visibility, attrs,
|
||||
items_allowed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use abi::AbiSet;
|
||||
use abi;
|
||||
use ast::{RegionTyParamBound, TraitTyParamBound, required, provided};
|
||||
use ast;
|
||||
use ast_util;
|
||||
|
@ -186,7 +188,8 @@ pub fn fun_to_str(decl: &ast::fn_decl, purity: ast::purity, name: ast::ident,
|
|||
generics: &ast::Generics, intr: @ident_interner) -> ~str {
|
||||
do io::with_str_writer |wr| {
|
||||
let s = rust_printer(wr, intr);
|
||||
print_fn(s, decl, purity, name, generics, opt_self_ty, ast::inherited);
|
||||
print_fn(s, decl, Some(purity), AbiSet::Rust(),
|
||||
name, generics, opt_self_ty, ast::inherited);
|
||||
end(s); // Close the head box
|
||||
end(s); // Close the outer box
|
||||
eof(s.s);
|
||||
|
@ -405,7 +408,7 @@ pub fn print_type(s: @ps, &&ty: @ast::Ty) {
|
|||
ast::ty_bare_fn(f) => {
|
||||
let generics = ast::Generics {lifetimes: copy f.lifetimes,
|
||||
ty_params: opt_vec::Empty};
|
||||
print_ty_fn(s, Some(f.abi), None, None,
|
||||
print_ty_fn(s, Some(f.abis), None, None,
|
||||
f.purity, ast::Many, &f.decl, None,
|
||||
Some(&generics), None);
|
||||
}
|
||||
|
@ -446,7 +449,7 @@ pub fn print_foreign_item(s: @ps, item: @ast::foreign_item) {
|
|||
print_outer_attributes(s, item.attrs);
|
||||
match item.node {
|
||||
ast::foreign_item_fn(ref decl, purity, ref generics) => {
|
||||
print_fn(s, decl, purity, item.ident, generics, None,
|
||||
print_fn(s, decl, Some(purity), AbiSet::Rust(), item.ident, generics, None,
|
||||
ast::inherited);
|
||||
end(s); // end head-ibox
|
||||
word(s.s, ~";");
|
||||
|
@ -485,11 +488,12 @@ pub fn print_item(s: @ps, &&item: @ast::item) {
|
|||
end(s); // end the outer cbox
|
||||
|
||||
}
|
||||
ast::item_fn(ref decl, purity, ref typarams, ref body) => {
|
||||
ast::item_fn(ref decl, purity, abi, ref typarams, ref body) => {
|
||||
print_fn(
|
||||
s,
|
||||
decl,
|
||||
purity,
|
||||
Some(purity),
|
||||
abi,
|
||||
item.ident,
|
||||
typarams,
|
||||
None,
|
||||
|
@ -508,8 +512,7 @@ pub fn print_item(s: @ps, &&item: @ast::item) {
|
|||
}
|
||||
ast::item_foreign_mod(ref nmod) => {
|
||||
head(s, visibility_qualified(item.vis, ~"extern"));
|
||||
print_string(s, *s.intr.get(nmod.abi));
|
||||
nbsp(s);
|
||||
word_nbsp(s, nmod.abis.to_str());
|
||||
match nmod.sort {
|
||||
ast::named => {
|
||||
word_nbsp(s, ~"mod");
|
||||
|
@ -817,7 +820,7 @@ pub fn print_method(s: @ps, meth: @ast::method) {
|
|||
hardbreak_if_not_bol(s);
|
||||
maybe_print_comment(s, meth.span.lo);
|
||||
print_outer_attributes(s, meth.attrs);
|
||||
print_fn(s, &meth.decl, meth.purity,
|
||||
print_fn(s, &meth.decl, Some(meth.purity), AbiSet::Rust(),
|
||||
meth.ident, &meth.generics, Some(meth.self_ty.node),
|
||||
meth.vis);
|
||||
word(s.s, ~" ");
|
||||
|
@ -1650,13 +1653,14 @@ pub fn print_self_ty(s: @ps, self_ty: ast::self_ty_) -> bool {
|
|||
|
||||
pub fn print_fn(s: @ps,
|
||||
decl: &ast::fn_decl,
|
||||
purity: ast::purity,
|
||||
purity: Option<ast::purity>,
|
||||
abis: AbiSet,
|
||||
name: ast::ident,
|
||||
generics: &ast::Generics,
|
||||
opt_self_ty: Option<ast::self_ty_>,
|
||||
vis: ast::visibility) {
|
||||
head(s, ~"");
|
||||
print_fn_header_info(s, purity, ast::Many, None, vis);
|
||||
print_fn_header_info(s, opt_self_ty, purity, abis, ast::Many, None, vis);
|
||||
nbsp(s);
|
||||
print_ident(s, name);
|
||||
print_generics(s, generics);
|
||||
|
@ -1905,7 +1909,7 @@ pub fn print_arg(s: @ps, input: ast::arg) {
|
|||
}
|
||||
|
||||
pub fn print_ty_fn(s: @ps,
|
||||
opt_abi: Option<ast::Abi>,
|
||||
opt_abis: Option<AbiSet>,
|
||||
opt_sigil: Option<ast::Sigil>,
|
||||
opt_region: Option<@ast::Lifetime>,
|
||||
purity: ast::purity,
|
||||
|
@ -1918,7 +1922,7 @@ pub fn print_ty_fn(s: @ps,
|
|||
|
||||
// Duplicates the logic in `print_fn_header_info()`. This is because that
|
||||
// function prints the sigil in the wrong place. That should be fixed.
|
||||
print_opt_abi(s, opt_abi);
|
||||
print_extern_opt_abis(s, opt_abis);
|
||||
print_opt_sigil(s, opt_sigil);
|
||||
print_opt_lifetime(s, opt_region);
|
||||
print_purity(s, purity);
|
||||
|
@ -2146,9 +2150,22 @@ pub fn next_comment(s: @ps) -> Option<comments::cmnt> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn print_opt_abi(s: @ps, opt_abi: Option<ast::Abi>) {
|
||||
match opt_abi {
|
||||
Some(ast::RustAbi) => { word_nbsp(s, ~"extern"); }
|
||||
pub fn print_opt_purity(s: @ps, opt_purity: Option<ast::purity>) {
|
||||
match opt_purity {
|
||||
Some(ast::impure_fn) => { }
|
||||
Some(purity) => {
|
||||
word_nbsp(s, purity_to_str(purity));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_extern_opt_abis(s: @ps, opt_abis: Option<AbiSet>) {
|
||||
match opt_abis {
|
||||
Some(abis) => {
|
||||
word_nbsp(s, ~"extern");
|
||||
word_nbsp(s, abis.to_str());
|
||||
}
|
||||
None => {}
|
||||
};
|
||||
}
|
||||
|
@ -2163,12 +2180,25 @@ pub fn print_opt_sigil(s: @ps, opt_sigil: Option<ast::Sigil>) {
|
|||
}
|
||||
|
||||
pub fn print_fn_header_info(s: @ps,
|
||||
purity: ast::purity,
|
||||
opt_sty: Option<ast::self_ty_>,
|
||||
opt_purity: Option<ast::purity>,
|
||||
abis: AbiSet,
|
||||
onceness: ast::Onceness,
|
||||
opt_sigil: Option<ast::Sigil>,
|
||||
vis: ast::visibility) {
|
||||
word(s.s, visibility_qualified(vis, ~""));
|
||||
print_purity(s, purity);
|
||||
|
||||
if abis != AbiSet::Rust() {
|
||||
word_nbsp(s, ~"extern");
|
||||
word_nbsp(s, abis.to_str());
|
||||
|
||||
if opt_purity != Some(ast::extern_fn) {
|
||||
print_opt_purity(s, opt_purity);
|
||||
}
|
||||
} else {
|
||||
print_opt_purity(s, opt_purity);
|
||||
}
|
||||
|
||||
print_onceness(s, onceness);
|
||||
word(s.s, ~"fn");
|
||||
print_opt_sigil(s, opt_sigil);
|
||||
|
|
|
@ -39,6 +39,7 @@ pub mod opt_vec;
|
|||
pub mod attr;
|
||||
pub mod diagnostic;
|
||||
pub mod codemap;
|
||||
pub mod abi;
|
||||
pub mod ast;
|
||||
pub mod ast_util;
|
||||
pub mod ast_map;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use abi::AbiSet;
|
||||
use ast::*;
|
||||
use ast;
|
||||
use ast_util;
|
||||
|
@ -29,10 +30,18 @@ use opt_vec::OptVec;
|
|||
pub enum vt<E> { mk_vt(visitor<E>), }
|
||||
|
||||
pub enum fn_kind<'self> {
|
||||
fk_item_fn(ident, &'self Generics, purity), // fn foo()
|
||||
fk_method(ident, &'self Generics, &'self method), // fn foo(&self)
|
||||
fk_anon(ast::Sigil), // fn@(x, y) { ... }
|
||||
fk_fn_block, // |x, y| ...
|
||||
// fn foo() or extern "Abi" fn foo()
|
||||
fk_item_fn(ident, &'self Generics, purity, AbiSet),
|
||||
|
||||
// fn foo(&self)
|
||||
fk_method(ident, &'self Generics, &'self method),
|
||||
|
||||
// fn@(x, y) { ... }
|
||||
fk_anon(ast::Sigil),
|
||||
|
||||
// |x, y| ...
|
||||
fk_fn_block,
|
||||
|
||||
fk_dtor( // class destructor
|
||||
&'self Generics,
|
||||
&'self [attribute],
|
||||
|
@ -43,8 +52,8 @@ pub enum fn_kind<'self> {
|
|||
|
||||
pub fn name_of_fn(fk: &fn_kind) -> ident {
|
||||
match *fk {
|
||||
fk_item_fn(name, _, _) | fk_method(name, _, _) => {
|
||||
/* FIXME (#2543) */ copy name
|
||||
fk_item_fn(name, _, _, _) | fk_method(name, _, _) => {
|
||||
name
|
||||
}
|
||||
fk_anon(*) | fk_fn_block(*) => parse::token::special_idents::anon,
|
||||
fk_dtor(*) => parse::token::special_idents::dtor
|
||||
|
@ -53,7 +62,7 @@ pub fn name_of_fn(fk: &fn_kind) -> ident {
|
|||
|
||||
pub fn generics_of_fn(fk: &fn_kind) -> Generics {
|
||||
match *fk {
|
||||
fk_item_fn(_, generics, _) |
|
||||
fk_item_fn(_, generics, _, _) |
|
||||
fk_method(_, generics, _) |
|
||||
fk_dtor(generics, _, _, _) => {
|
||||
copy *generics
|
||||
|
@ -144,12 +153,13 @@ pub fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
|||
(v.visit_ty)(t, e, v);
|
||||
(v.visit_expr)(ex, e, v);
|
||||
}
|
||||
item_fn(ref decl, purity, ref generics, ref body) => {
|
||||
item_fn(ref decl, purity, abi, ref generics, ref body) => {
|
||||
(v.visit_fn)(
|
||||
&fk_item_fn(
|
||||
/* FIXME (#2543) */ copy i.ident,
|
||||
i.ident,
|
||||
generics,
|
||||
purity
|
||||
purity,
|
||||
abi
|
||||
),
|
||||
decl,
|
||||
body,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
|
||||
fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
|
||||
fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;
|
||||
|
|
|
@ -19,5 +19,5 @@ fn main() {
|
|||
}
|
||||
|
||||
f(g);
|
||||
//~^ ERROR mismatched types: expected `extern fn(extern fn(extern fn()))`
|
||||
//~^ ERROR mismatched types: expected `extern "Rust" fn(extern "Rust" fn(extern "Rust" fn()))`
|
||||
}
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
// except according to those terms.
|
||||
|
||||
fn main() -> char {
|
||||
//~^ ERROR Wrong type in main function: found `extern fn() -> char`
|
||||
//~^ ERROR Wrong type in main function: found `extern "Rust" fn() -> char`
|
||||
}
|
||||
|
|
|
@ -14,5 +14,5 @@ struct S {
|
|||
}
|
||||
|
||||
fn main(foo: S) {
|
||||
//~^ ERROR Wrong type in main function: found `extern fn(S)`
|
||||
//~^ ERROR Wrong type in main function: found `extern "Rust" fn(S)`
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@ fn foo(f: &fn()) { f() }
|
|||
|
||||
fn main() {
|
||||
~"" || 42; //~ ERROR binary operation || cannot be applied to type `~str`
|
||||
foo || {}; //~ ERROR binary operation || cannot be applied to type `extern fn(&fn())`
|
||||
foo || {}; //~ ERROR binary operation || cannot be applied to type `extern "Rust" fn(&fn())`
|
||||
//~^ NOTE did you forget the `do` keyword for the call?
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
// pp-exact
|
||||
|
||||
fn from_foreign_fn(x: extern fn()) { }
|
||||
fn from_foreign_fn(x: extern "Rust" fn()) { }
|
||||
fn from_stack_closure(x: &fn()) { }
|
||||
fn from_box_closure(x: @fn()) { }
|
||||
fn from_unique_closure(x: ~fn()) { }
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn pref_align_of<T>() -> uint;
|
||||
pub fn min_align_of<T>() -> uint;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
|
||||
pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
|
||||
pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn frame_address(f: &once fn(*u8));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn move_val_init<T>(dst: &mut T, +src: T);
|
||||
pub fn move_val<T>(dst: &mut T, +src: T);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ extern mod std;
|
|||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
fn ctpop8(x: i8) -> i8;
|
||||
fn ctpop16(x: i16) -> i16;
|
||||
fn ctpop32(x: i32) -> i32;
|
||||
|
|
|
@ -16,7 +16,7 @@ use std::cmp::FuzzyEq;
|
|||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
fn sqrtf32(x: f32) -> f32;
|
||||
fn sqrtf64(x: f64) -> f64;
|
||||
fn powif32(a: f32, x: i32) -> f32;
|
||||
|
|
|
@ -45,7 +45,6 @@ pub mod pipes {
|
|||
}
|
||||
}
|
||||
|
||||
#[abi = "rust-intrinsic"]
|
||||
mod rusti {
|
||||
pub fn atomic_xchg(_dst: &mut int, _src: int) -> int { fail!(); }
|
||||
pub fn atomic_xchg_acq(_dst: &mut int, _src: int) -> int { fail!(); }
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
mod rusti {
|
||||
#[nolink]
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn morestack_addr() -> *();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn pref_align_of<T>() -> uint;
|
||||
pub fn min_align_of<T>() -> uint;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub extern "rust-intrinsic" {
|
||||
pub fn pref_align_of<T>() -> uint;
|
||||
pub fn min_align_of<T>() -> uint;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ mod kernel32 {
|
|||
|
||||
#[cfg(target_os = "win32")]
|
||||
#[abi = "stdcall"]
|
||||
pub extern {
|
||||
pub extern "stdcall" {
|
||||
pub fn GetProcessHeap() -> HANDLE;
|
||||
pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T)
|
||||
-> LPVOID;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue