From d261df4a72e60e8baa0f21b67eba8f7b91cc2135 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Mon, 26 Apr 2021 01:09:35 +0800 Subject: [PATCH] Implement RFC 1260 with feature_name `imported_main`. --- .../rustc_codegen_cranelift/src/driver/jit.rs | 2 +- .../rustc_codegen_cranelift/src/main_shim.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 2 +- compiler/rustc_codegen_ssa/src/base.rs | 27 +- .../src/error_codes/E0136.md | 4 +- compiler/rustc_expand/src/expand.rs | 4 +- compiler/rustc_feature/src/active.rs | 3 + compiler/rustc_interface/src/queries.rs | 2 +- compiler/rustc_middle/src/mir/mono.rs | 4 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 7 +- compiler/rustc_middle/src/ty/mod.rs | 14 + .../rustc_mir/src/monomorphize/collector.rs | 4 +- compiler/rustc_passes/src/dead.rs | 4 +- compiler/rustc_passes/src/entry.rs | 51 ++-- compiler/rustc_resolve/src/lib.rs | 35 ++- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/check.rs | 30 +- compiler/rustc_typeck/src/check/mod.rs | 1 - compiler/rustc_typeck/src/lib.rs | 283 ++++++++++++------ src/test/ui/async-await/issue-68523.rs | 1 - src/test/ui/async-await/issue-68523.stderr | 13 +- .../entry-point/auxiliary/main_functions.rs | 1 + .../ui/entry-point/imported_main_conflict.rs | 7 + .../entry-point/imported_main_conflict.stderr | 18 ++ ...orted_main_const_fn_item_type_forbidden.rs | 12 + ...d_main_const_fn_item_type_forbidden.stderr | 17 ++ .../imported_main_const_forbidden.rs | 7 + .../imported_main_const_forbidden.stderr | 17 ++ .../imported_main_from_extern_crate.rs | 9 + .../imported_main_from_extern_crate.stderr | 10 + .../imported_main_from_inner_mod.rs | 9 + ...ed_main_unused_not_trigger_feature_gate.rs | 11 + .../feature-gate-imported_main.rs | 6 + .../feature-gate-imported_main.stderr | 12 + .../issue-59191-replace-root-with-fn.rs | 1 - .../issue-59191-replace-root-with-fn.stderr | 13 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 38 files changed, 459 insertions(+), 189 deletions(-) create mode 100644 src/test/ui/entry-point/auxiliary/main_functions.rs create mode 100644 src/test/ui/entry-point/imported_main_conflict.rs create mode 100644 src/test/ui/entry-point/imported_main_conflict.stderr create mode 100644 src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs create mode 100644 src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr create mode 100644 src/test/ui/entry-point/imported_main_const_forbidden.rs create mode 100644 src/test/ui/entry-point/imported_main_const_forbidden.stderr create mode 100644 src/test/ui/entry-point/imported_main_from_extern_crate.rs create mode 100644 src/test/ui/entry-point/imported_main_from_extern_crate.stderr create mode 100644 src/test/ui/entry-point/imported_main_from_inner_mod.rs create mode 100644 src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs create mode 100644 src/test/ui/feature-gates/feature-gate-imported_main.rs create mode 100644 src/test/ui/feature-gates/feature-gate-imported_main.stderr diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index dbe1ff083f0db..f585ebca9dc40 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -103,7 +103,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { }); let (main_def_id, entry_ty) = tcx.entry_fn(LOCAL_CRATE).unwrap(); - let instance = Instance::mono(tcx, main_def_id.to_def_id()).polymorphize(tcx); + let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx); match entry_ty { EntryFnType::Main => { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index a6266f507765f..dc86290b3fe93 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -13,7 +13,7 @@ pub(crate) fn maybe_create_entry_wrapper( ) { let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) { Some((def_id, entry_ty)) => ( - def_id.to_def_id(), + def_id, match entry_ty { EntryFnType::Main => true, EntryFnType::Start => false, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index e157a38aa03d5..b928e903730b6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -344,7 +344,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { spflags |= DISPFlags::SPFlagOptimized; } if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) { - if id.to_def_id() == def_id { + if id == def_id { spflags |= DISPFlags::SPFlagMainSubprogram; } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 318eed76acf2b..e045a23eb0ce3 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{par_iter, ParallelIterator}; use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -348,12 +348,29 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, ) -> Option { let main_def_id = cx.tcx().entry_fn(LOCAL_CRATE).map(|(def_id, _)| def_id)?; - let instance = Instance::mono(cx.tcx(), main_def_id.to_def_id()); + let main_is_local = main_def_id.is_local(); + let instance = Instance::mono(cx.tcx(), main_def_id); - if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) { + if main_is_local { // We want to create the wrapper in the same codegen unit as Rust's main // function. - return None; + if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) { + return None; + } + } else { + // FIXME: Add support for non-local main fn codegen + let span = cx.tcx().main_def.unwrap().span; + let n = 28937; + cx.sess() + .struct_span_err(span, "entry symbol `main` from foreign crate is not yet supported.") + .note(&format!( + "see issue #{} \ + for more information", + n, n, + )) + .emit(); + cx.sess().abort_if_errors(); + bug!(); } let main_llfn = cx.get_fn_addr(instance); @@ -366,7 +383,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, rust_main: Bx::Value, - rust_main_def_id: LocalDefId, + rust_main_def_id: DefId, use_start_lang_item: bool, ) -> Bx::Function { // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, diff --git a/compiler/rustc_error_codes/src/error_codes/E0136.md b/compiler/rustc_error_codes/src/error_codes/E0136.md index b91b52c074cd2..15cf09a18cbde 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0136.md +++ b/compiler/rustc_error_codes/src/error_codes/E0136.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + More than one `main` function was found. Erroneous code example: -```compile_fail,E0136 +```compile_fail fn main() { // ... } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 529ef7e4611e2..3347c93948ccc 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -20,7 +20,7 @@ use rustc_attr::{self as attr, is_builtin_attr}; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser, RecoverComma}; use rustc_parse::validate_attr; @@ -414,6 +414,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind.article(), kind.descr() ), ); + // FIXME: this workaround issue #84569 + FatalError.raise(); } }; self.cx.trace_macros_diag(); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 7ae7e0094c6d1..b13b98875323b 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -655,6 +655,9 @@ declare_features! ( /// Allows unsizing coercions in `const fn`. (active, const_fn_unsize, "1.53.0", Some(64992), None), + /// Allows using imported `main` function + (active, imported_main, "1.53.0", Some(28937), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 01853eab530da..bc94fb67ac3dc 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -307,7 +307,7 @@ impl<'tcx> Queries<'tcx> { _ => return, }; - let attrs = &*tcx.get_attrs(def_id.to_def_id()); + let attrs = &*tcx.get_attrs(def_id); let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error)); for attr in attrs { match attr.meta_item_list() { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 92a1094bbcdc1..77f38e52ad2e4 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -6,7 +6,7 @@ use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::{HirId, ItemId}; use rustc_session::config::OptLevel; use rustc_span::source_map::Span; @@ -93,7 +93,7 @@ impl<'tcx> MonoItem<'tcx> { // indicator, then we'll be creating a globally shared version. if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator() || !instance.def.generates_cgu_internal_copy(tcx) - || Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id) + || Some(instance.def_id()) == entry_def_id { return InstantiationMode::GloballyShared { may_conflict: false }; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 08fa12aa3718f..7e62e10821c9e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1194,7 +1194,7 @@ rustc_queries! { /// Identifies the entry-point (e.g., the `main` function) for a given /// crate, returning `None` if there is no entry point (such as for library crates). - query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> { + query entry_fn(_: CrateNum) -> Option<(DefId, EntryFnType)> { desc { "looking up the entry function of a crate" } } query plugin_registrar_fn(_: CrateNum) -> Option { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index bb2b00cbaea81..b414618f7d571 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -20,8 +20,8 @@ use crate::ty::TyKind::*; use crate::ty::{ self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst, - InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, - PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions, + InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig, + Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility, }; use rustc_ast as ast; @@ -1025,6 +1025,8 @@ pub struct GlobalCtxt<'tcx> { layout_interner: ShardedHashMap<&'tcx Layout, ()>, output_filenames: Arc, + + pub main_def: Option, } impl<'tcx> TyCtxt<'tcx> { @@ -1185,6 +1187,7 @@ impl<'tcx> TyCtxt<'tcx> { const_stability_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), output_filenames: Arc::new(output_filenames.clone()), + main_def: resolutions.main_def, } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6574c9382604b..af49533753fae 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -124,6 +124,20 @@ pub struct ResolverOutputs { /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. pub extern_prelude: FxHashMap, + pub main_def: Option, +} + +#[derive(Clone, Copy)] +pub struct MainDefinition { + pub res: Res, + pub is_import: bool, + pub span: Span, +} + +impl MainDefinition { + pub fn opt_fn_def_id(self) -> Option { + if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None } + } } /// The "header" of an impl is everything outside the body: a Self type, a trait diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index e621bc9167d80..fdefc89067477 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -1066,7 +1066,7 @@ struct RootCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, mode: MonoItemCollectionMode, output: &'a mut Vec>>, - entry_fn: Option<(LocalDefId, EntryFnType)>, + entry_fn: Option<(DefId, EntryFnType)>, } impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { @@ -1154,7 +1154,7 @@ impl RootCollector<'_, 'v> { && match self.mode { MonoItemCollectionMode::Eager => true, MonoItemCollectionMode::Lazy => { - self.entry_fn.map(|(id, _)| id) == Some(def_id) + self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) || self.tcx.is_reachable_non_generic(def_id) || self .tcx diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c63edf365a1aa..d32180525bf70 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -472,7 +472,9 @@ fn create_and_seed_worklist<'tcx>( ) .chain( // Seed entry point - tcx.entry_fn(LOCAL_CRATE).map(|(def_id, _)| tcx.hir().local_def_id_to_hir_id(def_id)), + tcx.entry_fn(LOCAL_CRATE).and_then(|(def_id, _)| { + def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) + }), ) .collect::>(); diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index e1b750df33c68..65cfe986ad454 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,12 +1,13 @@ use rustc_ast::entry::EntryPointType; use rustc_errors::struct_span_err; -use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem, CRATE_HIR_ID}; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{CrateType, EntryFnType}; +use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -16,9 +17,6 @@ struct EntryContext<'a, 'tcx> { map: Map<'tcx>, - /// The top-level function called `main`. - main_fn: Option<(HirId, Span)>, - /// The function that has attribute named `main`. attr_main_fn: Option<(HirId, Span)>, @@ -50,7 +48,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { } } -fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> { +fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> { assert_eq!(cnum, LOCAL_CRATE); let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable); @@ -67,7 +65,6 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType) let mut ctxt = EntryContext { session: tcx.sess, map: tcx.hir(), - main_fn: None, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new(), @@ -115,14 +112,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { throw_attr_err(&ctxt.session, attr.span, "rustc_main"); } } - EntryPointType::MainNamed => { - if ctxt.main_fn.is_none() { - ctxt.main_fn = Some((item.hir_id(), item.span)); - } else { - struct_span_err!(ctxt.session, item.span, E0136, "multiple `main` functions") - .emit(); - } - } + EntryPointType::MainNamed => (), EntryPointType::OtherMain => { ctxt.non_main_fns.push((item.hir_id(), item.span)); } @@ -154,16 +144,23 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { } } -fn configure_main( - tcx: TyCtxt<'_>, - visitor: &EntryContext<'_, '_>, -) -> Option<(LocalDefId, EntryFnType)> { +fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> { if let Some((hir_id, _)) = visitor.start_fn { - Some((tcx.hir().local_def_id(hir_id), EntryFnType::Start)) + Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Start)) } else if let Some((hir_id, _)) = visitor.attr_main_fn { - Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main)) - } else if let Some((hir_id, _)) = visitor.main_fn { - Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main)) + Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Main)) + } else if let Some(def_id) = tcx.main_def.and_then(|main_def| main_def.opt_fn_def_id()) { + if tcx.main_def.unwrap().is_import && !tcx.features().imported_main { + let span = tcx.main_def.unwrap().span; + feature_err( + &tcx.sess.parse_sess, + sym::imported_main, + span, + "using an imported function as entry point `main` is experimental", + ) + .emit(); + } + Some((def_id, EntryFnType::Main)) } else { no_main_err(tcx, visitor); None @@ -213,6 +210,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { } else { err.note(¬e); } + + if let Some(main_def) = tcx.main_def { + if main_def.opt_fn_def_id().is_none() { + // There is something at `crate::main`, but it is not a function definition. + err.span_label(main_def.span, &format!("non-function item at `crate::main` is found")); + } + } + if tcx.sess.teach(&err.get_code().unwrap()) { err.note( "If you don't know the basics of Rust, you can go look to the Rust Book \ @@ -222,7 +227,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { err.emit(); } -pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(LocalDefId, EntryFnType)> { +pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> { tcx.entry_fn(LOCAL_CRATE) } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1d1969f7e78ab..9197f4059ca2e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -50,7 +50,7 @@ use rustc_middle::hir::exports::ExportMap; use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, DefIdTree, ResolverOutputs}; +use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; @@ -1021,6 +1021,8 @@ pub struct Resolver<'a> { trait_impl_items: FxHashSet, legacy_const_generic_args: FxHashMap>>, + + main_def: Option, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1348,6 +1350,7 @@ impl<'a> Resolver<'a> { next_disambiguator: Default::default(), trait_impl_items: Default::default(), legacy_const_generic_args: Default::default(), + main_def: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1382,6 +1385,7 @@ impl<'a> Resolver<'a> { let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let maybe_unused_extern_crates = self.maybe_unused_extern_crates; let glob_map = self.glob_map; + let main_def = self.main_def; ResolverOutputs { definitions, cstore: Box::new(self.crate_loader.into_cstore()), @@ -1396,6 +1400,7 @@ impl<'a> Resolver<'a> { .iter() .map(|(ident, entry)| (ident.name, entry.introduced_by_item)) .collect(), + main_def, } } @@ -1414,6 +1419,7 @@ impl<'a> Resolver<'a> { .iter() .map(|(ident, entry)| (ident.name, entry.introduced_by_item)) .collect(), + main_def: self.main_def.clone(), } } @@ -1459,6 +1465,7 @@ impl<'a> Resolver<'a> { self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports()); self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.session.time("late_resolve_crate", || self.late_resolve_crate(krate)); + self.session.time("resolve_main", || self.resolve_main()); self.session.time("resolve_check_unused", || self.check_unused(krate)); self.session.time("resolve_report_errors", || self.report_errors(krate)); self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate)); @@ -3350,6 +3357,32 @@ impl<'a> Resolver<'a> { } None } + + fn resolve_main(&mut self) { + let module = self.graph_root; + let ident = Ident::with_dummy_span(sym::main); + let parent_scope = &ParentScope::module(module, self); + + let name_binding = match self.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ValueNS, + parent_scope, + false, + DUMMY_SP, + ) { + Ok(name_binding) => name_binding, + _ => return, + }; + + let res = name_binding.res(); + let is_import = name_binding.is_import(); + let span = name_binding.span; + if let Res::Def(DefKind::Fn, _) = res { + self.record_use(ident, ValueNS, name_binding, false); + } + self.main_def = Some(MainDefinition { res, is_import, span }); + } } fn names_to_string(names: &[Symbol]) -> String { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4be187c5208cd..895b64be27c93 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -634,6 +634,7 @@ symbols! { impl_macros, impl_trait_in_bindings, import_shadowing, + imported_main, in_band_lifetimes, include, include_bytes, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 72c633dcb20c4..92d7ea2600300 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -6,7 +6,7 @@ use super::*; use rustc_attr as attr; use rustc_errors::{Applicability, ErrorReported}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{def::Res, ItemKind, Node, PathSegment}; @@ -16,15 +16,14 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::layout::MAX_SIMD_LANES; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, ParamEnv, RegionKind, ToPredicate, Ty, TyCtxt}; -use rustc_session::config::EntryFnType; +use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt}; use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_span::symbol::sym; use rustc_span::{self, MultiSpan, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::opaque_types::InferCtxtExt as _; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCauseCode}; use rustc_ty_utils::representability::{self, Representability}; use std::iter; @@ -326,29 +325,6 @@ pub(super) fn check_fn<'a, 'tcx>( } fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); - // Check that the main return type implements the termination trait. - if let Some(term_id) = tcx.lang_items().termination() { - if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { - let main_id = hir.local_def_id_to_hir_id(def_id); - if main_id == fn_id { - let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); - let trait_ref = ty::TraitRef::new(term_id, substs); - let return_ty_span = decl.output.span(); - let cause = traits::ObligationCause::new( - return_ty_span, - fn_id, - ObligationCauseCode::MainFunctionType, - ); - - inherited.register_predicate(traits::Obligation::new( - cause, - param_env, - trait_ref.without_const().to_predicate(tcx), - )); - } - } - } - // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { if panic_impl_did == hir.local_def_id(fn_id).to_def_id() { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index cb4257e05347a..cb7589318d2a7 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -116,7 +116,6 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::WithConstness; use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType}; use rustc_session::config; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 190744fe6f1d8..4e07e52347a19 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -97,8 +97,8 @@ mod variance; use rustc_errors::{struct_span_err, ErrorReported}; use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; -use rustc_hir::Node; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::{Node, CRATE_HIR_ID}; use rustc_infer::infer::{InferOk, TyCtxtInferExt}; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::middle; @@ -110,7 +110,7 @@ use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ - ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, + self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, }; use std::iter; @@ -164,106 +164,203 @@ fn require_same_types<'tcx>( }) } -fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) { - let main_id = tcx.hir().local_def_id_to_hir_id(main_def_id); +fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { + let main_fnsig = tcx.fn_sig(main_def_id); let main_span = tcx.def_span(main_def_id); - let main_t = tcx.type_of(main_def_id); - match main_t.kind() { - ty::FnDef(..) => { - if let Some(Node::Item(it)) = tcx.hir().find(main_id) { - if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind { - let mut error = false; - if !generics.params.is_empty() { - let msg = "`main` function is not allowed to have generic \ - parameters" - .to_owned(); - let label = "`main` cannot have generic parameters".to_string(); - struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg) - .span_label(generics.span, label) - .emit(); - error = true; - } - if let Some(sp) = generics.where_clause.span() { - struct_span_err!( - tcx.sess, - sp, - E0646, - "`main` function is not allowed to have a `where` clause" - ) - .span_label(sp, "`main` cannot have a `where` clause") - .emit(); - error = true; - } - if let hir::IsAsync::Async = sig.header.asyncness { - let span = tcx.sess.source_map().guess_head_span(it.span); - struct_span_err!( - tcx.sess, - span, - E0752, - "`main` function is not allowed to be `async`" - ) - .span_label(span, "`main` function is not allowed to be `async`") - .emit(); - error = true; - } - let attrs = tcx.hir().attrs(main_id); - for attr in attrs { - if tcx.sess.check_name(attr, sym::track_caller) { - tcx.sess - .struct_span_err( - attr.span, - "`main` function is not allowed to be `#[track_caller]`", - ) - .span_label( - main_span, - "`main` function is not allowed to be `#[track_caller]`", - ) - .emit(); - error = true; - } - } + fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId { + if let Some(local_def_id) = def_id.as_local() { + let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id); + let hir_type = tcx.type_of(local_def_id); + if !matches!(hir_type.kind(), ty::FnDef(..)) { + span_bug!(sp, "main has a non-function type: found `{}`", hir_type); + } + hir_id + } else { + CRATE_HIR_ID + } + } - if error { - return; - } - } + fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + if !def_id.is_local() { + return None; + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().find(hir_id) { + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { + let generics_param_span = + if !generics.params.is_empty() { Some(generics.span) } else { None }; + generics_param_span + } + _ => { + span_bug!(tcx.def_span(def_id), "main has a non-function type"); } + } + } - let actual = tcx.fn_sig(main_def_id); - let expected_return_type = if tcx.lang_items().termination().is_some() { - // we take the return type of the given main function, the real check is done - // in `check_fn` - actual.output() - } else { - // standard () main return type - ty::Binder::dummy(tcx.mk_unit()) - }; - - let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| { - tcx.mk_fn_sig( - iter::empty(), - expected_return_type, - false, - hir::Unsafety::Normal, - Abi::Rust, - ) - })); + fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + if !def_id.is_local() { + return None; + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().find(hir_id) { + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { + generics.where_clause.span() + } + _ => { + span_bug!(tcx.def_span(def_id), "main has a non-function type"); + } + } + } - require_same_types( - tcx, - &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType), - se_ty, - tcx.mk_fn_ptr(actual), - ); + fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + if !def_id.is_local() { + return None; } - _ => { - span_bug!(main_span, "main has a non-function type: found `{}`", main_t); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().find(hir_id) { + Some(Node::Item(hir::Item { span: item_span, .. })) => { + Some(tcx.sess.source_map().guess_head_span(*item_span)) + } + _ => { + span_bug!(tcx.def_span(def_id), "main has a non-function type"); + } } } -} -fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) { + fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + if !def_id.is_local() { + return None; + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().find(hir_id) { + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => { + Some(fn_sig.decl.output.span()) + } + _ => { + span_bug!(tcx.def_span(def_id), "main has a non-function type"); + } + } + } + + let mut error = false; + let main_diagnostics_hir_id = main_fn_diagnostics_hir_id(tcx, main_def_id, main_span); + let main_fn_generics = tcx.generics_of(main_def_id); + let main_fn_predicates = tcx.predicates_of(main_def_id); + if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() { + let generics_param_span = main_fn_generics_params_span(tcx, main_def_id); + let msg = "`main` function is not allowed to have generic \ + parameters"; + let mut diag = + struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg); + if let Some(generics_param_span) = generics_param_span { + let label = "`main` cannot have generic parameters".to_string(); + diag.span_label(generics_param_span, label); + } + diag.emit(); + error = true; + } else if !main_fn_predicates.predicates.is_empty() { + // generics may bring in implicit predicates, so we skip this check if generics is present. + let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id); + let mut diag = struct_span_err!( + tcx.sess, + generics_where_clauses_span.unwrap_or(main_span), + E0646, + "`main` function is not allowed to have a `where` clause" + ); + if let Some(generics_where_clauses_span) = generics_where_clauses_span { + diag.span_label(generics_where_clauses_span, "`main` cannot have a `where` clause"); + } + diag.emit(); + error = true; + } + + let main_asyncness = tcx.asyncness(main_def_id); + if let hir::IsAsync::Async = main_asyncness { + let mut diag = struct_span_err!( + tcx.sess, + main_span, + E0752, + "`main` function is not allowed to be `async`" + ); + let asyncness_span = main_fn_asyncness_span(tcx, main_def_id); + if let Some(asyncness_span) = asyncness_span { + diag.span_label(asyncness_span, "`main` function is not allowed to be `async`"); + } + diag.emit(); + error = true; + } + + for attr in tcx.get_attrs(main_def_id) { + if tcx.sess.check_name(attr, sym::track_caller) { + tcx.sess + .struct_span_err( + attr.span, + "`main` function is not allowed to be `#[track_caller]`", + ) + .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`") + .emit(); + error = true; + } + } + + if error { + return; + } + + let expected_return_type; + if let Some(term_id) = tcx.lang_items().termination() { + let return_ty = main_fnsig.output(); + let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span); + if !return_ty.bound_vars().is_empty() { + let msg = "`main` function return type is not allowed to have generic \ + parameters" + .to_owned(); + struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit(); + error = true; + } + let return_ty = return_ty.skip_binder(); + tcx.infer_ctxt().enter(|infcx| { + let cause = traits::ObligationCause::new( + return_ty_span, + main_diagnostics_hir_id, + ObligationCauseCode::MainFunctionType, + ); + let mut fulfillment_cx = traits::FulfillmentContext::new(); + fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause); + if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(&err, None, false); + error = true; + } + }); + // now we can take the return type of the given main function + expected_return_type = main_fnsig.output(); + } else { + // standard () main return type + expected_return_type = ty::Binder::dummy(tcx.mk_unit()); + } + + if error { + return; + } + + let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| { + tcx.mk_fn_sig(iter::empty(), expected_return_type, false, hir::Unsafety::Normal, Abi::Rust) + })); + + require_same_types( + tcx, + &ObligationCause::new( + main_span, + main_diagnostics_hir_id, + ObligationCauseCode::MainFunctionType, + ), + se_ty, + tcx.mk_fn_ptr(main_fnsig), + ); +} +fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { + let start_def_id = start_def_id.expect_local(); let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id); let start_span = tcx.def_span(start_def_id); let start_t = tcx.type_of(start_def_id); diff --git a/src/test/ui/async-await/issue-68523.rs b/src/test/ui/async-await/issue-68523.rs index 718c597e7129a..7a67661a0197b 100644 --- a/src/test/ui/async-await/issue-68523.rs +++ b/src/test/ui/async-await/issue-68523.rs @@ -2,6 +2,5 @@ async fn main() -> Result { //~^ ERROR `main` function is not allowed to be `async` -//~^^ ERROR `main` has invalid return type `impl Future` Ok(1) } diff --git a/src/test/ui/async-await/issue-68523.stderr b/src/test/ui/async-await/issue-68523.stderr index 6f67af04cd44f..dfdf078e30351 100644 --- a/src/test/ui/async-await/issue-68523.stderr +++ b/src/test/ui/async-await/issue-68523.stderr @@ -1,18 +1,9 @@ -error[E0277]: `main` has invalid return type `impl Future` - --> $DIR/issue-68523.rs:3:20 - | -LL | async fn main() -> Result { - | ^^^^^^^^^^^^^^^ `main` can only return types that implement `Termination` - | - = help: consider using `()`, or a `Result` - error[E0752]: `main` function is not allowed to be `async` --> $DIR/issue-68523.rs:3:1 | LL | async fn main() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` function is not allowed to be `async` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0277, E0752. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0752`. diff --git a/src/test/ui/entry-point/auxiliary/main_functions.rs b/src/test/ui/entry-point/auxiliary/main_functions.rs new file mode 100644 index 0000000000000..cc7992a42c187 --- /dev/null +++ b/src/test/ui/entry-point/auxiliary/main_functions.rs @@ -0,0 +1 @@ +pub fn boilerplate() {} diff --git a/src/test/ui/entry-point/imported_main_conflict.rs b/src/test/ui/entry-point/imported_main_conflict.rs new file mode 100644 index 0000000000000..2839688f34240 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_conflict.rs @@ -0,0 +1,7 @@ +#![feature(imported_main)] +//~^ ERROR `main` is ambiguous (glob import vs glob import in the same module) +mod m1 { pub(crate) fn main() {} } +mod m2 { pub(crate) fn main() {} } + +use m1::*; +use m2::*; diff --git a/src/test/ui/entry-point/imported_main_conflict.stderr b/src/test/ui/entry-point/imported_main_conflict.stderr new file mode 100644 index 0000000000000..36cb98d94e69a --- /dev/null +++ b/src/test/ui/entry-point/imported_main_conflict.stderr @@ -0,0 +1,18 @@ +error[E0659]: `main` is ambiguous (glob import vs glob import in the same module) + | +note: `main` could refer to the function imported here + --> $DIR/imported_main_conflict.rs:6:5 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `main` to disambiguate +note: `main` could also refer to the function imported here + --> $DIR/imported_main_conflict.rs:7:5 + | +LL | use m2::*; + | ^^^^^ + = help: consider adding an explicit import of `main` to disambiguate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs new file mode 100644 index 0000000000000..559f10de10981 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs @@ -0,0 +1,12 @@ +#![feature(imported_main)] +#![feature(min_type_alias_impl_trait, impl_trait_in_bindings)] +#![allow(incomplete_features)] +//~^^^ ERROR `main` function not found in crate +pub mod foo { + type MainFn = impl Fn(); + + fn bar() {} + pub const BAR: MainFn = bar; +} + +use foo::BAR as main; diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr new file mode 100644 index 0000000000000..9b879fc09f729 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr @@ -0,0 +1,17 @@ +error[E0601]: `main` function not found in crate `imported_main_const_fn_item_type_forbidden` + --> $DIR/imported_main_const_fn_item_type_forbidden.rs:1:1 + | +LL | / #![feature(imported_main)] +LL | | #![feature(min_type_alias_impl_trait, impl_trait_in_bindings)] +LL | | #![allow(incomplete_features)] +LL | | +... | +LL | | +LL | | use foo::BAR as main; + | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_fn_item_type_forbidden.rs` + | | + | non-function item at `crate::main` is found + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/entry-point/imported_main_const_forbidden.rs b/src/test/ui/entry-point/imported_main_const_forbidden.rs new file mode 100644 index 0000000000000..989a6c97a8004 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_const_forbidden.rs @@ -0,0 +1,7 @@ +#![feature(imported_main)] +//~^ ERROR `main` function not found in crate +pub mod foo { + pub const BAR: usize = 42; +} + +use foo::BAR as main; diff --git a/src/test/ui/entry-point/imported_main_const_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_forbidden.stderr new file mode 100644 index 0000000000000..4640513c2bb5f --- /dev/null +++ b/src/test/ui/entry-point/imported_main_const_forbidden.stderr @@ -0,0 +1,17 @@ +error[E0601]: `main` function not found in crate `imported_main_const_forbidden` + --> $DIR/imported_main_const_forbidden.rs:1:1 + | +LL | / #![feature(imported_main)] +LL | | +LL | | pub mod foo { +LL | | pub const BAR: usize = 42; +LL | | } +LL | | +LL | | use foo::BAR as main; + | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_forbidden.rs` + | | + | non-function item at `crate::main` is found + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/entry-point/imported_main_from_extern_crate.rs b/src/test/ui/entry-point/imported_main_from_extern_crate.rs new file mode 100644 index 0000000000000..6bbf67fa5408d --- /dev/null +++ b/src/test/ui/entry-point/imported_main_from_extern_crate.rs @@ -0,0 +1,9 @@ +// build-fail +// aux-build:main_functions.rs + +#![feature(imported_main)] + +extern crate main_functions; +pub use main_functions::boilerplate as main; //~ ERROR entry symbol `main` from foreign crate + +// FIXME: Should be run-pass diff --git a/src/test/ui/entry-point/imported_main_from_extern_crate.stderr b/src/test/ui/entry-point/imported_main_from_extern_crate.stderr new file mode 100644 index 0000000000000..8792e1e414244 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_from_extern_crate.stderr @@ -0,0 +1,10 @@ +error: entry symbol `main` from foreign crate is not yet supported. + --> $DIR/imported_main_from_extern_crate.rs:7:9 + | +LL | pub use main_functions::boilerplate as main; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #28937 for more information + +error: aborting due to previous error + diff --git a/src/test/ui/entry-point/imported_main_from_inner_mod.rs b/src/test/ui/entry-point/imported_main_from_inner_mod.rs new file mode 100644 index 0000000000000..45750072a7f68 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_from_inner_mod.rs @@ -0,0 +1,9 @@ +// run-pass +#![feature(imported_main)] + +pub mod foo { + pub fn bar() { + println!("Hello world!"); + } +} +use foo::bar as main; diff --git a/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs b/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs new file mode 100644 index 0000000000000..4762fbb7c59ce --- /dev/null +++ b/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs @@ -0,0 +1,11 @@ +// check-pass +#![feature(rustc_attrs)] + +#[rustc_main] +fn actual_main() {} + +mod foo { + pub(crate) fn something() {} +} + +use foo::something as main; diff --git a/src/test/ui/feature-gates/feature-gate-imported_main.rs b/src/test/ui/feature-gates/feature-gate-imported_main.rs new file mode 100644 index 0000000000000..b351d0d0e9a50 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-imported_main.rs @@ -0,0 +1,6 @@ +pub mod foo { + pub fn bar() { + println!("Hello world!"); + } +} +use foo::bar as main; //~ ERROR using an imported function as entry point diff --git a/src/test/ui/feature-gates/feature-gate-imported_main.stderr b/src/test/ui/feature-gates/feature-gate-imported_main.stderr new file mode 100644 index 0000000000000..3b879fdfc6bbf --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-imported_main.stderr @@ -0,0 +1,12 @@ +error[E0658]: using an imported function as entry point `main` is experimental + --> $DIR/feature-gate-imported_main.rs:6:5 + | +LL | use foo::bar as main; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #28937 for more information + = help: add `#![feature(imported_main)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs index a59cacb8bde1f..039878af56eb6 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -3,6 +3,5 @@ // Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely. // `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`. #![feature(custom_inner_attributes)] -//~^ ERROR `main` function not found in crate `issue_59191_replace_root_with_fn` [E0601] #![issue_59191::no_main] //~^ ERROR expected crate top-level item to be a module after macro expansion, found a function diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr index 5995a4891f37d..579041c52598f 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -1,19 +1,10 @@ error: expected crate top-level item to be a module after macro expansion, found a function - --> $DIR/issue-59191-replace-root-with-fn.rs:7:1 + --> $DIR/issue-59191-replace-root-with-fn.rs:6:1 | LL | #![issue_59191::no_main] | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0601]: `main` function not found in crate `issue_59191_replace_root_with_fn` - --> $DIR/issue-59191-replace-root-with-fn.rs:5:1 - | -LL | / #![feature(custom_inner_attributes)] -LL | | -LL | | #![issue_59191::no_main] - | |________________________^ consider adding a `main` function to `$DIR/issue-59191-replace-root-with-fn.rs` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0601`. diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index cd85c487798d9..e81a92eb74ca7 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -678,7 +678,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option, def_id: DefId) -> bool { cx.tcx .entry_fn(LOCAL_CRATE) - .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id()) + .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id) } /// Returns `true` if the expression is in the program's `#[panic_handler]`.