Skip to content

Commit

Permalink
Auto merge of rust-lang#84401 - crlf0710:impl_main_by_path, r=petroch…
Browse files Browse the repository at this point in the history
…enkov

Implement RFC 1260 with feature_name `imported_main`.

This is the second extraction part of rust-lang#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 rust-lang#28937
r? `@petrochenkov`
  • Loading branch information
bors committed Apr 30, 2021
2 parents a45f0d7 + d261df4 commit bcd696d
Show file tree
Hide file tree
Showing 38 changed files with 459 additions and 189 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/driver/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/main_shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
27 changes: 22 additions & 5 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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)`,
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0136.md
Original file line number Diff line number Diff line change
@@ -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() {
// ...
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
// -------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 };
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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,
}
}

Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir/src/monomorphize/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<_>>();

Expand Down
51 changes: 28 additions & 23 deletions compiler/rustc_passes/src/entry.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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)>,

Expand Down Expand Up @@ -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);
Expand All @@ -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(),
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -213,6 +210,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
} else {
err.note(&note);
}

if let Some(main_def) = tcx.main_def {
if main_def.opt_fn_def_id().is_none() {
// There is something at `crate::main`, but it is not a function definition.
err.span_label(main_def.span, &format!("non-function item at `crate::main` is found"));
}
}

if tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"If you don't know the basics of Rust, you can go look to the Rust Book \
Expand All @@ -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)
}

Expand Down

0 comments on commit bcd696d

Please sign in to comment.