提交 cd41ee20 编写于 作者: J James Miller

Add #[start] attribute to define a new entry point function

上级 412a0705
......@@ -698,7 +698,8 @@ pub fn build_session_(sopts: @session::options,
parse_sess: p_s,
codemap: cm,
// For a library crate, this is always none
main_fn: @mut None,
entry_fn: @mut None,
entry_type: @mut None,
span_diagnostic: span_diagnostic_handler,
filesearch: filesearch,
building_library: @mut false,
......
......@@ -144,6 +144,16 @@ pub struct crate_metadata {
data: ~[u8]
}
// The type of entry function, so
// users can have their own entry
// functions that don't start a
// scheduler
#[deriving(Eq)]
pub enum EntryFnType {
EntryMain,
EntryStart
}
pub struct Session_ {
targ_cfg: @config,
opts: @options,
......@@ -151,7 +161,8 @@ pub struct Session_ {
parse_sess: @mut ParseSess,
codemap: @codemap::CodeMap,
// For a library crate, this is always none
main_fn: @mut Option<(node_id, codemap::span)>,
entry_fn: @mut Option<(node_id, codemap::span)>,
entry_type: @mut Option<EntryFnType>,
span_diagnostic: @diagnostic::span_handler,
filesearch: @filesearch::FileSearch,
building_library: @mut bool,
......
......@@ -801,6 +801,8 @@ pub fn Resolver(session: Session,
attr_main_fn: None,
main_fns: ~[],
start_fn: None,
def_map: @mut HashMap::new(),
export_map2: @mut HashMap::new(),
trait_map: HashMap::new(),
......@@ -860,9 +862,13 @@ pub struct Resolver {
// The function that has attribute named 'main'
attr_main_fn: Option<(node_id, span)>,
// The functions named 'main'
// The functions that could be main functions
main_fns: ~[Option<(node_id, span)>],
// The function that has the attribute 'start' on it
start_fn: Option<(node_id, span)>,
def_map: DefMap,
export_map2: ExportMap2,
trait_map: TraitMap,
......@@ -3538,6 +3544,7 @@ fn resolve_item(@mut self, item: @item, visitor: ResolveVisitor) {
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
if !*self.session.building_library ||
self.session.targ_cfg.os == session::os_android {
......@@ -3557,6 +3564,16 @@ fn resolve_item(@mut self, item: @item, visitor: ResolveVisitor) {
~"multiple 'main' functions");
}
}
if attrs_contains_name(item.attrs, ~"start") {
if self.start_fn.is_none() {
self.start_fn = Some((item.id, item.span));
} else {
self.session.span_err(
item.span,
~"multiple 'start' functions");
}
}
}
self.resolve_function(OpaqueFunctionRibKind,
......@@ -5096,7 +5113,7 @@ fn enforce_default_binding_mode(@mut self,
//
fn check_duplicate_main(@mut self) {
let this = &mut *self;
if this.attr_main_fn.is_none() {
if this.attr_main_fn.is_none() && this.start_fn.is_none() {
if this.main_fns.len() >= 1u {
let mut i = 1u;
while i < this.main_fns.len() {
......@@ -5106,10 +5123,15 @@ fn check_duplicate_main(@mut self) {
~"multiple 'main' functions");
i += 1;
}
*this.session.main_fn = this.main_fns[0];
*this.session.entry_fn = this.main_fns[0];
*this.session.entry_type = Some(session::EntryMain);
}
} else if !this.start_fn.is_none() {
*this.session.entry_fn = this.start_fn;
*this.session.entry_type = Some(session::EntryStart);
} else {
*this.session.main_fn = this.attr_main_fn;
*this.session.entry_fn = this.attr_main_fn;
*this.session.entry_type = Some(session::EntryMain);
}
}
......
......@@ -2197,28 +2197,32 @@ pub fn register_fn_fuller(ccx: @CrateContext,
ccx.item_symbols.insert(node_id, ps);
// FIXME #4404 android JNI hacks
let is_main = is_main_fn(&ccx.sess, node_id) &&
let is_entry = is_entry_fn(&ccx.sess, node_id) &&
(!*ccx.sess.building_library ||
(*ccx.sess.building_library &&
ccx.sess.targ_cfg.os == session::os_android));
if is_main { create_main_wrapper(ccx, sp, llfn); }
if is_entry { create_entry_wrapper(ccx, sp, llfn); }
llfn
}
pub fn is_main_fn(sess: &Session, node_id: ast::node_id) -> bool {
match *sess.main_fn {
Some((main_id, _)) => node_id == main_id,
pub fn is_entry_fn(sess: &Session, node_id: ast::node_id) -> bool {
match *sess.entry_fn {
Some((entry_id, _)) => node_id == entry_id,
None => false
}
}
// Create a _rust_main(args: ~[str]) function which will be called from the
// runtime rust_start function
pub fn create_main_wrapper(ccx: @CrateContext,
pub fn create_entry_wrapper(ccx: @CrateContext,
_sp: span, main_llfn: ValueRef) {
let llfn = create_main(ccx, main_llfn);
create_entry_fn(ccx, llfn);
let et = ccx.sess.entry_type.unwrap();
if et == session::EntryMain {
let llfn = create_main(ccx, main_llfn);
create_entry_fn(ccx, llfn, true);
} else {
create_entry_fn(ccx, main_llfn, false);
}
fn create_main(ccx: @CrateContext, main_llfn: ValueRef) -> ValueRef {
let nt = ty::mk_nil(ccx.tcx);
......@@ -2242,7 +2246,7 @@ fn create_main(ccx: @CrateContext, main_llfn: ValueRef) -> ValueRef {
return llfdecl;
}
fn create_entry_fn(ccx: @CrateContext, rust_main: ValueRef) {
fn create_entry_fn(ccx: @CrateContext, rust_main: ValueRef, use_start_lang_item:bool) {
let llfty = T_fn(~[ccx.int_type, T_ptr(T_ptr(T_i8()))], ccx.int_type);
// FIXME #4404 android JNI hacks
......@@ -2264,34 +2268,51 @@ fn create_entry_fn(ccx: @CrateContext, rust_main: ValueRef) {
unsafe {
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
}
let crate_map = ccx.crate_map;
let start_def_id = ccx.tcx.lang_items.start_fn();
let start_fn = if start_def_id.crate == ast::local_crate {
ccx.sess.bug(~"start lang item is never in the local crate")
} else {
let start_fn_type = csearch::get_type(ccx.tcx,
start_def_id).ty;
trans_external_path(ccx, start_def_id, start_fn_type)
};
let retptr = unsafe {
llvm::LLVMBuildAlloca(bld, ccx.int_type, noname())
};
let args = unsafe {
let opaque_rust_main = llvm::LLVMBuildPointerCast(
bld, rust_main, T_ptr(T_i8()), noname());
let opaque_crate_map = llvm::LLVMBuildPointerCast(
bld, crate_map, T_ptr(T_i8()), noname());
~[
retptr,
C_null(T_opaque_box_ptr(ccx)),
opaque_rust_main,
llvm::LLVMGetParam(llfn, 0 as c_uint),
llvm::LLVMGetParam(llfn, 1 as c_uint),
opaque_crate_map
]
let crate_map = ccx.crate_map;
let opaque_crate_map = unsafe {llvm::LLVMBuildPointerCast(
bld, crate_map, T_ptr(T_i8()), noname())};
let (start_fn, args) = if use_start_lang_item {
let start_def_id = ccx.tcx.lang_items.start_fn();
let start_fn = if start_def_id.crate == ast::local_crate {
ccx.sess.bug(~"start lang item is never in the local crate")
} else {
let start_fn_type = csearch::get_type(ccx.tcx,
start_def_id).ty;
trans_external_path(ccx, start_def_id, start_fn_type)
};
let args = unsafe {
let opaque_rust_main = llvm::LLVMBuildPointerCast(
bld, rust_main, T_ptr(T_i8()), noname());
~[
retptr,
C_null(T_opaque_box_ptr(ccx)),
opaque_rust_main,
llvm::LLVMGetParam(llfn, 0 as c_uint),
llvm::LLVMGetParam(llfn, 1 as c_uint),
opaque_crate_map
]
};
(start_fn, args)
} else {
debug!("using user-defined start fn");
let args = unsafe {
~[ retptr,
C_null(T_opaque_box_ptr(ccx)),
llvm::LLVMGetParam(llfn, 0 as c_uint),
llvm::LLVMGetParam(llfn, 1 as c_uint),
opaque_crate_map
]
};
(rust_main, args)
};
unsafe {
......
......@@ -50,6 +50,8 @@
use core::prelude::*;
use driver::session;
use middle::resolve;
use middle::ty;
use util::common::time;
......@@ -62,7 +64,8 @@
use std::list;
use syntax::codemap::span;
use syntax::print::pprust::*;
use syntax::{ast, ast_map};
use syntax::{ast, ast_map, abi};
use syntax::opt_vec;
#[path = "check/mod.rs"]
pub mod check;
......@@ -325,12 +328,68 @@ fn check_main_fn_ty(ccx: @mut CrateCtxt,
}
}
fn check_for_main_fn(ccx: @mut CrateCtxt) {
fn check_start_fn_ty(ccx: @mut CrateCtxt,
start_id: ast::node_id,
start_span: span) {
let tcx = ccx.tcx;
let start_t = ty::node_id_to_type(tcx, start_id);
match ty::get(start_t).sty {
ty::ty_bare_fn(_) => {
match tcx.items.find(&start_id) {
Some(&ast_map::node_item(it,_)) => {
match it.node {
ast::item_fn(_,_,_,ref ps,_)
if ps.is_parameterized() => {
tcx.sess.span_err(
start_span,
~"start function is not allowed to have type \
parameters");
return;
}
_ => ()
}
}
_ => ()
}
fn arg(m: ast::rmode, ty: ty::t) -> ty::arg {
ty::arg {mode: ast::expl(m), ty: ty}
}
let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy {
purity: ast::impure_fn,
abis: abi::AbiSet::Rust(),
sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
inputs: ~[arg(ast::by_copy, ty::mk_int(tcx)),
arg(ast::by_copy, ty::mk_imm_ptr(tcx,
ty::mk_imm_ptr(tcx, ty::mk_u8(tcx)))),
arg(ast::by_copy, ty::mk_imm_ptr(tcx, ty::mk_u8(tcx)))],
output: ty::mk_int(tcx)}
});
require_same_types(tcx, None, false, start_span, start_t, se_ty,
|| fmt!("start function expects type: `%s`", ppaux::ty_to_str(ccx.tcx, se_ty)));
}
_ => {
tcx.sess.span_bug(start_span,
~"start has a non-function type: found `" +
ppaux::ty_to_str(tcx, start_t) + ~"`");
}
}
}
fn check_for_entry_fn(ccx: @mut CrateCtxt) {
let tcx = ccx.tcx;
if !*tcx.sess.building_library {
match *tcx.sess.main_fn {
Some((id, sp)) => check_main_fn_ty(ccx, id, sp),
None => tcx.sess.err(~"main function not found")
match *tcx.sess.entry_fn {
Some((id, sp)) => match *tcx.sess.entry_type {
Some(session::EntryMain) => check_main_fn_ty(ccx, id, sp),
Some(session::EntryStart) => check_start_fn_ty(ccx, id, sp),
None => tcx.sess.bug(~"entry function without a type")
},
None => tcx.sess.err(~"entry function not found")
}
}
}
......@@ -357,7 +416,7 @@ pub fn check_crate(tcx: ty::ctxt,
time(time_passes, ~"type checking", ||
check::check_item_types(ccx, crate));
check_for_main_fn(ccx);
check_for_entry_fn(ccx);
tcx.sess.abort_if_errors();
(ccx.method_map, ccx.vtable_map)
}
......
// Copyright 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.
#[start]
fn start(argc:int, argv: **u8, crate_map: *u8) -> int {
return 0;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册