From a860b0ec578d5fd212e5019024cbaa902d394820 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 13 Jan 2013 23:56:16 -0500 Subject: [PATCH 1/5] librustc: main fn searching/checks cleanup Move duplicate main check from trans to resolve and change trans to use main fn indicated in session. --- src/librustc/middle/resolve.rs | 11 ++++++----- src/librustc/middle/trans/base.rs | 20 +++++++++----------- src/librustc/middle/trans/common.rs | 1 - 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index a7c579127f954..27182f9958e58 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -3923,15 +3923,16 @@ impl Resolver { item_fn(ref fn_decl, _, ref ty_params, ref block) => { // If this is the main function, we must record it in the // session. - // - // For speed, we put the string comparison last in this chain - // of conditionals. if !self.session.building_library && - is_none(&self.session.main_fn) && item.ident == special_idents::main { - self.session.main_fn = Some((item.id, item.span)); + if is_none(&self.session.main_fn) { + self.session.main_fn = Some((item.id, item.span)); + } else { + self.session.span_fatal(item.span, ~"multiple 'main' functions"); + } + } self.resolve_function(OpaqueFunctionRibKind, diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index a8b0da47e9ac2..59bbca3383070 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -61,7 +61,6 @@ use middle::trans::shape::*; use middle::trans::tvec; use middle::trans::type_of::*; use util::common::indenter; -use util::common::is_main_name; use util::ppaux::{ty_to_str, ty_to_short_str}; use util::ppaux; @@ -2130,7 +2129,7 @@ fn register_fn_full(ccx: @crate_ctxt, } fn register_fn_fuller(ccx: @crate_ctxt, - sp: span, + _sp: span, +path: path, node_id: ast::node_id, attrs: &[ast::attribute], @@ -2152,21 +2151,21 @@ fn register_fn_fuller(ccx: @crate_ctxt, let llfn: ValueRef = decl_fn(ccx.llmod, copy ps, cc, llfty); ccx.item_symbols.insert(node_id, ps); - let is_main = is_main_name(path) && !ccx.sess.building_library; - if is_main { create_main_wrapper(ccx, sp, llfn); } + let is_main = match ccx.sess.main_fn { + Some((id, _)) => node_id == id, + // Shouldn't get to this branch + // since typeck catches no main + None => false + }; + if is_main { create_main_wrapper(ccx, llfn); } llfn } // Create a _rust_main(args: ~[str]) function which will be called from the // runtime rust_start function -fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef) { - - if ccx.main_fn != None:: { - ccx.sess.span_fatal(sp, ~"multiple 'main' functions"); - } +fn create_main_wrapper(ccx: @crate_ctxt, main_llfn: ValueRef) { let llfn = create_main(ccx, main_llfn); - ccx.main_fn = Some(llfn); create_entry_fn(ccx, llfn); fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef) -> ValueRef { @@ -2965,7 +2964,6 @@ fn trans_crate(sess: session::Session, exp_map2: emap2, reachable: reachable, item_symbols: HashMap(), - mut main_fn: None::, link_meta: copy link_meta, // XXX: Bad copy. enum_sizes: ty::new_ty_hash(), discrims: HashMap(), diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 5fd36228f7357..5a421e429b106 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -162,7 +162,6 @@ struct crate_ctxt { exp_map2: resolve::ExportMap2, reachable: reachable::map, item_symbols: HashMap, - mut main_fn: Option, link_meta: link_meta, enum_sizes: HashMap, discrims: HashMap, From 08e486cc6e1e2ff752f5e8d49ac581a31c06d7ba Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Mon, 14 Jan 2013 00:40:04 -0500 Subject: [PATCH 2/5] librustc: Add #[main] attribute Attribute to allow naming the entry point something other than `main`. --- src/librustc/middle/resolve.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 27182f9958e58..a84f3e7e70ba5 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -59,7 +59,7 @@ use syntax::ast_util::{def_id_of_def, dummy_sp, local_def}; use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method}; use syntax::ast_util::{Privacy, Public, Private, visibility_to_privacy}; use syntax::ast_util::has_legacy_export_attr; -use syntax::attr::{attr_metas, contains_name}; +use syntax::attr::{attr_metas, contains_name, find_attrs_by_name}; use syntax::parse::token::ident_interner; use syntax::parse::token::special_idents; use syntax::print::pprust::{pat_to_str, path_to_str}; @@ -3924,13 +3924,19 @@ impl Resolver { // If this is the main function, we must record it in the // session. - if !self.session.building_library && - item.ident == special_idents::main { + if !self.session.building_library { + + let has_main_attr = + find_attrs_by_name(item.attrs, ~"main").is_not_empty(); + + if item.ident == special_idents::main || has_main_attr { + + if is_none(&self.session.main_fn) { + self.session.main_fn = Some((item.id, item.span)); + } else { + self.session.span_fatal(item.span, ~"multiple 'main' functions"); + } - if is_none(&self.session.main_fn) { - self.session.main_fn = Some((item.id, item.span)); - } else { - self.session.span_fatal(item.span, ~"multiple 'main' functions"); } } From e6c98ab1f487017a90f00a1266392c695fb8cc22 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Mon, 14 Jan 2013 01:33:31 -0500 Subject: [PATCH 3/5] librustc: Handle multiple main fn's properly Functions explicitly marked with #[main] have precedence over the regular `main` fn. --- src/librustc/driver/session.rs | 2 +- src/librustc/middle/resolve.rs | 34 ++++++++++++++++++++++++------- src/librustc/middle/trans/base.rs | 2 +- src/librustc/middle/typeck/mod.rs | 2 +- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index ee34570203bc5..a622bffe114fd 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -155,7 +155,7 @@ type Session_ = {targ_cfg: @config, parse_sess: parse_sess, codemap: @codemap::CodeMap, // For a library crate, this is always none - mut main_fn: Option<(node_id, codemap::span)>, + mut main_fn: Option<(node_id, codemap::span, bool)>, span_diagnostic: diagnostic::span_handler, filesearch: filesearch::FileSearch, mut building_library: bool, diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index a84f3e7e70ba5..3f6e23f3ed143 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -3925,20 +3925,40 @@ impl Resolver { // session. if !self.session.building_library { - let has_main_attr = find_attrs_by_name(item.attrs, ~"main").is_not_empty(); + let called_main = item.ident == special_idents::main; + + if has_main_attr || called_main { + match self.session.main_fn { + Some((_, _, ident_main)) => { + + if ident_main && !has_main_attr || + !ident_main && has_main_attr { + + // Already found a fn called `main` + // or multple functions marked + // with #[main] + self.session.span_fatal(item.span, + ~"multiple 'main' functions"); + + } else if ident_main && has_main_attr { - if item.ident == special_idents::main || has_main_attr { + // Replace 'main' with fn explicitly + // marked #[main] + self.session.main_fn = + Some((item.id, item.span, called_main)); - if is_none(&self.session.main_fn) { - self.session.main_fn = Some((item.id, item.span)); - } else { - self.session.span_fatal(item.span, ~"multiple 'main' functions"); + } + + }, + None => { + self.session.main_fn = + Some((item.id, item.span, called_main)) + } } } - } self.resolve_function(OpaqueFunctionRibKind, diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 59bbca3383070..68cab2edbd767 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2152,7 +2152,7 @@ fn register_fn_fuller(ccx: @crate_ctxt, ccx.item_symbols.insert(node_id, ps); let is_main = match ccx.sess.main_fn { - Some((id, _)) => node_id == id, + Some((id, _, _)) => node_id == id, // Shouldn't get to this branch // since typeck catches no main None => false diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 509fe96508b2c..adabbbd5d8de2 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -391,7 +391,7 @@ fn check_for_main_fn(ccx: @crate_ctxt) { let tcx = ccx.tcx; if !tcx.sess.building_library { match copy tcx.sess.main_fn { - Some((id, sp)) => check_main_fn_ty(ccx, id, sp), + Some((id, sp, _)) => check_main_fn_ty(ccx, id, sp), None => tcx.sess.err(~"main function not found") } } From e887b9b2b6f128148fc217a1ae0fe778ea6c3c6c Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Mon, 14 Jan 2013 04:27:04 -0500 Subject: [PATCH 4/5] librustc: Use #[main] attribute in test pass. --- src/librustc/front/test.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 870a7d6c59377..da67a5a6d45c5 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -85,21 +85,25 @@ fn strip_test_functions(crate: @ast::crate) -> @ast::crate { fn fold_mod(cx: test_ctxt, m: ast::_mod, fld: fold::ast_fold) -> ast::_mod { - // Remove any defined main function from the AST so it doesn't clash with + // Remove all #[main] attributes from the AST so it doesn't clash with // the one we're going to add. Only if compiling an executable. - - // FIXME (#2403): This is sloppy. Instead we should have some mechanism to - // indicate to the translation pass which function we want to be main. fn nomain(cx: test_ctxt, item: @ast::item) -> Option<@ast::item> { - match item.node { - ast::item_fn(*) => { - if item.ident == cx.sess.ident_of(~"main") - && !cx.sess.building_library { - option::None - } else { option::Some(item) } - } - _ => option::Some(item) - } + + let it = @{ + ident: item.ident, + attrs: vec::filter_map(item.attrs, |attr| { + if !cx.sess.building_library && + attr::get_attr_name(*attr) == ~"main" { + None + } else { Some(copy *attr) } + }), + id: item.id, + node: copy item.node, + vis: item.vis, + span: item.span + }; + + Some(it) } let mod_nomain = @@ -498,7 +502,7 @@ fn mk_main(cx: test_ctxt) -> @ast::item { let item_ = ast::item_fn(decl, ast::impure_fn, ~[], body); let item: ast::item = {ident: cx.sess.ident_of(~"main"), - attrs: ~[], + attrs: ~[attr::mk_attr(attr::mk_word_item(~"main"))], id: cx.sess.next_node_id(), node: item_, vis: ast::public, From 15a5309d041256af2efdf9fd8026801cb71cff4c Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Mon, 14 Jan 2013 12:03:33 -0500 Subject: [PATCH 5/5] librustc: Fix edge cases for determining main fn. --- src/librustc/middle/resolve.rs | 41 ++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 3f6e23f3ed143..9f039651d3338 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -857,6 +857,8 @@ fn Resolver(session: Session, lang_items: LanguageItems, namespaces: ~[ TypeNS, ValueNS ], + have_main_attr: false, + def_map: HashMap(), export_map2: HashMap(), trait_map: @HashMap(), @@ -916,6 +918,9 @@ struct Resolver { // The four namespaces. namespaces: ~[Namespace], + // Whether there is any fn annotated with #[main] + mut have_main_attr: bool, + def_map: DefMap, export_map2: ExportMap2, trait_map: TraitMap, @@ -934,6 +939,8 @@ impl Resolver { self.record_exports(); self.session.abort_if_errors(); + self.find_if_main_attr(); + self.resolve_crate(); self.session.abort_if_errors(); @@ -3720,6 +3727,31 @@ impl Resolver { return None; } + // Find if there are any fn's with #[main] + fn find_if_main_attr(@self) { + visit_crate(*self.crate, (), mk_vt(@Visitor { + visit_item: |item, _context, _visitor| { + + match /*bad*/copy item.node { + + item_fn(*) => { + + if !self.session.building_library { + if find_attrs_by_name(item.attrs, ~"main") + .is_not_empty() { + self.have_main_attr = true; + } + } + + }, + _ => {} + } + + }, + .. *default_visitor() + })); + } + fn resolve_crate(@self) { debug!("(resolving crate) starting"); @@ -3933,8 +3965,9 @@ impl Resolver { match self.session.main_fn { Some((_, _, ident_main)) => { - if ident_main && !has_main_attr || - !ident_main && has_main_attr { + if (!ident_main && has_main_attr) || + (ident_main && !has_main_attr + && !self.have_main_attr) { // Already found a fn called `main` // or multple functions marked @@ -3947,14 +3980,14 @@ impl Resolver { // Replace 'main' with fn explicitly // marked #[main] self.session.main_fn = - Some((item.id, item.span, called_main)); + Some((item.id, item.span, !has_main_attr)); } }, None => { self.session.main_fn = - Some((item.id, item.span, called_main)) + Some((item.id, item.span, !has_main_attr)) } }