mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-25 06:03:16 +00:00
Accept main(args: [str]) as main signature
This commit is contained in:
parent
76aab80e39
commit
053b8bff5a
@ -6345,28 +6345,153 @@ fn decl_fn_and_pair_full(ccx: &@crate_ctxt, sp: &span, path: &[str],
|
||||
}
|
||||
_ { ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!"); }
|
||||
}
|
||||
let is_main: bool = is_main_name(path) && !ccx.sess.get_opts().library;
|
||||
// Declare the function itself.
|
||||
|
||||
let s: str =
|
||||
if is_main {
|
||||
"_rust_main"
|
||||
} else { mangle_internal_name_by_path(ccx, path) };
|
||||
let s: str = mangle_internal_name_by_path(ccx, path);
|
||||
let llfn: ValueRef = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
|
||||
// Declare the global constant pair that points to it.
|
||||
|
||||
let ps: str = mangle_exported_name(ccx, path, node_type);
|
||||
register_fn_pair(ccx, ps, llfty, llfn, node_id);
|
||||
|
||||
let is_main: bool = is_main_name(path) && !ccx.sess.get_opts().library;
|
||||
if is_main {
|
||||
if ccx.main_fn != none[ValueRef] {
|
||||
ccx.sess.span_fatal(sp, "multiple 'main' functions");
|
||||
}
|
||||
llvm::LLVMSetLinkage(llfn,
|
||||
lib::llvm::LLVMExternalLinkage as llvm::Linkage);
|
||||
ccx.main_fn = some(llfn);
|
||||
create_main_wrapper(ccx, sp, llfn, node_type);
|
||||
}
|
||||
}
|
||||
|
||||
fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span,
|
||||
main_llfn: ValueRef, main_node_type: ty::t) {
|
||||
|
||||
if ccx.main_fn != none[ValueRef] {
|
||||
ccx.sess.span_fatal(sp, "multiple 'main' functions");
|
||||
}
|
||||
|
||||
tag main_mode {
|
||||
mm_nil;
|
||||
mm_vec;
|
||||
mm_ivec;
|
||||
};
|
||||
|
||||
let main_mode = alt ty::struct(ccx.tcx, main_node_type) {
|
||||
ty::ty_fn(_, args, _ ,_ ,_) {
|
||||
if std::ivec::len(args) == 0u {
|
||||
mm_nil
|
||||
} else {
|
||||
alt ty::struct(ccx.tcx, args.(0).ty) {
|
||||
ty::ty_ivec(_) { mm_ivec }
|
||||
ty::ty_vec(_) { mm_vec }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Have to create two different main functions depending on whether
|
||||
// main was declared to take vec or ivec
|
||||
let llfn_vec = create_main_wrapper_vec(ccx, sp, main_llfn, main_mode);
|
||||
let llfn_ivec = create_main_wrapper_ivec(ccx, sp, main_llfn, main_mode);
|
||||
let takes_ivec = main_mode == mm_ivec;
|
||||
// Create a global to tell main.ll which main we want to use
|
||||
create_main_type_indicator(ccx, takes_ivec);
|
||||
ccx.main_fn = takes_ivec ? some(llfn_ivec) : some(llfn_vec);
|
||||
|
||||
fn create_main_wrapper_vec(ccx: &@crate_ctxt,
|
||||
sp: &span,
|
||||
main_llfn: ValueRef,
|
||||
main_mode: main_mode) -> ValueRef {
|
||||
|
||||
let vecarg = {
|
||||
mode: ty::mo_val,
|
||||
ty: ty::mk_vec(ccx.tcx, {
|
||||
ty: ty::mk_str(ccx.tcx),
|
||||
mut: ast::imm
|
||||
})
|
||||
};
|
||||
let llfty = type_of_fn(ccx, sp,
|
||||
ast::proto_fn,
|
||||
~[vecarg],
|
||||
ty::mk_nil(ccx.tcx),
|
||||
0u);
|
||||
let llfdecl = decl_fastcall_fn(ccx.llmod, "_rust_main", llfty);
|
||||
|
||||
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, llfdecl);
|
||||
let bcx = new_top_block_ctxt(fcx);
|
||||
|
||||
if main_mode != mm_ivec {
|
||||
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0u);
|
||||
let lltaskarg = llvm::LLVMGetParam(llfdecl, 1u);
|
||||
let llenvarg = llvm::LLVMGetParam(llfdecl, 2u);
|
||||
let llargvarg = llvm::LLVMGetParam(llfdecl, 3u);
|
||||
let args = alt main_mode {
|
||||
mm_nil. { ~[lloutputarg,
|
||||
lltaskarg,
|
||||
llenvarg] }
|
||||
mm_vec. { ~[lloutputarg,
|
||||
lltaskarg,
|
||||
llenvarg,
|
||||
llargvarg] }
|
||||
};
|
||||
bcx.build.FastCall(main_llfn, args);
|
||||
}
|
||||
bcx.build.RetVoid();
|
||||
|
||||
let lltop = bcx.llbb;
|
||||
finish_fn(fcx, lltop);
|
||||
|
||||
ret llfdecl;
|
||||
}
|
||||
|
||||
fn create_main_wrapper_ivec(ccx: &@crate_ctxt,
|
||||
sp: &span,
|
||||
main_llfn: ValueRef,
|
||||
main_mode: main_mode) -> ValueRef {
|
||||
let ivecarg = {
|
||||
mode: ty::mo_val,
|
||||
ty: ty::mk_ivec(ccx.tcx, {
|
||||
ty: ty::mk_str(ccx.tcx),
|
||||
mut: ast::imm
|
||||
})
|
||||
};
|
||||
let llfty = type_of_fn(ccx, sp,
|
||||
ast::proto_fn,
|
||||
~[ivecarg],
|
||||
ty::mk_nil(ccx.tcx),
|
||||
0u);
|
||||
let llfdecl = decl_fastcall_fn(ccx.llmod, "_rust_main_ivec", llfty);
|
||||
|
||||
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, llfdecl);
|
||||
let bcx = new_top_block_ctxt(fcx);
|
||||
|
||||
if main_mode == mm_ivec {
|
||||
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0u);
|
||||
let lltaskarg = llvm::LLVMGetParam(llfdecl, 1u);
|
||||
let llenvarg = llvm::LLVMGetParam(llfdecl, 2u);
|
||||
let llargvarg = llvm::LLVMGetParam(llfdecl, 3u);
|
||||
let args = ~[lloutputarg,
|
||||
lltaskarg,
|
||||
llenvarg,
|
||||
llargvarg];
|
||||
bcx.build.FastCall(main_llfn, args);
|
||||
}
|
||||
bcx.build.RetVoid();
|
||||
|
||||
let lltop = bcx.llbb;
|
||||
finish_fn(fcx, lltop);
|
||||
|
||||
ret llfdecl;
|
||||
}
|
||||
|
||||
// FIXME: Remove after main takes only ivec
|
||||
// Sets a global value hinting to the runtime whether main takes
|
||||
// a vec or an ivec
|
||||
fn create_main_type_indicator(ccx: &@crate_ctxt, takes_ivec: bool) {
|
||||
let i = llvm::LLVMAddGlobal(ccx.llmod, T_int(),
|
||||
str::buf("_rust_main_is_ivec"));
|
||||
llvm::LLVMSetInitializer(i, C_int(takes_ivec as int));
|
||||
llvm::LLVMSetGlobalConstant(i, True);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create a closure: a pair containing (1) a ValueRef, pointing to where the
|
||||
// fn's definition is in the executable we're creating, and (2) a pointer to
|
||||
// space for the function's environment.
|
||||
|
@ -2715,6 +2715,7 @@ fn check_item(ccx: @crate_ctxt, it: &@ast::item) {
|
||||
|
||||
fn arg_is_argv_ty(tcx: &ty::ctxt, a: &ty::arg) -> bool {
|
||||
alt ty::struct(tcx, a.ty) {
|
||||
// FIXME: Remove after main takes only ivec
|
||||
ty::ty_vec(mt) {
|
||||
if mt.mut != ast::imm { ret false; }
|
||||
alt ty::struct(tcx, mt.ty) {
|
||||
@ -2722,6 +2723,13 @@ fn arg_is_argv_ty(tcx: &ty::ctxt, a: &ty::arg) -> bool {
|
||||
_ { ret false; }
|
||||
}
|
||||
}
|
||||
ty::ty_ivec(mt) {
|
||||
if mt.mut != ast::imm { ret false; }
|
||||
alt ty::struct(tcx, mt.ty) {
|
||||
ty::ty_str. { ret true; }
|
||||
_ { ret false; }
|
||||
}
|
||||
}
|
||||
_ { ret false; }
|
||||
}
|
||||
}
|
||||
|
@ -6,23 +6,48 @@
|
||||
%5 = type { i32, i32, i32, i32, [0 x %6*] }
|
||||
%6 = type { i32, i32, i32, i32, [0 x i8] }
|
||||
|
||||
|
||||
@_rust_crate_map_toplevel = external global %0
|
||||
|
||||
declare fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %5*);
|
||||
declare i32 @rust_start(i32, i32, i32, i32)
|
||||
|
||||
%tydesc = type { %tydesc**, i32, i32, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*, i8*, i8)* }
|
||||
|
||||
%task = type { i32, i32, i32, i32, i32, i32, i32, i32 }
|
||||
|
||||
%ivec = type { i32, i32, [4 x { i32, i32, i32, i32, [0 x i8] }*] }
|
||||
|
||||
@_rust_crate_map_toplevel = external global %0
|
||||
|
||||
; FIXME: Remove after main takes only ivec
|
||||
@_rust_main_is_ivec = external global i32
|
||||
|
||||
declare i32 @rust_start(i32, i32, i32, i32)
|
||||
|
||||
declare external fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %5*);
|
||||
|
||||
define void @_rust_main_wrap(i1* nocapture, %task *, %2* nocapture, %5 *)
|
||||
{
|
||||
tail call fastcc void @_rust_main(i1* %0, %task *%1, %2* nocapture %2, %5 *%3)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @rust_start_ivec(i32, i32, i32, i32, i32)
|
||||
|
||||
declare external fastcc void @_rust_main_ivec(i1* nocapture, %task*, %2* nocapture, %ivec)
|
||||
|
||||
define void @_rust_main_wrap_ivec(i1* nocapture, %task *, %2* nocapture, %ivec *)
|
||||
{
|
||||
%ivec = load %ivec *%3
|
||||
tail call fastcc void @_rust_main_ivec(i1* %0, %task *%1, %2* nocapture %2, %ivec %ivec)
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @"MAIN"(i32, i32) {
|
||||
%is_ivec = load i32 *@_rust_main_is_ivec
|
||||
%is_ivec1 = trunc i32 %is_ivec to i1
|
||||
br i1 %is_ivec1, label %ivec, label %evec
|
||||
|
||||
evec:
|
||||
%3 = tail call i32 @rust_start(i32 ptrtoint (void (i1*, %task*, %2*, %5*)* @_rust_main_wrap to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32))
|
||||
ret i32 %3
|
||||
|
||||
ivec:
|
||||
%4 = tail call i32 @rust_start_ivec(i32 ptrtoint (void (i1*, %task*, %2*, %ivec*)* @_rust_main_wrap_ivec to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32), i32 %is_ivec)
|
||||
ret i32 %4
|
||||
}
|
||||
|
@ -10,10 +10,12 @@ command_line_args : public kernel_owned<command_line_args>
|
||||
|
||||
// vec[str] passed to rust_task::start.
|
||||
rust_vec *args;
|
||||
rust_ivec *args_ivec;
|
||||
|
||||
command_line_args(rust_task *task,
|
||||
int sys_argc,
|
||||
char **sys_argv)
|
||||
char **sys_argv,
|
||||
bool main_is_ivec)
|
||||
: kernel(task->kernel),
|
||||
task(task),
|
||||
argc(sys_argc),
|
||||
@ -49,15 +51,39 @@ command_line_args : public kernel_owned<command_line_args>
|
||||
mem = kernel->malloc(str_alloc, "command line arg");
|
||||
strs[i] = new (mem) rust_str(str_alloc, str_fill,
|
||||
(uint8_t const *)argv[i]);
|
||||
strs[i]->ref_count++;
|
||||
}
|
||||
args->fill = vec_fill;
|
||||
// If the caller has a declared args array, they may drop; but
|
||||
// we don't know if they have such an array. So we pin the args
|
||||
// array here to ensure it survives to program-shutdown.
|
||||
args->ref();
|
||||
|
||||
if (main_is_ivec) {
|
||||
size_t ivec_interior_sz =
|
||||
sizeof(size_t) * 2 + sizeof(rust_str *) * 4;
|
||||
args_ivec = (rust_ivec *)
|
||||
kernel->malloc(ivec_interior_sz,
|
||||
"command line arg interior");
|
||||
args_ivec->fill = 0;
|
||||
size_t ivec_exterior_sz = sizeof(rust_str *) * argc;
|
||||
args_ivec->alloc = ivec_exterior_sz;
|
||||
// NB: This is freed by some ivec machinery, probably the drop
|
||||
// glue in main, so we don't free it ourselves
|
||||
args_ivec->payload.ptr = (rust_ivec_heap *)
|
||||
kernel->malloc(ivec_exterior_sz + sizeof(size_t),
|
||||
"command line arg exterior");
|
||||
args_ivec->payload.ptr->fill = ivec_exterior_sz;
|
||||
memcpy(&args_ivec->payload.ptr->data, strs, ivec_exterior_sz);
|
||||
} else {
|
||||
args_ivec = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~command_line_args() {
|
||||
if (args_ivec) {
|
||||
kernel->free(args_ivec);
|
||||
}
|
||||
if (args) {
|
||||
// Drop the args we've had pinned here.
|
||||
rust_str **strs = (rust_str**) &args->data[0];
|
||||
@ -84,7 +110,8 @@ command_line_args : public kernel_owned<command_line_args>
|
||||
int check_claims = 0;
|
||||
|
||||
extern "C" CDECL int
|
||||
rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
|
||||
rust_start_ivec(uintptr_t main_fn, int argc, char **argv,
|
||||
void* crate_map, int main_is_ivec) {
|
||||
|
||||
rust_env *env = load_env();
|
||||
|
||||
@ -99,7 +126,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
|
||||
rust_scheduler *sched = root_task->sched;
|
||||
command_line_args *args
|
||||
= new (kernel, "main command line args")
|
||||
command_line_args(root_task, argc, argv);
|
||||
command_line_args(root_task, argc, argv, main_is_ivec);
|
||||
|
||||
DLOG(sched, dom, "startup: %d args in 0x%" PRIxPTR,
|
||||
args->argc, (uintptr_t)args->args);
|
||||
@ -107,7 +134,13 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
|
||||
DLOG(sched, dom, "startup: arg[%d] = '%s'", i, args->argv[i]);
|
||||
}
|
||||
|
||||
root_task->start(main_fn, (uintptr_t)args->args);
|
||||
if (main_is_ivec) {
|
||||
DLOG(sched, dom, "main takes ivec");
|
||||
root_task->start(main_fn, (uintptr_t)args->args_ivec);
|
||||
} else {
|
||||
DLOG(sched, dom, "main takes vec");
|
||||
root_task->start(main_fn, (uintptr_t)args->args);
|
||||
}
|
||||
root_task->deref();
|
||||
root_task = NULL;
|
||||
|
||||
@ -127,6 +160,13 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" CDECL int
|
||||
rust_start(uintptr_t main_fn, int argc, char **argv,
|
||||
void* crate_map) {
|
||||
return rust_start_ivec(main_fn, argc, argv, crate_map, 0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: C++
|
||||
|
@ -62,6 +62,7 @@ rust_process_wait
|
||||
rust_ptr_eq
|
||||
rust_run_program
|
||||
rust_start
|
||||
rust_start_ivec
|
||||
rust_getcwd
|
||||
set_min_stack
|
||||
sched_threads
|
||||
|
3
src/test/run-pass/main-ivec.rs
Normal file
3
src/test/run-pass/main-ivec.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main(args: [str]) {
|
||||
for s in args { log s }
|
||||
}
|
Loading…
Reference in New Issue
Block a user