From 3d891e75ee0cd674f7e1509af840c08bc9041402 Mon Sep 17 00:00:00 2001 From: York Xiang Date: Sun, 4 Dec 2016 12:28:31 +0800 Subject: [PATCH] Initial work for RFC 1260 --- src/librustc/middle/entry.rs | 29 ++++++++++++++++++++----- src/librustc_driver/driver.rs | 14 ++++++++++-- src/librustc_driver/pretty.rs | 2 ++ src/librustc_resolve/lib.rs | 4 ++++ src/librustc_resolve/resolve_imports.rs | 7 +++++- src/libsyntax/entry.rs | 2 ++ src/libsyntax/test.rs | 3 ++- 7 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index e927843a984b8..c6050061eb962 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -11,7 +11,7 @@ use dep_graph::DepNode; use hir::map as ast_map; -use hir::def_id::{CRATE_DEF_INDEX}; +use hir::def_id::{CRATE_DEF_INDEX, DefId}; use session::{config, Session}; use syntax::ast::NodeId; use syntax::attr; @@ -36,7 +36,14 @@ struct EntryContext<'a, 'tcx: 'a> { // 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: Vec<(NodeId, Span)> , + non_main_fns: Vec<(NodeId, Span)>, + + // Function item that imported to root namespace named 'main'. + // It was collected in resolve phase + defined_as_main: Option, + + // The function that imported to root namespace named 'main'. + imported_main_fn: Option<(NodeId, Span)>, } impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { @@ -53,7 +60,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { } } -pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { +pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map, defined_as_main: Option) { let _task = ast_map.dep_graph.in_task(DepNode::EntryPoint); let any_exe = session.crate_types.borrow().iter().any(|ty| { @@ -77,6 +84,8 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { attr_main_fn: None, start_fn: None, non_main_fns: Vec::new(), + defined_as_main: defined_as_main, + imported_main_fn: None, }; ast_map.krate().visit_all_item_likes(&mut ctxt); @@ -86,13 +95,15 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { // Beware, this is duplicated in libsyntax/entry.rs, make sure to keep // them in sync. -fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType { +fn entry_point_type bool>(item: &Item, at_root: bool, defined_as_main: F) -> 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 defined_as_main() { + EntryPointType::ImportedMain } else if item.name == "main" { if at_root { // This is a top-level function so can be 'main' @@ -110,7 +121,9 @@ fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType { fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) { - match entry_point_type(item, at_root) { + match entry_point_type(item, + at_root, + || ctxt.defined_as_main == Some(ctxt.map.local_def_id(item.id))) { EntryPointType::MainNamed => { if ctxt.main_fn.is_none() { ctxt.main_fn = Some((item.id, item.span)); @@ -146,6 +159,9 @@ fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) { .emit(); } }, + EntryPointType::ImportedMain => { + ctxt.imported_main_fn = Some((item.id, item.span)); + }, EntryPointType::None => () } } @@ -160,6 +176,9 @@ fn configure_main(this: &mut EntryContext) { } else if this.main_fn.is_some() { *this.session.entry_fn.borrow_mut() = this.main_fn; this.session.entry_type.set(Some(config::EntryMain)); + } else if this.imported_main_fn.is_some() { + *this.session.entry_fn.borrow_mut() = this.imported_main_fn; + this.session.entry_type.set(Some(config::EntryMain)); } else { // No main function let mut err = this.session.struct_err("main function not found"); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 069f0a89bef08..7ddd48e359273 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -11,6 +11,7 @@ use rustc::hir; use rustc::hir::{map as hir_map, FreevarMap, TraitMap}; use rustc::hir::lowering::lower_crate; +use rustc::hir::def_id::DefId; use rustc_data_structures::blake2b::Blake2bHasher; use rustc_data_structures::fmt_wrap::FmtWrap; use rustc::ty::util::ArchIndependentHasher; @@ -117,7 +118,12 @@ pub fn compile_input(sess: &Session, let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input); - let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = { + let ExpansionResult { expanded_crate, + defs, + analysis, + resolutions, + defined_as_main, + mut hir_forest } = { phase_2_configure_and_expand( sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map, |expanded_crate| { @@ -175,6 +181,7 @@ pub fn compile_input(sess: &Session, resolutions, &arenas, &crate_name, + defined_as_main, |tcx, analysis, incremental_hashes_map, result| { { // Eventually, we will want to track plugins. @@ -536,6 +543,7 @@ pub struct ExpansionResult { pub analysis: ty::CrateAnalysis<'static>, pub resolutions: Resolutions, pub hir_forest: hir_map::Forest, + pub defined_as_main: Option, } /// Run the "early phases" of the compiler: initial `cfg` processing, @@ -791,6 +799,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, hir_ty_to_ty: NodeMap(), }, + defined_as_main: resolver.defined_as_main, resolutions: Resolutions { freevars: resolver.freevars, trait_map: resolver.trait_map, @@ -809,6 +818,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, resolutions: Resolutions, arenas: &'tcx ty::CtxtArenas<'tcx>, name: &str, + defined_as_main: Option, f: F) -> Result where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, @@ -842,7 +852,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "looking for entry point", - || middle::entry::find_entry_point(sess, &hir_map)); + || middle::entry::find_entry_point(sess, &hir_map, defined_as_main)); sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || { plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map) diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index b055b043723e4..db96e1501bfe4 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -232,6 +232,7 @@ impl PpSourceMode { resolutions.clone(), arenas, id, + None, |tcx, _, _, _| { let annotation = TypedAnnotation { tcx: tcx }; let _ignore = tcx.dep_graph.in_ignore(); @@ -960,6 +961,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, resolutions.clone(), arenas, crate_name, + None, |tcx, _, _, _| { match ppm { PpmMir | PpmMirCFG => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4738e73d2a8df..c8d653c8afb13 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1102,6 +1102,9 @@ pub struct Resolver<'a> { // Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap, + + // Track function imported as main in root namespace + pub defined_as_main: Option, } pub struct ResolverArenas<'a> { @@ -1277,6 +1280,7 @@ impl<'a> Resolver<'a> { macro_exports: Vec::new(), invocations: invocations, name_already_seen: FxHashMap(), + defined_as_main: None, } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 2a803d72fd1bd..cd927a2e76d05 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -11,7 +11,7 @@ use self::ImportDirectiveSubclass::*; use {Module, PerNS}; -use Namespace::{self, TypeNS, MacroNS}; +use Namespace::{self, TypeNS, MacroNS, ValueNS}; use {NameBinding, NameBindingKind, PathResult, PathScope, PrivacyError, ToNameBinding}; use Resolver; use {names_to_string, module_to_string}; @@ -293,6 +293,11 @@ impl<'a> Resolver<'a> { where T: ToNameBinding<'a> { let binding = self.arenas.alloc_name_binding(binding.to_name_binding()); + if ns == ValueNS && module.parent.is_none() && name == Name::intern("main") { + if let Def::Fn(def_id) = binding.def() { + self.defined_as_main = Some(def_id); + } + } self.update_resolution(module, name, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { if binding.is_glob_import() { diff --git a/src/libsyntax/entry.rs b/src/libsyntax/entry.rs index 93ca1948ed84b..1bc50fcb97ee0 100644 --- a/src/libsyntax/entry.rs +++ b/src/libsyntax/entry.rs @@ -17,10 +17,12 @@ pub enum EntryPointType { MainAttr, Start, OtherMain, // Not an entry point, but some other function named main + ImportedMain, // function imported as "main" in root namespace } // Beware, this is duplicated in librustc/middle/entry.rs, make sure to keep // them in sync. +// FIXME: get it sync or find other way to keep sane in --test mode pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType { match item.node { ItemKind::Fn(..) => { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index fca89e265e4ed..b8bb19217ae92 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -186,7 +186,8 @@ impl fold::Folder for EntryPointCleaner { // Remove any #[main] or #[start] from the AST so it doesn't // clash with the one we're going to add, but mark it as // #[allow(dead_code)] to avoid printing warnings. - let folded = match entry::entry_point_type(&folded, self.depth) { + let folded = match entry::entry_point_type(&folded, self.depth) { + EntryPointType::ImportedMain => unimplemented!(), // FIXME EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start =>