diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index c6e5b654f9a..8cdd4f7fe74 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -11,20 +11,19 @@ use ast_map; use session::{config, Session}; -use syntax::ast::{Name, NodeId, Item, ItemFn}; +use syntax; +use syntax::ast::{NodeId, Item}; use syntax::attr; use syntax::codemap::Span; -use syntax::parse::token; +use syntax::entry::EntryPointType; use syntax::visit; use syntax::visit::Visitor; -struct EntryContext<'a, 'ast: 'a> { +struct EntryContext<'a> { session: &'a Session, - ast_map: &'a ast_map::Map<'ast>, - - // The interned Name for "main". - main_name: Name, + // The current depth in the ast + depth: usize, // The top-level function called 'main' main_fn: Option<(NodeId, Span)>, @@ -40,9 +39,11 @@ struct EntryContext<'a, 'ast: 'a> { non_main_fns: Vec<(NodeId, Span)> , } -impl<'a, 'ast, 'v> Visitor<'v> for EntryContext<'a, 'ast> { +impl<'a, 'v> Visitor<'v> for EntryContext<'a> { fn visit_item(&mut self, item: &Item) { + self.depth += 1; find_item(item, self); + self.depth -= 1; } } @@ -63,8 +64,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { let mut ctxt = EntryContext { session: session, - main_name: token::intern("main"), - ast_map: ast_map, + depth: 0, main_fn: None, attr_main_fn: None, start_fn: None, @@ -77,44 +77,35 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { } fn find_item(item: &Item, ctxt: &mut EntryContext) { - match item.node { - ItemFn(..) => { - if item.ident.name == ctxt.main_name { - ctxt.ast_map.with_path(item.id, |path| { - if path.count() == 1 { - // 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 { - span_err!(ctxt.session, item.span, E0136, - "multiple 'main' functions"); - } - } else { - // This isn't main - ctxt.non_main_fns.push((item.id, item.span)); - } - }); + match syntax::entry::entry_point_type(item, ctxt.depth) { + EntryPointType::MainNamed => { + if ctxt.main_fn.is_none() { + ctxt.main_fn = Some((item.id, item.span)); + } else { + span_err!(ctxt.session, item.span, E0136, + "multiple 'main' functions"); } - - if attr::contains_name(&item.attrs, "main") { - if ctxt.attr_main_fn.is_none() { - ctxt.attr_main_fn = Some((item.id, item.span)); - } else { - span_err!(ctxt.session, item.span, E0137, - "multiple functions with a #[main] attribute"); - } + }, + EntryPointType::OtherMain => { + ctxt.non_main_fns.push((item.id, item.span)); + }, + EntryPointType::MainAttr => { + if ctxt.attr_main_fn.is_none() { + ctxt.attr_main_fn = Some((item.id, item.span)); + } else { + span_err!(ctxt.session, item.span, E0137, + "multiple functions with a #[main] attribute"); } - - if attr::contains_name(&item.attrs, "start") { - if ctxt.start_fn.is_none() { - ctxt.start_fn = Some((item.id, item.span)); - } else { - span_err!(ctxt.session, item.span, E0138, - "multiple 'start' functions"); - } + }, + EntryPointType::Start => { + if ctxt.start_fn.is_none() { + ctxt.start_fn = Some((item.id, item.span)); + } else { + span_err!(ctxt.session, item.span, E0138, + "multiple 'start' functions"); } - } - _ => () + }, + EntryPointType::None => () } visit::walk_item(ctxt, item); diff --git a/src/libsyntax/entry.rs b/src/libsyntax/entry.rs new file mode 100644 index 00000000000..b6c5d0066a2 --- /dev/null +++ b/src/libsyntax/entry.rs @@ -0,0 +1,42 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use attr; +use ast::{Item, ItemFn}; + +pub enum EntryPointType { + None, + MainNamed, + MainAttr, + Start, + OtherMain, // Not an entry point, but some other function named main +} + +pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType { + match item.node { + ItemFn(..) => { + if attr::contains_name(&item.attrs, "start") { + EntryPointType::Start + } else if attr::contains_name(&item.attrs, "main") { + EntryPointType::MainAttr + } else if item.ident.name == "main" { + if depth == 1 { + // This is a top-level function so can be 'main' + EntryPointType::MainNamed + } else { + EntryPointType::OtherMain + } + } else { + EntryPointType::None + } + } + _ => EntryPointType::None, + } +} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 0d1fa6dd726..d1c862ad40b 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -90,6 +90,7 @@ pub mod attr; pub mod codemap; pub mod config; pub mod diagnostic; +pub mod entry; pub mod feature_gate; pub mod fold; pub mod owned_slice;