]>
git.proxmox.com Git - rustc.git/blob - src/librustc/middle/entry.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use dep_graph
::DepNode
;
13 use hir
::map
as ast_map
;
14 use hir
::def_id
::{CRATE_DEF_INDEX}
;
15 use session
::{config, Session}
;
16 use syntax
::ast
::NodeId
;
18 use syntax
::codemap
::Span
;
19 use syntax
::entry
::EntryPointType
;
20 use hir
::{Item, ItemFn}
;
21 use hir
::intravisit
::Visitor
;
23 struct EntryContext
<'a
, 'tcx
: 'a
> {
26 map
: &'a ast_map
::Map
<'tcx
>,
28 // The top-level function called 'main'
29 main_fn
: Option
<(NodeId
, Span
)>,
31 // The function that has attribute named 'main'
32 attr_main_fn
: Option
<(NodeId
, Span
)>,
34 // The function that has the attribute 'start' on it
35 start_fn
: Option
<(NodeId
, Span
)>,
37 // The functions that one might think are 'main' but aren't, e.g.
38 // main functions not defined at the top level. For diagnostics.
39 non_main_fns
: Vec
<(NodeId
, Span
)> ,
42 impl<'a
, 'tcx
> Visitor
<'tcx
> for EntryContext
<'a
, 'tcx
> {
43 fn visit_item(&mut self, item
: &'tcx Item
) {
44 let def_id
= self.map
.local_def_id(item
.id
);
45 let def_key
= self.map
.def_key(def_id
);
46 let at_root
= def_key
.parent
== Some(CRATE_DEF_INDEX
);
47 find_item(item
, self, at_root
);
51 pub fn find_entry_point(session
: &Session
, ast_map
: &ast_map
::Map
) {
52 let _task
= ast_map
.dep_graph
.in_task(DepNode
::EntryPoint
);
54 let any_exe
= session
.crate_types
.borrow().iter().any(|ty
| {
55 *ty
== config
::CrateTypeExecutable
58 // No need to find a main function
62 // If the user wants no main function at all, then stop here.
63 if attr
::contains_name(&ast_map
.krate().attrs
, "no_main") {
64 session
.entry_type
.set(Some(config
::EntryNone
));
68 let mut ctxt
= EntryContext
{
74 non_main_fns
: Vec
::new(),
77 ast_map
.krate().visit_all_items(&mut ctxt
);
79 configure_main(&mut ctxt
);
82 // Beware, this is duplicated in libsyntax/entry.rs, make sure to keep
84 fn entry_point_type(item
: &Item
, at_root
: bool
) -> EntryPointType
{
87 if attr
::contains_name(&item
.attrs
, "start") {
89 } else if attr
::contains_name(&item
.attrs
, "main") {
90 EntryPointType
::MainAttr
91 } else if item
.name
.as_str() == "main" {
93 // This is a top-level function so can be 'main'
94 EntryPointType
::MainNamed
96 EntryPointType
::OtherMain
102 _
=> EntryPointType
::None
,
107 fn find_item(item
: &Item
, ctxt
: &mut EntryContext
, at_root
: bool
) {
108 match entry_point_type(item
, at_root
) {
109 EntryPointType
::MainNamed
=> {
110 if ctxt
.main_fn
.is_none() {
111 ctxt
.main_fn
= Some((item
.id
, item
.span
));
113 span_err
!(ctxt
.session
, item
.span
, E0136
,
114 "multiple 'main' functions");
117 EntryPointType
::OtherMain
=> {
118 ctxt
.non_main_fns
.push((item
.id
, item
.span
));
120 EntryPointType
::MainAttr
=> {
121 if ctxt
.attr_main_fn
.is_none() {
122 ctxt
.attr_main_fn
= Some((item
.id
, item
.span
));
124 span_err
!(ctxt
.session
, item
.span
, E0137
,
125 "multiple functions with a #[main] attribute");
128 EntryPointType
::Start
=> {
129 if ctxt
.start_fn
.is_none() {
130 ctxt
.start_fn
= Some((item
.id
, item
.span
));
132 span_err
!(ctxt
.session
, item
.span
, E0138
,
133 "multiple 'start' functions");
136 EntryPointType
::None
=> ()
140 fn configure_main(this
: &mut EntryContext
) {
141 if this
.start_fn
.is_some() {
142 *this
.session
.entry_fn
.borrow_mut() = this
.start_fn
;
143 this
.session
.entry_type
.set(Some(config
::EntryStart
));
144 } else if this
.attr_main_fn
.is_some() {
145 *this
.session
.entry_fn
.borrow_mut() = this
.attr_main_fn
;
146 this
.session
.entry_type
.set(Some(config
::EntryMain
));
147 } else if this
.main_fn
.is_some() {
148 *this
.session
.entry_fn
.borrow_mut() = this
.main_fn
;
149 this
.session
.entry_type
.set(Some(config
::EntryMain
));
152 let mut err
= this
.session
.struct_err("main function not found");
153 if !this
.non_main_fns
.is_empty() {
154 // There were some functions named 'main' though. Try to give the user a hint.
155 err
.note("the main function must be defined at the crate level \
156 but you have one or more functions named 'main' that are not \
157 defined at the crate level. Either move the definition or \
158 attach the `#[main]` attribute to override this behavior.");
159 for &(_
, span
) in &this
.non_main_fns
{
160 err
.span_note(span
, "here is a function named 'main'");
163 this
.session
.abort_if_errors();