Implement RFC 1260 with feature_name imported_main
.
This commit is contained in:
parent
727d101561
commit
d261df4a72
38 changed files with 463 additions and 193 deletions
|
@ -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 (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 {
|
match entry_ty {
|
||||||
EntryFnType::Main => {
|
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) {
|
let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
|
||||||
Some((def_id, entry_ty)) => (
|
Some((def_id, entry_ty)) => (
|
||||||
def_id.to_def_id(),
|
def_id,
|
||||||
match entry_ty {
|
match entry_ty {
|
||||||
EntryFnType::Main => true,
|
EntryFnType::Main => true,
|
||||||
EntryFnType::Start => false,
|
EntryFnType::Start => false,
|
||||||
|
|
|
@ -344,7 +344,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||||
spflags |= DISPFlags::SPFlagOptimized;
|
spflags |= DISPFlags::SPFlagOptimized;
|
||||||
}
|
}
|
||||||
if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
|
if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
|
||||||
if id.to_def_id() == def_id {
|
if id == def_id {
|
||||||
spflags |= DISPFlags::SPFlagMainSubprogram;
|
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::profiling::{get_resident_set_size, print_time_passes_entry};
|
||||||
use rustc_data_structures::sync::{par_iter, ParallelIterator};
|
use rustc_data_structures::sync::{par_iter, ParallelIterator};
|
||||||
use rustc_hir as hir;
|
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_hir::lang_items::LangItem;
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
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,
|
cx: &'a Bx::CodegenCx,
|
||||||
) -> Option<Bx::Function> {
|
) -> Option<Bx::Function> {
|
||||||
let main_def_id = cx.tcx().entry_fn(LOCAL_CRATE).map(|(def_id, _)| def_id)?;
|
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
|
// We want to create the wrapper in the same codegen unit as Rust's main
|
||||||
// function.
|
// 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);
|
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>>(
|
fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
cx: &'a Bx::CodegenCx,
|
cx: &'a Bx::CodegenCx,
|
||||||
rust_main: Bx::Value,
|
rust_main: Bx::Value,
|
||||||
rust_main_def_id: LocalDefId,
|
rust_main_def_id: DefId,
|
||||||
use_start_lang_item: bool,
|
use_start_lang_item: bool,
|
||||||
) -> Bx::Function {
|
) -> Bx::Function {
|
||||||
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
|
// 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.
|
More than one `main` function was found.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0136
|
```compile_fail
|
||||||
fn main() {
|
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::map_in_place::MapInPlace;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::{Applicability, PResult};
|
use rustc_errors::{Applicability, FatalError, PResult};
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser, RecoverComma};
|
use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser, RecoverComma};
|
||||||
use rustc_parse::validate_attr;
|
use rustc_parse::validate_attr;
|
||||||
|
@ -414,6 +414,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
kind.article(), kind.descr()
|
kind.article(), kind.descr()
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
// FIXME: this workaround issue #84569
|
||||||
|
FatalError.raise();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.cx.trace_macros_diag();
|
self.cx.trace_macros_diag();
|
||||||
|
|
|
@ -655,6 +655,9 @@ declare_features! (
|
||||||
/// Allows unsizing coercions in `const fn`.
|
/// Allows unsizing coercions in `const fn`.
|
||||||
(active, const_fn_unsize, "1.53.0", Some(64992), None),
|
(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
|
// feature-group-end: actual feature gates
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
|
@ -307,7 +307,7 @@ impl<'tcx> Queries<'tcx> {
|
||||||
_ => return,
|
_ => 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));
|
let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error));
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
match attr.meta_item_list() {
|
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::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
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_hir::{HirId, ItemId};
|
||||||
use rustc_session::config::OptLevel;
|
use rustc_session::config::OptLevel;
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
|
@ -93,7 +93,7 @@ impl<'tcx> MonoItem<'tcx> {
|
||||||
// indicator, then we'll be creating a globally shared version.
|
// indicator, then we'll be creating a globally shared version.
|
||||||
if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
|
if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
|
||||||
|| !instance.def.generates_cgu_internal_copy(tcx)
|
|| !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 };
|
return InstantiationMode::GloballyShared { may_conflict: false };
|
||||||
}
|
}
|
||||||
|
|
|
@ -1194,7 +1194,7 @@ rustc_queries! {
|
||||||
|
|
||||||
/// Identifies the entry-point (e.g., the `main` function) for a given
|
/// 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).
|
/// 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" }
|
desc { "looking up the entry function of a crate" }
|
||||||
}
|
}
|
||||||
query plugin_registrar_fn(_: CrateNum) -> Option<DefId> {
|
query plugin_registrar_fn(_: CrateNum) -> Option<DefId> {
|
||||||
|
|
|
@ -20,8 +20,8 @@ use crate::ty::TyKind::*;
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
|
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
|
||||||
DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
|
DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
|
||||||
InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate,
|
InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig,
|
||||||
PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
|
Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
|
||||||
TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
|
TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
|
||||||
};
|
};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
|
@ -1025,6 +1025,8 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
layout_interner: ShardedHashMap<&'tcx Layout, ()>,
|
layout_interner: ShardedHashMap<&'tcx Layout, ()>,
|
||||||
|
|
||||||
output_filenames: Arc<OutputFilenames>,
|
output_filenames: Arc<OutputFilenames>,
|
||||||
|
|
||||||
|
pub main_def: Option<MainDefinition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TyCtxt<'tcx> {
|
impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
@ -1185,6 +1187,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
const_stability_interner: Default::default(),
|
const_stability_interner: Default::default(),
|
||||||
alloc_map: Lock::new(interpret::AllocMap::new()),
|
alloc_map: Lock::new(interpret::AllocMap::new()),
|
||||||
output_filenames: Arc::new(output_filenames.clone()),
|
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
|
/// Extern prelude entries. The value is `true` if the entry was introduced
|
||||||
/// via `extern crate` item and not `--extern` option or compiler built-in.
|
/// via `extern crate` item and not `--extern` option or compiler built-in.
|
||||||
pub extern_prelude: FxHashMap<Symbol, bool>,
|
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
|
/// 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>,
|
tcx: TyCtxt<'tcx>,
|
||||||
mode: MonoItemCollectionMode,
|
mode: MonoItemCollectionMode,
|
||||||
output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
|
output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
|
||||||
entry_fn: Option<(LocalDefId, EntryFnType)>,
|
entry_fn: Option<(DefId, EntryFnType)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
|
impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
|
||||||
|
@ -1154,7 +1154,7 @@ impl RootCollector<'_, 'v> {
|
||||||
&& match self.mode {
|
&& match self.mode {
|
||||||
MonoItemCollectionMode::Eager => true,
|
MonoItemCollectionMode::Eager => true,
|
||||||
MonoItemCollectionMode::Lazy => {
|
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.is_reachable_non_generic(def_id)
|
||||||
|| self
|
|| self
|
||||||
.tcx
|
.tcx
|
||||||
|
|
|
@ -472,7 +472,9 @@ fn create_and_seed_worklist<'tcx>(
|
||||||
)
|
)
|
||||||
.chain(
|
.chain(
|
||||||
// Seed entry point
|
// 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<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use rustc_ast::entry::EntryPointType;
|
use rustc_ast::entry::EntryPointType;
|
||||||
use rustc_errors::struct_span_err;
|
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::itemlikevisit::ItemLikeVisitor;
|
||||||
use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem, CRATE_HIR_ID};
|
use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem, CRATE_HIR_ID};
|
||||||
use rustc_middle::hir::map::Map;
|
use rustc_middle::hir::map::Map;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::config::{CrateType, EntryFnType};
|
use rustc_session::config::{CrateType, EntryFnType};
|
||||||
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
@ -16,9 +17,6 @@ struct EntryContext<'a, 'tcx> {
|
||||||
|
|
||||||
map: Map<'tcx>,
|
map: Map<'tcx>,
|
||||||
|
|
||||||
/// The top-level function called `main`.
|
|
||||||
main_fn: Option<(HirId, Span)>,
|
|
||||||
|
|
||||||
/// The function that has attribute named `main`.
|
/// The function that has attribute named `main`.
|
||||||
attr_main_fn: Option<(HirId, Span)>,
|
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);
|
assert_eq!(cnum, LOCAL_CRATE);
|
||||||
|
|
||||||
let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
|
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 {
|
let mut ctxt = EntryContext {
|
||||||
session: tcx.sess,
|
session: tcx.sess,
|
||||||
map: tcx.hir(),
|
map: tcx.hir(),
|
||||||
main_fn: None,
|
|
||||||
attr_main_fn: None,
|
attr_main_fn: None,
|
||||||
start_fn: None,
|
start_fn: None,
|
||||||
non_main_fns: Vec::new(),
|
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");
|
throw_attr_err(&ctxt.session, attr.span, "rustc_main");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntryPointType::MainNamed => {
|
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::OtherMain => {
|
EntryPointType::OtherMain => {
|
||||||
ctxt.non_main_fns.push((item.hir_id(), item.span));
|
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(
|
fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
|
||||||
tcx: TyCtxt<'_>,
|
|
||||||
visitor: &EntryContext<'_, '_>,
|
|
||||||
) -> Option<(LocalDefId, EntryFnType)> {
|
|
||||||
if let Some((hir_id, _)) = visitor.start_fn {
|
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 {
|
} else if let Some((hir_id, _)) = visitor.attr_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((hir_id, _)) = visitor.main_fn {
|
} else if let Some(def_id) = tcx.main_def.and_then(|main_def| main_def.opt_fn_def_id()) {
|
||||||
Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
|
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 {
|
} else {
|
||||||
no_main_err(tcx, visitor);
|
no_main_err(tcx, visitor);
|
||||||
None
|
None
|
||||||
|
@ -213,6 +210,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
|
||||||
} else {
|
} else {
|
||||||
err.note(¬e);
|
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()) {
|
if tcx.sess.teach(&err.get_code().unwrap()) {
|
||||||
err.note(
|
err.note(
|
||||||
"If you don't know the basics of Rust, you can go look to the Rust Book \
|
"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();
|
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)
|
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::middle::cstore::{CrateStore, MetadataLoaderDyn};
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
use rustc_middle::ty::query::Providers;
|
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;
|
||||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
@ -1021,6 +1021,8 @@ pub struct Resolver<'a> {
|
||||||
trait_impl_items: FxHashSet<LocalDefId>,
|
trait_impl_items: FxHashSet<LocalDefId>,
|
||||||
|
|
||||||
legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
|
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.
|
/// 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(),
|
next_disambiguator: Default::default(),
|
||||||
trait_impl_items: Default::default(),
|
trait_impl_items: Default::default(),
|
||||||
legacy_const_generic_args: Default::default(),
|
legacy_const_generic_args: Default::default(),
|
||||||
|
main_def: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let root_parent_scope = ParentScope::module(graph_root, &resolver);
|
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_trait_imports = self.maybe_unused_trait_imports;
|
||||||
let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
|
let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
|
||||||
let glob_map = self.glob_map;
|
let glob_map = self.glob_map;
|
||||||
|
let main_def = self.main_def;
|
||||||
ResolverOutputs {
|
ResolverOutputs {
|
||||||
definitions,
|
definitions,
|
||||||
cstore: Box::new(self.crate_loader.into_cstore()),
|
cstore: Box::new(self.crate_loader.into_cstore()),
|
||||||
|
@ -1396,6 +1400,7 @@ impl<'a> Resolver<'a> {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
|
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
main_def,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1414,6 +1419,7 @@ impl<'a> Resolver<'a> {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
|
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
|
||||||
.collect(),
|
.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_imports", || ImportResolver { r: self }.finalize_imports());
|
||||||
self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
|
self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
|
||||||
self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
|
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_check_unused", || self.check_unused(krate));
|
||||||
self.session.time("resolve_report_errors", || self.report_errors(krate));
|
self.session.time("resolve_report_errors", || self.report_errors(krate));
|
||||||
self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate));
|
self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate));
|
||||||
|
@ -3350,6 +3357,32 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
None
|
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 {
|
fn names_to_string(names: &[Symbol]) -> String {
|
||||||
|
|
|
@ -634,6 +634,7 @@ symbols! {
|
||||||
impl_macros,
|
impl_macros,
|
||||||
impl_trait_in_bindings,
|
impl_trait_in_bindings,
|
||||||
import_shadowing,
|
import_shadowing,
|
||||||
|
imported_main,
|
||||||
in_band_lifetimes,
|
in_band_lifetimes,
|
||||||
include,
|
include,
|
||||||
include_bytes,
|
include_bytes,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use super::*;
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_errors::{Applicability, ErrorReported};
|
use rustc_errors::{Applicability, ErrorReported};
|
||||||
use rustc_hir as hir;
|
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::intravisit::Visitor;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
|
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::layout::MAX_SIMD_LANES;
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||||
use rustc_middle::ty::{self, ParamEnv, RegionKind, ToPredicate, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt};
|
||||||
use rustc_session::config::EntryFnType;
|
|
||||||
use rustc_session::lint::builtin::UNINHABITED_STATIC;
|
use rustc_session::lint::builtin::UNINHABITED_STATIC;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{self, MultiSpan, Span};
|
use rustc_span::{self, MultiSpan, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::opaque_types::InferCtxtExt as _;
|
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::error_reporting::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
|
||||||
use rustc_ty_utils::representability::{self, Representability};
|
use rustc_ty_utils::representability::{self, Representability};
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
@ -326,29 +325,6 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
|
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) -> !`
|
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
|
||||||
if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
|
if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
|
||||||
if panic_impl_did == hir.local_def_id(fn_id).to_def_id() {
|
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::query::Providers;
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::WithConstness;
|
|
||||||
use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType};
|
use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType};
|
||||||
use rustc_session::config;
|
use rustc_session::config;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
|
|
|
@ -97,8 +97,8 @@ mod variance;
|
||||||
|
|
||||||
use rustc_errors::{struct_span_err, ErrorReported};
|
use rustc_errors::{struct_span_err, ErrorReported};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_hir::Node;
|
use rustc_hir::{Node, CRATE_HIR_ID};
|
||||||
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
|
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::TraitEngineExt as _;
|
use rustc_infer::traits::TraitEngineExt as _;
|
||||||
use rustc_middle::middle;
|
use rustc_middle::middle;
|
||||||
|
@ -110,7 +110,7 @@ use rustc_span::{symbol::sym, Span, DUMMY_SP};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
|
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
@ -164,106 +164,203 @@ fn require_same_types<'tcx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) {
|
fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
||||||
let main_id = tcx.hir().local_def_id_to_hir_id(main_def_id);
|
let main_fnsig = tcx.fn_sig(main_def_id);
|
||||||
let main_span = tcx.def_span(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);
|
fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId {
|
||||||
for attr in attrs {
|
if let Some(local_def_id) = def_id.as_local() {
|
||||||
if tcx.sess.check_name(attr, sym::track_caller) {
|
let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
|
||||||
tcx.sess
|
let hir_type = tcx.type_of(local_def_id);
|
||||||
.struct_span_err(
|
if !matches!(hir_type.kind(), ty::FnDef(..)) {
|
||||||
attr.span,
|
span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
|
||||||
"`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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
hir_id
|
||||||
let actual = tcx.fn_sig(main_def_id);
|
} else {
|
||||||
let expected_return_type = if tcx.lang_items().termination().is_some() {
|
CRATE_HIR_ID
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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_id = tcx.hir().local_def_id_to_hir_id(start_def_id);
|
||||||
let start_span = tcx.def_span(start_def_id);
|
let start_span = tcx.def_span(start_def_id);
|
||||||
let start_t = tcx.type_of(start_def_id);
|
let start_t = tcx.type_of(start_def_id);
|
||||||
|
|
|
@ -2,6 +2,5 @@
|
||||||
|
|
||||||
async fn main() -> Result<i32, ()> {
|
async fn main() -> Result<i32, ()> {
|
||||||
//~^ ERROR `main` function is not allowed to be `async`
|
//~^ ERROR `main` function is not allowed to be `async`
|
||||||
//~^^ ERROR `main` has invalid return type `impl Future`
|
|
||||||
Ok(1)
|
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`
|
error[E0752]: `main` function is not allowed to be `async`
|
||||||
--> $DIR/issue-68523.rs:3:1
|
--> $DIR/issue-68523.rs:3:1
|
||||||
|
|
|
|
||||||
LL | async fn main() -> Result<i32, ()> {
|
LL | async fn main() -> Result<i32, ()> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `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 this error, try `rustc --explain E0752`.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
|
||||||
|
|
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.
|
// 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() {}`.
|
// `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`.
|
||||||
#![feature(custom_inner_attributes)]
|
#![feature(custom_inner_attributes)]
|
||||||
//~^ ERROR `main` function not found in crate `issue_59191_replace_root_with_fn` [E0601]
|
|
||||||
#![issue_59191::no_main]
|
#![issue_59191::no_main]
|
||||||
//~^ ERROR expected crate top-level item to be a module after macro expansion, found a function
|
//~^ 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
|
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]
|
LL | #![issue_59191::no_main]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= 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`
|
error: aborting due to previous error
|
||||||
--> $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
|
|
||||||
|
|
||||||
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 {
|
pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
|
||||||
cx.tcx
|
cx.tcx
|
||||||
.entry_fn(LOCAL_CRATE)
|
.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]`.
|
/// Returns `true` if the expression is in the program's `#[panic_handler]`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue