/src/librustc/middle/entry.rs

https://gitlab.com/0072016/0072016-rusty · Rust · 165 lines · 126 code · 18 blank · 21 comment · 31 complexity · c4b9b7b45bf851830d9e4f667c703974 MD5 · raw file

  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. use front::map as ast_map;
  11. use middle::def_id::{CRATE_DEF_INDEX};
  12. use session::{config, Session};
  13. use syntax::ast::NodeId;
  14. use syntax::attr;
  15. use syntax::codemap::Span;
  16. use syntax::entry::EntryPointType;
  17. use rustc_front::hir::{Item, ItemFn};
  18. use rustc_front::intravisit::Visitor;
  19. struct EntryContext<'a, 'tcx: 'a> {
  20. session: &'a Session,
  21. map: &'a ast_map::Map<'tcx>,
  22. // The top-level function called 'main'
  23. main_fn: Option<(NodeId, Span)>,
  24. // The function that has attribute named 'main'
  25. attr_main_fn: Option<(NodeId, Span)>,
  26. // The function that has the attribute 'start' on it
  27. start_fn: Option<(NodeId, Span)>,
  28. // The functions that one might think are 'main' but aren't, e.g.
  29. // main functions not defined at the top level. For diagnostics.
  30. non_main_fns: Vec<(NodeId, Span)> ,
  31. }
  32. impl<'a, 'tcx> Visitor<'tcx> for EntryContext<'a, 'tcx> {
  33. fn visit_item(&mut self, item: &'tcx Item) {
  34. let def_id = self.map.local_def_id(item.id);
  35. let def_key = self.map.def_key(def_id);
  36. let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
  37. find_item(item, self, at_root);
  38. }
  39. }
  40. pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
  41. let any_exe = session.crate_types.borrow().iter().any(|ty| {
  42. *ty == config::CrateTypeExecutable
  43. });
  44. if !any_exe {
  45. // No need to find a main function
  46. return
  47. }
  48. // If the user wants no main function at all, then stop here.
  49. if attr::contains_name(&ast_map.krate().attrs, "no_main") {
  50. session.entry_type.set(Some(config::EntryNone));
  51. return
  52. }
  53. let mut ctxt = EntryContext {
  54. session: session,
  55. map: ast_map,
  56. main_fn: None,
  57. attr_main_fn: None,
  58. start_fn: None,
  59. non_main_fns: Vec::new(),
  60. };
  61. ast_map.krate().visit_all_items(&mut ctxt);
  62. configure_main(&mut ctxt);
  63. }
  64. // Beware, this is duplicated in libsyntax/entry.rs, make sure to keep
  65. // them in sync.
  66. fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType {
  67. match item.node {
  68. ItemFn(..) => {
  69. if attr::contains_name(&item.attrs, "start") {
  70. EntryPointType::Start
  71. } else if attr::contains_name(&item.attrs, "main") {
  72. EntryPointType::MainAttr
  73. } else if item.name.as_str() == "main" {
  74. if at_root {
  75. // This is a top-level function so can be 'main'
  76. EntryPointType::MainNamed
  77. } else {
  78. EntryPointType::OtherMain
  79. }
  80. } else {
  81. EntryPointType::None
  82. }
  83. }
  84. _ => EntryPointType::None,
  85. }
  86. }
  87. fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) {
  88. match entry_point_type(item, at_root) {
  89. EntryPointType::MainNamed => {
  90. if ctxt.main_fn.is_none() {
  91. ctxt.main_fn = Some((item.id, item.span));
  92. } else {
  93. span_err!(ctxt.session, item.span, E0136,
  94. "multiple 'main' functions");
  95. }
  96. },
  97. EntryPointType::OtherMain => {
  98. ctxt.non_main_fns.push((item.id, item.span));
  99. },
  100. EntryPointType::MainAttr => {
  101. if ctxt.attr_main_fn.is_none() {
  102. ctxt.attr_main_fn = Some((item.id, item.span));
  103. } else {
  104. span_err!(ctxt.session, item.span, E0137,
  105. "multiple functions with a #[main] attribute");
  106. }
  107. },
  108. EntryPointType::Start => {
  109. if ctxt.start_fn.is_none() {
  110. ctxt.start_fn = Some((item.id, item.span));
  111. } else {
  112. span_err!(ctxt.session, item.span, E0138,
  113. "multiple 'start' functions");
  114. }
  115. },
  116. EntryPointType::None => ()
  117. }
  118. }
  119. fn configure_main(this: &mut EntryContext) {
  120. if this.start_fn.is_some() {
  121. *this.session.entry_fn.borrow_mut() = this.start_fn;
  122. this.session.entry_type.set(Some(config::EntryStart));
  123. } else if this.attr_main_fn.is_some() {
  124. *this.session.entry_fn.borrow_mut() = this.attr_main_fn;
  125. this.session.entry_type.set(Some(config::EntryMain));
  126. } else if this.main_fn.is_some() {
  127. *this.session.entry_fn.borrow_mut() = this.main_fn;
  128. this.session.entry_type.set(Some(config::EntryMain));
  129. } else {
  130. // No main function
  131. let mut err = this.session.struct_err("main function not found");
  132. if !this.non_main_fns.is_empty() {
  133. // There were some functions named 'main' though. Try to give the user a hint.
  134. err.note("the main function must be defined at the crate level \
  135. but you have one or more functions named 'main' that are not \
  136. defined at the crate level. Either move the definition or \
  137. attach the `#[main]` attribute to override this behavior.");
  138. for &(_, span) in &this.non_main_fns {
  139. err.span_note(span, "here is a function named 'main'");
  140. }
  141. err.emit();
  142. this.session.abort_if_errors();
  143. } else {
  144. err.emit();
  145. }
  146. }
  147. }