mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-20 03:32:52 +00:00
Auto merge of #84401 - crlf0710:impl_main_by_path, r=petrochenkov
Implement RFC 1260 with feature_name `imported_main`. This is the second extraction part of #84062 plus additional adjustments. This (mostly) implements RFC 1260. However there's still one test case failure in the extern crate case. Maybe `LocalDefId` doesn't work here? I'm not sure. cc https://github.com/rust-lang/rust/issues/28937 r? `@petrochenkov`
This commit is contained in:
commit
bcd696d722
@ -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 => {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)`,
|
||||
|
@ -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() {
|
||||
// ...
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -653,6 +653,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
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -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() {
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<_>>();
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -634,6 +634,7 @@ symbols! {
|
||||
impl_macros,
|
||||
impl_trait_in_bindings,
|
||||
import_shadowing,
|
||||
imported_main,
|
||||
in_band_lifetimes,
|
||||
include,
|
||||
include_bytes,
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
if error {
|
||||
return;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
)
|
||||
}));
|
||||
|
||||
require_same_types(
|
||||
tcx,
|
||||
&ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
|
||||
se_ty,
|
||||
tcx.mk_fn_ptr(actual),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
span_bug!(main_span, "main has a non-function type: found `{}`", main_t);
|
||||
hir_id
|
||||
} else {
|
||||
CRATE_HIR_ID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main_fn_asyncness_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 { 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 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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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`.
|
||||
|
1
src/test/ui/entry-point/auxiliary/main_functions.rs
Normal file
1
src/test/ui/entry-point/auxiliary/main_functions.rs
Normal file
@ -0,0 +1 @@
|
||||
pub fn boilerplate() {}
|
7
src/test/ui/entry-point/imported_main_conflict.rs
Normal file
7
src/test/ui/entry-point/imported_main_conflict.rs
Normal file
@ -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::*;
|
18
src/test/ui/entry-point/imported_main_conflict.stderr
Normal file
18
src/test/ui/entry-point/imported_main_conflict.stderr
Normal file
@ -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`.
|
@ -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;
|
@ -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`.
|
7
src/test/ui/entry-point/imported_main_const_forbidden.rs
Normal file
7
src/test/ui/entry-point/imported_main_const_forbidden.rs
Normal file
@ -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;
|
17
src/test/ui/entry-point/imported_main_const_forbidden.stderr
Normal file
17
src/test/ui/entry-point/imported_main_const_forbidden.stderr
Normal file
@ -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`.
|
@ -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
|
@ -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
|
||||
|
9
src/test/ui/entry-point/imported_main_from_inner_mod.rs
Normal file
9
src/test/ui/entry-point/imported_main_from_inner_mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// run-pass
|
||||
#![feature(imported_main)]
|
||||
|
||||
pub mod foo {
|
||||
pub fn bar() {
|
||||
println!("Hello world!");
|
||||
}
|
||||
}
|
||||
use foo::bar as main;
|
@ -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;
|
6
src/test/ui/feature-gates/feature-gate-imported_main.rs
Normal file
6
src/test/ui/feature-gates/feature-gate-imported_main.rs
Normal file
@ -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
|
12
src/test/ui/feature-gates/feature-gate-imported_main.stderr
Normal file
12
src/test/ui/feature-gates/feature-gate-imported_main.stderr
Normal file
@ -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`.
|
@ -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
|
||||
|
@ -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 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0601`.
|
||||
|
@ -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]`.
|
||||
|
Loading…
Reference in New Issue
Block a user