Skip to content

Commit f26ca02

Browse files
committed
Make resolve and the typechecker check for a main fn of the
correct type This means if a non-library program leaves out the main program, the error gets caught earlier than link. Closes #626.
1 parent 196753e commit f26ca02

File tree

9 files changed

+89
-10
lines changed

9 files changed

+89
-10
lines changed

src/comp/driver/rustc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ fn build_session(@session::options sopts) -> session::session {
361361
auto cstore = cstore::mk_cstore();
362362
ret session::session(target_cfg, sopts, cstore,
363363
@rec(cm=codemap::new_codemap(), mutable next_id=0),
364-
0u);
364+
none, 0u);
365365
}
366366

367367
fn parse_pretty(session::session sess, &str name) -> pp_mode {

src/comp/driver/session.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
import syntax::ast;
3+
import syntax::ast::node_id;
34
import syntax::codemap;
45
import codemap::span;
56
import syntax::ast::ty_mach;
@@ -49,6 +50,8 @@ obj session(@config targ_cfg,
4950
@options opts,
5051
metadata::cstore::cstore cstore,
5152
parse_sess parse_sess,
53+
// For a library crate, this is always none
54+
mutable option::t[node_id] main_fn,
5255
mutable uint err_count) {
5356
fn get_targ_cfg() -> @config { ret targ_cfg; }
5457
fn get_opts() -> @options { ret opts; }
@@ -110,6 +113,10 @@ obj session(@config targ_cfg,
110113
fn span_str(span sp) -> str {
111114
ret codemap::span_to_str(sp, self.get_codemap());
112115
}
116+
fn set_main_id(node_id d) {
117+
main_fn = some(d);
118+
}
119+
fn get_main_id() -> option::t[node_id] { main_fn }
113120
}
114121
// Local Variables:
115122
// fill-column: 78;

src/comp/middle/resolve.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import ast::local_def;
1010
import metadata::csearch;
1111
import metadata::cstore;
1212
import driver::session::session;
13-
import util::common::new_def_hash;
13+
import util::common::*;
1414
import std::map::new_int_hash;
1515
import std::map::new_str_hash;
1616
import syntax::codemap::span;
@@ -337,6 +337,18 @@ fn visit_native_item_with_scope(&@ast::native_item ni, &scopes sc,
337337
fn visit_fn_with_scope(&@env e, &ast::_fn f, &ast::ty_param[] tp, &span sp,
338338
&fn_ident name, node_id id, &scopes sc,
339339
&vt[scopes] v) {
340+
// is this a main fn declaration?
341+
alt (name) {
342+
case (some(?nm)) {
343+
if (is_main_name(~[nm]) && !e.sess.get_opts().library) {
344+
// This is a main function -- set it in the session
345+
// as the main ID
346+
e.sess.set_main_id(id);
347+
}
348+
}
349+
case (_) {}
350+
}
351+
340352
// here's where we need to set up the mapping
341353
// for f's constrs in the table.
342354

src/comp/middle/trans.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ import back::upcall;
3333
import syntax::visit;
3434
import visit::vt;
3535
import util::common;
36-
import util::common::new_def_hash;
36+
import util::common::*;
3737
import std::map::new_int_hash;
3838
import std::map::new_str_hash;
39-
import util::common::local_rhs_span;
4039
import syntax::codemap::span;
4140
import lib::llvm::llvm;
4241
import lib::llvm::builder;
@@ -8586,9 +8585,7 @@ fn decl_fn_and_pair_full(&@crate_ctxt ccx, &span sp, &str[] path, str flav,
85868585
ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
85878586
}
85888587
}
8589-
let bool is_main =
8590-
str::eq(option::get(std::ivec::last(path)), "main") &&
8591-
!ccx.sess.get_opts().library;
8588+
let bool is_main = is_main_name(path) && !ccx.sess.get_opts().library;
85928589
// Declare the function itself.
85938590

85948591
let str s =

src/comp/middle/typeck.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,8 +1624,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
16241624
alt (operator.node) {
16251625
case (ast::expr_path(?oper_name)) {
16261626
alt (fcx.ccx.tcx.def_map.find(operator.id)) {
1627-
case (some(ast::def_fn(?_d_id,
1628-
ast::pure_fn))) {
1627+
case (some(ast::def_fn(_, ast::pure_fn))) {
16291628
// do nothing
16301629
}
16311630
case (_) {
@@ -2655,6 +2654,54 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) {
26552654
}
26562655
}
26572656

2657+
fn arg_is_argv_ty(&ty::ctxt tcx, &ty::arg a) -> bool {
2658+
alt (ty::struct(tcx, a.ty)) {
2659+
case (ty::ty_vec(?mt)) {
2660+
if (mt.mut != ast::imm) { ret false; }
2661+
alt (ty::struct(tcx, mt.ty)) {
2662+
case (ty::ty_str) { ret true; }
2663+
case (_) { ret false; }
2664+
}
2665+
}
2666+
case (_) { ret false; }
2667+
}
2668+
}
2669+
2670+
fn check_main_fn_ty(&ty::ctxt tcx, &ast::node_id main_id) {
2671+
auto main_t = ty::node_id_to_monotype(tcx, main_id);
2672+
alt (ty::struct(tcx, main_t)) {
2673+
case (ty::ty_fn(ast::proto_fn, ?args, ?rs, ast::return, ?constrs)) {
2674+
auto ok = ivec::len(constrs) == 0u;
2675+
ok &= ty::type_is_nil(tcx, rs);
2676+
auto num_args = ivec::len(args);
2677+
ok &= num_args == 0u || (num_args == 1u &&
2678+
arg_is_argv_ty(tcx, args.(0)));
2679+
if (!ok) {
2680+
tcx.sess.err("Wrong type in main function: found "
2681+
+ ty_to_str(tcx, main_t));
2682+
}
2683+
}
2684+
case (_) {
2685+
tcx.sess.err("Main has a non-function type: found"
2686+
+ ty_to_str(tcx, main_t));
2687+
}
2688+
}
2689+
}
2690+
2691+
fn check_for_main_fn(&ty::ctxt tcx, &@ast::crate crate) {
2692+
if (!tcx.sess.get_opts().library) {
2693+
alt (tcx.sess.get_main_id()) {
2694+
case (some(?id)) {
2695+
check_main_fn_ty(tcx, id);
2696+
}
2697+
case (none) {
2698+
tcx.sess.span_err(crate.span,
2699+
"Main function not found");
2700+
}
2701+
}
2702+
}
2703+
}
2704+
26582705
fn check_crate(&ty::ctxt tcx, &@ast::crate crate) {
26592706
collect::collect_item_types(tcx, crate);
26602707

@@ -2666,6 +2713,7 @@ fn check_crate(&ty::ctxt tcx, &@ast::crate crate) {
26662713
rec(visit_item_pre=bind check_item(ccx, _)
26672714
with walk::default_visitor());
26682715
walk::walk_crate(visit, *crate);
2716+
check_for_main_fn(tcx, crate);
26692717
tcx.sess.abort_if_errors();
26702718
}
26712719
//

src/comp/util/common.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
import std::str;
22
import std::map;
33
import std::map::hashmap;
44
import std::uint;
@@ -187,6 +187,9 @@ fn call_kind_str(call_kind c) -> str {
187187
}
188188
}
189189

190+
fn is_main_name(&str[] path) -> bool {
191+
str::eq(option::get(std::ivec::last(path)), "main")
192+
}
190193
//
191194
// Local Variables:
192195
// mode: rust
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// xfail-stage0
2+
// error-pattern:Wrong type in main function: found fn() -> char
3+
fn main() -> char {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// xfail-stage0
2+
// error-pattern:Wrong type in main function: found fn(rec(int x
3+
fn main(rec(int x, int y) foo) {
4+
}

src/test/compile-fail/missing-main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// xfail-stage0
2+
// error-pattern:Main function not found
3+
fn mian() {
4+
}

0 commit comments

Comments
 (0)