Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only look for main at the crate level #6119

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ pub fn compile_rest(sess: Session,
time(time_passes, ~"resolution", ||
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", ||
freevars::annotate_freevars(def_map, crate));

Expand Down
150 changes: 150 additions & 0 deletions src/librustc/middle/entry.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
79 changes: 0 additions & 79 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use driver::session;
use driver::session::Session;
use metadata::csearch::{each_path, get_trait_method_def_ids};
use metadata::csearch::get_method_name_and_self_ty;
Expand Down Expand Up @@ -794,11 +793,6 @@ pub fn Resolver(session: Session,

namespaces: ~[ TypeNS, ValueNS ],

attr_main_fn: None,
main_fns: ~[],

start_fn: None,

def_map: @mut HashMap::new(),
export_map2: @mut HashMap::new(),
trait_map: HashMap::new(),
Expand Down Expand Up @@ -856,15 +850,6 @@ pub struct Resolver {
// The four namespaces.
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,
export_map2: ExportMap2,
trait_map: TraitMap,
Expand All @@ -885,7 +870,6 @@ pub impl Resolver {
self.resolve_crate();
self.session.abort_if_errors();

self.check_duplicate_main();
self.check_for_unused_imports_if_necessary();
}

Expand Down Expand Up @@ -3545,40 +3529,6 @@ pub impl Resolver {
}

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,
Some(fn_decl),
HasTypeParameters
Expand Down Expand Up @@ -5109,35 +5059,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
//
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/typeck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ fn check_for_entry_fn(ccx: @mut CrateCtxt) {
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")
None => tcx.sess.bug(~"type checking without entry function")
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/rustc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub mod middle {
pub mod lang_items;
pub mod privacy;
pub mod moves;
pub mod entry;
}

pub mod front {
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/elided-test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// 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
// and the build will fail because main doesn't exist
Expand Down
2 changes: 2 additions & 0 deletions src/test/compile-fail/issue-2995.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
fn bad (p: *int) {
let _q: &int = p as &int; //~ ERROR non-scalar cast
}

fn main() { }
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
}

mod foo {
fn main() { //~ ERROR multiple 'main' functions
}
}
mod m {
// An inferred main entry point (that doesn't use #[main])
// must appear at the top of the crate
fn main() { } //~ NOTE here is a function named 'main'
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/missing-main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// error-pattern:entry function not found
// error-pattern:main function not found
fn mian() { }
2 changes: 2 additions & 0 deletions src/test/compile-fail/tag-variant-disr-dup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ enum color {
black = 0x000000,
white = 0x000000,
}

fn main() { }
2 changes: 2 additions & 0 deletions src/test/run-pass/dupe-first-attr.rc
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ mod hello;

#[cfg(target_os = "android")]
mod hello;

fn main() { }
4 changes: 4 additions & 0 deletions src/test/run-pass/intrinsic-alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod rusti {
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
mod m {
#[main]
#[cfg(target_arch = "x86")]
pub fn main() {
unsafe {
Expand All @@ -30,6 +31,7 @@ mod m {
}
}

#[main]
#[cfg(target_arch = "x86_64")]
pub fn main() {
unsafe {
Expand All @@ -41,6 +43,7 @@ mod m {

#[cfg(target_os = "win32")]
mod m {
#[main]
#[cfg(target_arch = "x86")]
pub fn main() {
unsafe {
Expand All @@ -52,6 +55,7 @@ mod m {

#[cfg(target_os = "android")]
mod m {
#[main]
#[cfg(target_arch = "arm")]
pub fn main() {
unsafe {
Expand Down