auto merge of #6119 : brson/rust/main, r=brson
r? @ILyoan This pulls all the logic for discovering the crate entry point into a new pass (out of resolve and typeck), then changes it so that main is only looked for at the crate level (`#[main]` can still be used anywhere). I don't understand the special android logic here and worry that I may have broken it.
This commit is contained in:
commit
65ded84d20
|
@ -225,6 +225,9 @@ pub fn compile_rest(sess: Session,
|
||||||
time(time_passes, ~"resolution", ||
|
time(time_passes, ~"resolution", ||
|
||||||
middle::resolve::resolve_crate(sess, lang_items, crate));
|
middle::resolve::resolve_crate(sess, lang_items, crate));
|
||||||
|
|
||||||
|
time(time_passes, ~"looking for entry point",
|
||||||
|
|| middle::entry::find_entry_point(sess, crate, ast_map));
|
||||||
|
|
||||||
let freevars = time(time_passes, ~"freevar finding", ||
|
let freevars = time(time_passes, ~"freevar finding", ||
|
||||||
freevars::annotate_freevars(def_map, crate));
|
freevars::annotate_freevars(def_map, crate));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright 2012 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 driver::session;
|
||||||
|
use driver::session::Session;
|
||||||
|
use syntax::parse::token::special_idents;
|
||||||
|
use syntax::ast::{crate, node_id, item, item_fn};
|
||||||
|
use syntax::codemap::span;
|
||||||
|
use syntax::visit::{default_visitor, mk_vt, vt, Visitor, visit_crate, visit_item};
|
||||||
|
use syntax::attr::{attrs_contains_name};
|
||||||
|
use syntax::ast_map;
|
||||||
|
use core::util;
|
||||||
|
|
||||||
|
struct EntryContext {
|
||||||
|
session: Session,
|
||||||
|
|
||||||
|
ast_map: ast_map::map,
|
||||||
|
|
||||||
|
// The top-level function called 'main'
|
||||||
|
main_fn: Option<(node_id, span)>,
|
||||||
|
|
||||||
|
// The function that has attribute named 'main'
|
||||||
|
attr_main_fn: Option<(node_id, span)>,
|
||||||
|
|
||||||
|
// The function that has the attribute 'start' on it
|
||||||
|
start_fn: Option<(node_id, span)>,
|
||||||
|
|
||||||
|
// The functions that one might think are 'main' but aren't, e.g.
|
||||||
|
// main functions not defined at the top level. For diagnostics.
|
||||||
|
non_main_fns: ~[(node_id, span)],
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntryVisitor = vt<@mut EntryContext>;
|
||||||
|
|
||||||
|
pub fn find_entry_point(session: Session, crate: @crate, ast_map: ast_map::map) {
|
||||||
|
|
||||||
|
// FIXME #4404 android JNI hacks
|
||||||
|
if *session.building_library &&
|
||||||
|
session.targ_cfg.os != session::os_android {
|
||||||
|
// No need to find a main function
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctxt = @mut EntryContext {
|
||||||
|
session: session,
|
||||||
|
ast_map: ast_map,
|
||||||
|
main_fn: None,
|
||||||
|
attr_main_fn: None,
|
||||||
|
start_fn: None,
|
||||||
|
non_main_fns: ~[],
|
||||||
|
};
|
||||||
|
|
||||||
|
visit_crate(crate, ctxt, mk_vt(@Visitor {
|
||||||
|
visit_item: |item, ctxt, visitor| find_item(item, ctxt, visitor),
|
||||||
|
.. *default_visitor()
|
||||||
|
}));
|
||||||
|
|
||||||
|
configure_main(ctxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) {
|
||||||
|
match item.node {
|
||||||
|
item_fn(*) => {
|
||||||
|
if item.ident == special_idents::main {
|
||||||
|
match ctxt.ast_map.find(&item.id) {
|
||||||
|
Some(&ast_map::node_item(_, path)) => {
|
||||||
|
if path.len() == 0 {
|
||||||
|
// This is a top-level function so can be 'main'
|
||||||
|
if ctxt.main_fn.is_none() {
|
||||||
|
ctxt.main_fn = Some((item.id, item.span));
|
||||||
|
} else {
|
||||||
|
ctxt.session.span_err(
|
||||||
|
item.span,
|
||||||
|
~"multiple 'main' functions");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This isn't main
|
||||||
|
ctxt.non_main_fns.push((item.id, item.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => util::unreachable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if attrs_contains_name(item.attrs, ~"main") {
|
||||||
|
if ctxt.attr_main_fn.is_none() {
|
||||||
|
ctxt.attr_main_fn = Some((item.id, item.span));
|
||||||
|
} else {
|
||||||
|
ctxt.session.span_err(
|
||||||
|
item.span,
|
||||||
|
~"multiple 'main' functions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if attrs_contains_name(item.attrs, ~"start") {
|
||||||
|
if ctxt.start_fn.is_none() {
|
||||||
|
ctxt.start_fn = Some((item.id, item.span));
|
||||||
|
} else {
|
||||||
|
ctxt.session.span_err(
|
||||||
|
item.span,
|
||||||
|
~"multiple 'start' functions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
visit_item(item, ctxt, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_main(ctxt: @mut EntryContext) {
|
||||||
|
let this = &mut *ctxt;
|
||||||
|
if this.start_fn.is_some() {
|
||||||
|
*this.session.entry_fn = this.start_fn;
|
||||||
|
*this.session.entry_type = Some(session::EntryStart);
|
||||||
|
} else if this.attr_main_fn.is_some() {
|
||||||
|
*this.session.entry_fn = this.attr_main_fn;
|
||||||
|
*this.session.entry_type = Some(session::EntryMain);
|
||||||
|
} else if this.main_fn.is_some() {
|
||||||
|
*this.session.entry_fn = this.main_fn;
|
||||||
|
*this.session.entry_type = Some(session::EntryMain);
|
||||||
|
} else {
|
||||||
|
if !*this.session.building_library {
|
||||||
|
// No main function
|
||||||
|
this.session.err(~"main function not found");
|
||||||
|
if !this.non_main_fns.is_empty() {
|
||||||
|
// There were some functions named 'main' though. Try to give the user a hint.
|
||||||
|
this.session.note(~"the main function must be defined at the crate level \
|
||||||
|
but you have one or more functions named 'main' that are not \
|
||||||
|
defined at the crate level. Either move the definition or \
|
||||||
|
attach the `#[main]` attribute to override this behavior.");
|
||||||
|
for this.non_main_fns.each |&(_, span)| {
|
||||||
|
this.session.span_note(span, ~"here is a function named 'main'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.session.abort_if_errors();
|
||||||
|
} else {
|
||||||
|
// If we *are* building a library, then we're on android where we still might
|
||||||
|
// optionally want to translate main $4404
|
||||||
|
assert!(this.session.targ_cfg.os == session::os_android);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use driver::session;
|
|
||||||
use driver::session::Session;
|
use driver::session::Session;
|
||||||
use metadata::csearch::{each_path, get_trait_method_def_ids};
|
use metadata::csearch::{each_path, get_trait_method_def_ids};
|
||||||
use metadata::csearch::get_method_name_and_self_ty;
|
use metadata::csearch::get_method_name_and_self_ty;
|
||||||
|
@ -794,11 +793,6 @@ pub fn Resolver(session: Session,
|
||||||
|
|
||||||
namespaces: ~[ TypeNS, ValueNS ],
|
namespaces: ~[ TypeNS, ValueNS ],
|
||||||
|
|
||||||
attr_main_fn: None,
|
|
||||||
main_fns: ~[],
|
|
||||||
|
|
||||||
start_fn: None,
|
|
||||||
|
|
||||||
def_map: @mut HashMap::new(),
|
def_map: @mut HashMap::new(),
|
||||||
export_map2: @mut HashMap::new(),
|
export_map2: @mut HashMap::new(),
|
||||||
trait_map: HashMap::new(),
|
trait_map: HashMap::new(),
|
||||||
|
@ -856,15 +850,6 @@ pub struct Resolver {
|
||||||
// The four namespaces.
|
// The four namespaces.
|
||||||
namespaces: ~[Namespace],
|
namespaces: ~[Namespace],
|
||||||
|
|
||||||
// The function that has attribute named 'main'
|
|
||||||
attr_main_fn: Option<(node_id, span)>,
|
|
||||||
|
|
||||||
// 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,
|
def_map: DefMap,
|
||||||
export_map2: ExportMap2,
|
export_map2: ExportMap2,
|
||||||
trait_map: TraitMap,
|
trait_map: TraitMap,
|
||||||
|
@ -885,7 +870,6 @@ pub impl Resolver {
|
||||||
self.resolve_crate();
|
self.resolve_crate();
|
||||||
self.session.abort_if_errors();
|
self.session.abort_if_errors();
|
||||||
|
|
||||||
self.check_duplicate_main();
|
|
||||||
self.check_for_unused_imports_if_necessary();
|
self.check_for_unused_imports_if_necessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3544,40 +3528,6 @@ 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
|
|
||||||
if !*self.session.building_library ||
|
|
||||||
self.session.targ_cfg.os == session::os_android {
|
|
||||||
|
|
||||||
if self.attr_main_fn.is_none() &&
|
|
||||||
item.ident == special_idents::main {
|
|
||||||
|
|
||||||
self.main_fns.push(Some((item.id, item.span)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if attrs_contains_name(item.attrs, ~"main") {
|
|
||||||
if self.attr_main_fn.is_none() {
|
|
||||||
self.attr_main_fn = Some((item.id, item.span));
|
|
||||||
} else {
|
|
||||||
self.session.span_err(
|
|
||||||
item.span,
|
|
||||||
~"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,
|
self.resolve_function(OpaqueFunctionRibKind,
|
||||||
Some(fn_decl),
|
Some(fn_decl),
|
||||||
HasTypeParameters
|
HasTypeParameters
|
||||||
|
@ -5089,35 +5039,6 @@ pub impl Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// main function checking
|
|
||||||
//
|
|
||||||
// be sure that there is only one main function
|
|
||||||
//
|
|
||||||
fn check_duplicate_main(@mut self) {
|
|
||||||
let this = &mut *self;
|
|
||||||
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() {
|
|
||||||
let (_, dup_main_span) = this.main_fns[i].unwrap();
|
|
||||||
this.session.span_err(
|
|
||||||
dup_main_span,
|
|
||||||
~"multiple 'main' functions");
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
*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.entry_fn = this.attr_main_fn;
|
|
||||||
*this.session.entry_type = Some(session::EntryMain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Unused import checking
|
// Unused import checking
|
||||||
//
|
//
|
||||||
|
|
|
@ -393,7 +393,7 @@ fn check_for_entry_fn(ccx: @mut CrateCtxt) {
|
||||||
Some(session::EntryStart) => check_start_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.bug(~"entry function without a type")
|
||||||
},
|
},
|
||||||
None => tcx.sess.err(~"entry function not found")
|
None => tcx.sess.bug(~"type checking without entry function")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ pub mod middle {
|
||||||
pub mod lang_items;
|
pub mod lang_items;
|
||||||
pub mod privacy;
|
pub mod privacy;
|
||||||
pub mod moves;
|
pub mod moves;
|
||||||
|
pub mod entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod front {
|
pub mod front {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// error-pattern: entry function not found
|
// error-pattern: main function not found
|
||||||
|
|
||||||
// Since we're not compiling a test runner this function should be elided
|
// Since we're not compiling a test runner this function should be elided
|
||||||
// and the build will fail because main doesn't exist
|
// and the build will fail because main doesn't exist
|
||||||
|
|
|
@ -11,3 +11,5 @@
|
||||||
fn bad (p: *int) {
|
fn bad (p: *int) {
|
||||||
let _q: &int = p as ∫ //~ ERROR non-scalar cast
|
let _q: &int = p as ∫ //~ ERROR non-scalar cast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -8,10 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
fn main() {
|
mod m {
|
||||||
}
|
// An inferred main entry point (that doesn't use #[main])
|
||||||
|
// must appear at the top of the crate
|
||||||
mod foo {
|
fn main() { } //~ NOTE here is a function named 'main'
|
||||||
fn main() { //~ ERROR multiple 'main' functions
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -8,5 +8,5 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// error-pattern:entry function not found
|
// error-pattern:main function not found
|
||||||
fn mian() { }
|
fn mian() { }
|
||||||
|
|
|
@ -19,3 +19,5 @@ enum color {
|
||||||
black = 0x000000,
|
black = 0x000000,
|
||||||
white = 0x000000,
|
white = 0x000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -25,3 +25,5 @@ mod hello;
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
mod hello;
|
mod hello;
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -22,6 +22,7 @@ mod rusti {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
mod m {
|
mod m {
|
||||||
|
#[main]
|
||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -30,6 +31,7 @@ mod m {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[main]
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -41,6 +43,7 @@ mod m {
|
||||||
|
|
||||||
#[cfg(target_os = "win32")]
|
#[cfg(target_os = "win32")]
|
||||||
mod m {
|
mod m {
|
||||||
|
#[main]
|
||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -52,6 +55,7 @@ mod m {
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
mod m {
|
mod m {
|
||||||
|
#[main]
|
||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
Loading…
Reference in New Issue