]> git.proxmox.com Git - rustc.git/blame - src/librustc/middle/entry.rs
New upstream version 1.27.1+dfsg1
[rustc.git] / src / librustc / middle / entry.rs
CommitLineData
970d7e83
LB
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.
4//
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.
10
11
32a655c1 12use hir::map as hir_map;
54a0048b 13use hir::def_id::{CRATE_DEF_INDEX};
1a4d82fc 14use session::{config, Session};
e9174d1e 15use syntax::ast::NodeId;
b039eaaf 16use syntax::attr;
e9174d1e 17use syntax::entry::EntryPointType;
3157f602 18use syntax_pos::Span;
32a655c1 19use hir::{Item, ItemFn, ImplItem, TraitItem};
476ff2be 20use hir::itemlikevisit::ItemLikeVisitor;
970d7e83 21
92a42be0 22struct EntryContext<'a, 'tcx: 'a> {
1a4d82fc 23 session: &'a Session,
970d7e83 24
32a655c1 25 map: &'a hir_map::Map<'tcx>,
970d7e83
LB
26
27 // The top-level function called 'main'
1a4d82fc 28 main_fn: Option<(NodeId, Span)>,
970d7e83
LB
29
30 // The function that has attribute named 'main'
1a4d82fc 31 attr_main_fn: Option<(NodeId, Span)>,
970d7e83
LB
32
33 // The function that has the attribute 'start' on it
1a4d82fc 34 start_fn: Option<(NodeId, Span)>,
970d7e83
LB
35
36 // The functions that one might think are 'main' but aren't, e.g.
37 // main functions not defined at the top level. For diagnostics.
1a4d82fc 38 non_main_fns: Vec<(NodeId, Span)> ,
970d7e83
LB
39}
40
476ff2be 41impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
92a42be0
SL
42 fn visit_item(&mut self, item: &'tcx Item) {
43 let def_id = self.map.local_def_id(item.id);
44 let def_key = self.map.def_key(def_id);
45 let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
46 find_item(item, self, at_root);
1a4d82fc 47 }
476ff2be 48
32a655c1
SL
49 fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem) {
50 // entry fn is never a trait item
51 }
476ff2be
SL
52
53 fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
54 // entry fn is never an impl item
55 }
1a4d82fc 56}
970d7e83 57
0531ce1d
XL
58pub fn find_entry_point(session: &Session,
59 hir_map: &hir_map::Map,
60 crate_name: &str) {
1a4d82fc
JJ
61 let any_exe = session.crate_types.borrow().iter().any(|ty| {
62 *ty == config::CrateTypeExecutable
63 });
64 if !any_exe {
970d7e83 65 // No need to find a main function
83c7162d 66 session.entry_fn.set(None);
1a4d82fc 67 return
970d7e83
LB
68 }
69
1a4d82fc 70 // If the user wants no main function at all, then stop here.
32a655c1 71 if attr::contains_name(&hir_map.krate().attrs, "no_main") {
83c7162d 72 session.entry_fn.set(None);
1a4d82fc
JJ
73 return
74 }
75
76 let mut ctxt = EntryContext {
041b39d2 77 session,
32a655c1 78 map: hir_map,
970d7e83
LB
79 main_fn: None,
80 attr_main_fn: None,
81 start_fn: None,
1a4d82fc 82 non_main_fns: Vec::new(),
970d7e83
LB
83 };
84
32a655c1 85 hir_map.krate().visit_all_item_likes(&mut ctxt);
970d7e83 86
0531ce1d 87 configure_main(&mut ctxt, crate_name);
970d7e83
LB
88}
89
e9174d1e
SL
90// Beware, this is duplicated in libsyntax/entry.rs, make sure to keep
91// them in sync.
92a42be0 92fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType {
970d7e83 93 match item.node {
1a4d82fc 94 ItemFn(..) => {
85aaf69f 95 if attr::contains_name(&item.attrs, "start") {
e9174d1e
SL
96 EntryPointType::Start
97 } else if attr::contains_name(&item.attrs, "main") {
98 EntryPointType::MainAttr
476ff2be 99 } else if item.name == "main" {
92a42be0 100 if at_root {
e9174d1e
SL
101 // This is a top-level function so can be 'main'
102 EntryPointType::MainNamed
970d7e83 103 } else {
e9174d1e 104 EntryPointType::OtherMain
970d7e83 105 }
e9174d1e
SL
106 } else {
107 EntryPointType::None
970d7e83
LB
108 }
109 }
e9174d1e
SL
110 _ => EntryPointType::None,
111 }
112}
113
114
92a42be0
SL
115fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) {
116 match entry_point_type(item, at_root) {
e9174d1e
SL
117 EntryPointType::MainNamed => {
118 if ctxt.main_fn.is_none() {
119 ctxt.main_fn = Some((item.id, item.span));
120 } else {
121 span_err!(ctxt.session, item.span, E0136,
122 "multiple 'main' functions");
123 }
124 },
125 EntryPointType::OtherMain => {
126 ctxt.non_main_fns.push((item.id, item.span));
127 },
128 EntryPointType::MainAttr => {
129 if ctxt.attr_main_fn.is_none() {
130 ctxt.attr_main_fn = Some((item.id, item.span));
131 } else {
5bcae85e
SL
132 struct_span_err!(ctxt.session, item.span, E0137,
133 "multiple functions with a #[main] attribute")
7cac9316
XL
134 .span_label(item.span, "additional #[main] function")
135 .span_label(ctxt.attr_main_fn.unwrap().1, "first #[main] function")
5bcae85e 136 .emit();
e9174d1e
SL
137 }
138 },
139 EntryPointType::Start => {
140 if ctxt.start_fn.is_none() {
141 ctxt.start_fn = Some((item.id, item.span));
142 } else {
5bcae85e
SL
143 struct_span_err!(
144 ctxt.session, item.span, E0138,
145 "multiple 'start' functions")
146 .span_label(ctxt.start_fn.unwrap().1,
7cac9316
XL
147 "previous `start` function here")
148 .span_label(item.span, "multiple `start` functions")
5bcae85e 149 .emit();
e9174d1e
SL
150 }
151 },
152 EntryPointType::None => ()
970d7e83 153 }
970d7e83
LB
154}
155
0531ce1d 156fn configure_main(this: &mut EntryContext, crate_name: &str) {
83c7162d
XL
157 if let Some((node_id, span)) = this.start_fn {
158 this.session.entry_fn.set(Some((node_id, span, config::EntryStart)));
159 } else if let Some((node_id, span)) = this.attr_main_fn {
160 this.session.entry_fn.set(Some((node_id, span, config::EntryMain)));
161 } else if let Some((node_id, span)) = this.main_fn {
162 this.session.entry_fn.set(Some((node_id, span, config::EntryMain)));
970d7e83 163 } else {
1a4d82fc 164 // No main function
83c7162d 165 this.session.entry_fn.set(None);
0531ce1d
XL
166 let mut err = struct_err!(this.session, E0601,
167 "`main` function not found in crate `{}`", crate_name);
1a4d82fc
JJ
168 if !this.non_main_fns.is_empty() {
169 // There were some functions named 'main' though. Try to give the user a hint.
9cc50fc6
SL
170 err.note("the main function must be defined at the crate level \
171 but you have one or more functions named 'main' that are not \
172 defined at the crate level. Either move the definition or \
173 attach the `#[main]` attribute to override this behavior.");
85aaf69f 174 for &(_, span) in &this.non_main_fns {
9cc50fc6 175 err.span_note(span, "here is a function named 'main'");
970d7e83 176 }
9cc50fc6 177 err.emit();
970d7e83 178 this.session.abort_if_errors();
9cc50fc6 179 } else {
0531ce1d
XL
180 if let Some(ref filename) = this.session.local_crate_source_file {
181 err.note(&format!("consider adding a `main` function to `{}`", filename.display()));
182 }
2c00a5a8
XL
183 if this.session.teach(&err.get_code().unwrap()) {
184 err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
185 to get started: https://doc.rust-lang.org/book/");
186 }
9cc50fc6 187 err.emit();
970d7e83
LB
188 }
189 }
190}