about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs27
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0136.md4
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_interface/src/queries.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs7
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs14
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs4
-rw-r--r--compiler/rustc_passes/src/dead.rs4
-rw-r--r--compiler/rustc_passes/src/entry.rs51
-rw-r--r--compiler/rustc_resolve/src/lib.rs35
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/check/check.rs30
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs1
-rw-r--r--compiler/rustc_typeck/src/lib.rs283
-rw-r--r--src/test/ui/async-await/issue-68523.rs1
-rw-r--r--src/test/ui/async-await/issue-68523.stderr13
-rw-r--r--src/test/ui/entry-point/auxiliary/main_functions.rs1
-rw-r--r--src/test/ui/entry-point/imported_main_conflict.rs7
-rw-r--r--src/test/ui/entry-point/imported_main_conflict.stderr18
-rw-r--r--src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs12
-rw-r--r--src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr17
-rw-r--r--src/test/ui/entry-point/imported_main_const_forbidden.rs7
-rw-r--r--src/test/ui/entry-point/imported_main_const_forbidden.stderr17
-rw-r--r--src/test/ui/entry-point/imported_main_from_extern_crate.rs9
-rw-r--r--src/test/ui/entry-point/imported_main_from_extern_crate.stderr10
-rw-r--r--src/test/ui/entry-point/imported_main_from_inner_mod.rs9
-rw-r--r--src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs11
-rw-r--r--src/test/ui/feature-gates/feature-gate-imported_main.rs6
-rw-r--r--src/test/ui/feature-gates/feature-gate-imported_main.stderr12
-rw-r--r--src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs1
-rw-r--r--src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr13
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
38 files changed, 459 insertions, 189 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index dbe1ff083f0..f585ebca9dc 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 a6266f50776..dc86290b3fe 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 e157a38aa03..b928e903730 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 318eed76acf..e045a23eb0c 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<Bx::Function> {
     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 #{} <https://github.com/rust-lang/rust/issues/{}> \
+                 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 b91b52c074c..15cf09a18cb 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 529ef7e4611..3347c93948c 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 7ae7e0094c6..b13b9887532 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 01853eab530..bc94fb67ac3 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 92a1094bbcd..77f38e52ad2 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 08fa12aa371..7e62e10821c 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<DefId> {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index bb2b00cbaea..b414618f7d5 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<OutputFilenames>,
+
+    pub main_def: Option<MainDefinition>,
 }
 
 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 6574c938260..af49533753f 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<Symbol, bool>,
+    pub main_def: Option<MainDefinition>,
+}
+
+#[derive(Clone, Copy)]
+pub struct MainDefinition {
+    pub res: Res<ast::NodeId>,
+    pub is_import: bool,
+    pub span: Span,
+}
+
+impl MainDefinition {
+    pub fn opt_fn_def_id(self) -> Option<DefId> {
+        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 e621bc9167d..fdefc890674 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<Spanned<MonoItem<'tcx>>>,
-    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 c63edf365a1..d32180525bf 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::<Vec<_>>();
 
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index e1b750df33c..65cfe986ad4 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(&note);
     }
+
+    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 1d1969f7e78..9197f4059ca 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<LocalDefId>,
 
     legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
+
+    main_def: Option<MainDefinition>,
 }
 
 /// 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 4be187c5208..895b64be27c 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 72c633dcb20..92d7ea26003 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 cb4257e0534..cb7589318d2 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 190744fe6f1..4e07e52347a 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<Span> {
+        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<Span> {
+        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<Span> {
+        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<Span> {
+        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 718c597e712..7a67661a019 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<i32, ()> {
 //~^ 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 6f67af04cd4..dfdf078e303 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<i32, ()> {
-   |                    ^^^^^^^^^^^^^^^ `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<i32, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `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 00000000000..cc7992a42c1
--- /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 00000000000..2839688f342
--- /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 00000000000..36cb98d94e6
--- /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 00000000000..559f10de109
--- /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 00000000000..9b879fc09f7
--- /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 00000000000..989a6c97a80
--- /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 00000000000..4640513c2bb
--- /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 00000000000..6bbf67fa540
--- /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 00000000000..8792e1e4142
--- /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 <https://github.com/rust-lang/rust/issues/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 00000000000..45750072a7f
--- /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 00000000000..4762fbb7c59
--- /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 00000000000..b351d0d0e9a
--- /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 00000000000..3b879fdfc6b
--- /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 <https://github.com/rust-lang/rust/issues/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 a59cacb8bde..039878af56e 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 5995a4891f3..579041c5259 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 cd85c487798..e81a92eb74c 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<Vec
 pub fn is_entrypoint_fn(cx: &LateContext<'_>, 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]`.