Implements RFC 1937: ?
in main
This is the first part of the RFC 1937 that supports new `Termination` trait in the rust `main` function.
This commit is contained in:
parent
8cdde6db71
commit
d7918fb2e8
13 changed files with 304 additions and 52 deletions
|
@ -338,6 +338,8 @@ language_item_table! {
|
||||||
U128ShloFnLangItem, "u128_shlo", u128_shlo_fn;
|
U128ShloFnLangItem, "u128_shlo", u128_shlo_fn;
|
||||||
I128ShroFnLangItem, "i128_shro", i128_shro_fn;
|
I128ShroFnLangItem, "i128_shro", i128_shro_fn;
|
||||||
U128ShroFnLangItem, "u128_shro", u128_shro_fn;
|
U128ShroFnLangItem, "u128_shro", u128_shro_fn;
|
||||||
|
|
||||||
|
TerminationTraitLangItem, "termination", termination;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
|
impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
|
||||||
|
|
|
@ -194,11 +194,13 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
use rustc::hir::map as hir_map;
|
use rustc::hir::map as hir_map;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::middle::const_val::ConstVal;
|
||||||
use rustc::middle::lang_items::{ExchangeMallocFnLangItem};
|
use rustc::middle::lang_items::{ExchangeMallocFnLangItem,StartFnLangItem};
|
||||||
|
use rustc::middle::trans::TransItem;
|
||||||
use rustc::traits;
|
use rustc::traits;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::{Substs, Kind};
|
||||||
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
|
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
|
||||||
use rustc::ty::adjustment::CustomCoerceUnsized;
|
use rustc::ty::adjustment::CustomCoerceUnsized;
|
||||||
|
use rustc::session::config;
|
||||||
use rustc::mir::{self, Location};
|
use rustc::mir::{self, Location};
|
||||||
use rustc::mir::visit::Visitor as MirVisitor;
|
use rustc::mir::visit::Visitor as MirVisitor;
|
||||||
use rustc::mir::mono::MonoItem;
|
use rustc::mir::mono::MonoItem;
|
||||||
|
@ -212,6 +214,8 @@ use rustc_data_structures::bitvec::BitVector;
|
||||||
|
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
|
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
||||||
pub enum MonoItemCollectionMode {
|
pub enum MonoItemCollectionMode {
|
||||||
Eager,
|
Eager,
|
||||||
|
@ -329,6 +333,8 @@ fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
tcx.hir.local_def_id(node_id)
|
tcx.hir.local_def_id(node_id)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
debug!("collect_roots: entry_fn = {:?}", entry_fn);
|
||||||
|
|
||||||
let mut visitor = RootCollector {
|
let mut visitor = RootCollector {
|
||||||
tcx,
|
tcx,
|
||||||
mode,
|
mode,
|
||||||
|
@ -951,16 +957,8 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
|
||||||
// actually used somewhere. Just declaring them is insufficient.
|
// actually used somewhere. Just declaring them is insufficient.
|
||||||
}
|
}
|
||||||
hir::ItemFn(..) => {
|
hir::ItemFn(..) => {
|
||||||
let tcx = self.tcx;
|
let def_id = self.tcx.hir.local_def_id(item.id);
|
||||||
let def_id = tcx.hir.local_def_id(item.id);
|
self.push_if_root(def_id);
|
||||||
|
|
||||||
if self.is_root(def_id) {
|
|
||||||
debug!("RootCollector: ItemFn({})",
|
|
||||||
def_id_to_string(tcx, def_id));
|
|
||||||
|
|
||||||
let instance = Instance::mono(tcx, def_id);
|
|
||||||
self.output.push(MonoItem::Fn(instance));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -973,16 +971,8 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
|
||||||
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
|
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
|
||||||
match ii.node {
|
match ii.node {
|
||||||
hir::ImplItemKind::Method(hir::MethodSig { .. }, _) => {
|
hir::ImplItemKind::Method(hir::MethodSig { .. }, _) => {
|
||||||
let tcx = self.tcx;
|
let def_id = self.tcx.hir.local_def_id(ii.id);
|
||||||
let def_id = tcx.hir.local_def_id(ii.id);
|
self.push_if_root(def_id);
|
||||||
|
|
||||||
if self.is_root(def_id) {
|
|
||||||
debug!("RootCollector: MethodImplItem({})",
|
|
||||||
def_id_to_string(tcx, def_id));
|
|
||||||
|
|
||||||
let instance = Instance::mono(tcx, def_id);
|
|
||||||
self.output.push(MonoItem::Fn(instance));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => { /* Nothing to do here */ }
|
_ => { /* Nothing to do here */ }
|
||||||
}
|
}
|
||||||
|
@ -1003,6 +993,56 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If `def_id` represents a root, then push it onto the list of
|
||||||
|
/// outputs. (Note that all roots must be monomorphic.)
|
||||||
|
fn push_if_root(&mut self, def_id: DefId) {
|
||||||
|
if self.is_root(def_id) {
|
||||||
|
debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
|
||||||
|
|
||||||
|
let instance = Instance::mono(self.tcx, def_id);
|
||||||
|
self.output.push(create_fn_trans_item(instance));
|
||||||
|
|
||||||
|
self.push_extra_entry_roots(def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// As a special case, when/if we encounter the
|
||||||
|
/// `main()` function, we also have to generate a
|
||||||
|
/// monomorphized copy of the start lang item based on
|
||||||
|
/// the return type of `main`. This is not needed when
|
||||||
|
/// the user writes their own `start` manually.
|
||||||
|
fn push_extra_entry_roots(&mut self, def_id: DefId) {
|
||||||
|
if self.entry_fn != Some(def_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.tcx.sess.entry_type.get() != Some(config::EntryMain) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_def_id = match self.tcx.lang_items().require(StartFnLangItem) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(err) => self.tcx.sess.fatal(&err),
|
||||||
|
};
|
||||||
|
let main_ret_ty = self.tcx.fn_sig(def_id).output();
|
||||||
|
|
||||||
|
// Given that `main()` has no arguments,
|
||||||
|
// then its return type cannot have
|
||||||
|
// late-bound regions, since late-bound
|
||||||
|
// regions must appear in the argument
|
||||||
|
// listing.
|
||||||
|
let main_ret_ty = self.tcx.no_late_bound_regions(&main_ret_ty).unwrap();
|
||||||
|
|
||||||
|
let start_instance = Instance::resolve(
|
||||||
|
self.tcx,
|
||||||
|
ty::ParamEnv::empty(traits::Reveal::All),
|
||||||
|
start_def_id,
|
||||||
|
self.tcx.mk_substs(iter::once(Kind::from(main_ret_ty)))
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
self.output.push(create_fn_trans_item(start_instance));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
|
fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
|
||||||
|
|
|
@ -106,7 +106,8 @@ use monomorphize::collector::InliningMap;
|
||||||
use rustc::dep_graph::WorkProductId;
|
use rustc::dep_graph::WorkProductId;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir::map::DefPathData;
|
use rustc::hir::map::DefPathData;
|
||||||
use rustc::mir::mono::{Linkage, Visibility};
|
use rustc::middle::lang_items::StartFnLangItem;
|
||||||
|
use rustc::middle::trans::{Linkage, Visibility};
|
||||||
use rustc::ty::{self, TyCtxt, InstanceDef};
|
use rustc::ty::{self, TyCtxt, InstanceDef};
|
||||||
use rustc::ty::item_path::characteristic_def_id_of_type;
|
use rustc::ty::item_path::characteristic_def_id_of_type;
|
||||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||||
|
@ -312,7 +313,13 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
MonoItem::Fn(ref instance) => {
|
MonoItem::Fn(ref instance) => {
|
||||||
let visibility = match instance.def {
|
let visibility = match instance.def {
|
||||||
InstanceDef::Item(def_id) => {
|
InstanceDef::Item(def_id) => {
|
||||||
if def_id.is_local() {
|
let start_def_id = tcx.lang_items().require(StartFnLangItem);
|
||||||
|
|
||||||
|
// If we encounter the lang start item, we set the visibility to
|
||||||
|
// default.
|
||||||
|
if start_def_id == Ok(def_id) {
|
||||||
|
Visibility::Default
|
||||||
|
} else if def_id.is_local() {
|
||||||
if tcx.is_exported_symbol(def_id) {
|
if tcx.is_exported_symbol(def_id) {
|
||||||
Visibility::Default
|
Visibility::Default
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -44,6 +44,7 @@ use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
|
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
|
||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
use rustc::dep_graph::{DepNode, DepConstructor};
|
use rustc::dep_graph::{DepNode, DepConstructor};
|
||||||
|
use rustc::ty::subst::Kind;
|
||||||
use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
|
use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
|
||||||
use rustc::util::common::{time, print_time_passes_entry};
|
use rustc::util::common::{time, print_time_passes_entry};
|
||||||
use rustc::session::config::{self, NoDebugInfo};
|
use rustc::session::config::{self, NoDebugInfo};
|
||||||
|
@ -79,6 +80,7 @@ use std::str;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Instant, Duration};
|
use std::time::{Instant, Duration};
|
||||||
use std::i32;
|
use std::i32;
|
||||||
|
use std::iter;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use syntax_pos::symbol::InternedString;
|
use syntax_pos::symbol::InternedString;
|
||||||
|
@ -540,17 +542,28 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) {
|
||||||
|
|
||||||
let et = ccx.sess().entry_type.get().unwrap();
|
let et = ccx.sess().entry_type.get().unwrap();
|
||||||
match et {
|
match et {
|
||||||
config::EntryMain => create_entry_fn(ccx, span, main_llfn, true),
|
config::EntryMain => create_entry_fn(ccx, span, main_llfn, main_def_id, true),
|
||||||
config::EntryStart => create_entry_fn(ccx, span, main_llfn, false),
|
config::EntryStart => create_entry_fn(ccx, span, main_llfn, main_def_id, false),
|
||||||
config::EntryNone => {} // Do nothing.
|
config::EntryNone => {} // Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_entry_fn(ccx: &CrateContext,
|
fn create_entry_fn<'ccx>(ccx: &'ccx CrateContext,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
rust_main: ValueRef,
|
rust_main: ValueRef,
|
||||||
|
rust_main_def_id: DefId,
|
||||||
use_start_lang_item: bool) {
|
use_start_lang_item: bool) {
|
||||||
// Signature of native main(), corresponding to C's `int main(int, char **)`
|
// The libstd lang_start function does not return anything, while user defined lang start
|
||||||
let llfty = Type::func(&[Type::c_int(ccx), Type::i8p(ccx).ptr_to()], &Type::c_int(ccx));
|
// returns a isize
|
||||||
|
let start_output_ty = if use_start_lang_item { Type::void(ccx) } else { Type::c_int(ccx) };
|
||||||
|
let llfty = Type::func(&[Type::c_int(ccx), Type::i8p(ccx).ptr_to()], &start_output_ty);
|
||||||
|
|
||||||
|
let main_ret_ty = ccx.tcx().fn_sig(rust_main_def_id).output();
|
||||||
|
// Given that `main()` has no arguments,
|
||||||
|
// then its return type cannot have
|
||||||
|
// late-bound regions, since late-bound
|
||||||
|
// regions must appear in the argument
|
||||||
|
// listing.
|
||||||
|
let main_ret_ty = ccx.tcx().no_late_bound_regions(&main_ret_ty).unwrap();
|
||||||
|
|
||||||
if declare::get_defined_value(ccx, "main").is_some() {
|
if declare::get_defined_value(ccx, "main").is_some() {
|
||||||
// FIXME: We should be smart and show a better diagnostic here.
|
// FIXME: We should be smart and show a better diagnostic here.
|
||||||
|
@ -577,8 +590,8 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) {
|
||||||
|
|
||||||
let (start_fn, args) = if use_start_lang_item {
|
let (start_fn, args) = if use_start_lang_item {
|
||||||
let start_def_id = ccx.tcx().require_lang_item(StartFnLangItem);
|
let start_def_id = ccx.tcx().require_lang_item(StartFnLangItem);
|
||||||
let start_instance = Instance::mono(ccx.tcx(), start_def_id);
|
let start_fn = callee::resolve_and_get_fn(ccx, start_def_id, ccx.tcx().mk_substs(
|
||||||
let start_fn = callee::get_fn(ccx, start_instance);
|
iter::once(Kind::from(main_ret_ty))));
|
||||||
(start_fn, vec![bld.pointercast(rust_main, Type::i8p(ccx).ptr_to()),
|
(start_fn, vec![bld.pointercast(rust_main, Type::i8p(ccx).ptr_to()),
|
||||||
arg_argc, arg_argv])
|
arg_argc, arg_argv])
|
||||||
} else {
|
} else {
|
||||||
|
@ -588,10 +601,13 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) {
|
||||||
|
|
||||||
let result = bld.call(start_fn, &args, None);
|
let result = bld.call(start_fn, &args, None);
|
||||||
|
|
||||||
// Return rust start function's result from native main()
|
if use_start_lang_item {
|
||||||
|
bld.ret_void();
|
||||||
|
} else {
|
||||||
bld.ret(bld.intcast(result, Type::c_int(ccx), true));
|
bld.ret(bld.intcast(result, Type::c_int(ccx), true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn contains_null(s: &str) -> bool {
|
fn contains_null(s: &str) -> bool {
|
||||||
s.bytes().any(|b| b == 0)
|
s.bytes().any(|b| b == 0)
|
||||||
|
|
|
@ -93,17 +93,18 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
|
||||||
use rustc::infer::anon_types::AnonTypeDecl;
|
use rustc::infer::anon_types::AnonTypeDecl;
|
||||||
use rustc::infer::type_variable::{TypeVariableOrigin};
|
use rustc::infer::type_variable::{TypeVariableOrigin};
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
|
use rustc::middle::lang_items::TerminationTraitLangItem;
|
||||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||||
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
|
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
|
||||||
use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
|
use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
|
||||||
use rustc::ty::{self, Ty, TyCtxt, Visibility};
|
use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
|
||||||
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||||
use rustc::ty::fold::TypeFoldable;
|
use rustc::ty::fold::TypeFoldable;
|
||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
use rustc::ty::util::{Representability, IntTypeExt};
|
use rustc::ty::util::{Representability, IntTypeExt};
|
||||||
use errors::{DiagnosticBuilder, DiagnosticId};
|
use errors::{DiagnosticBuilder, DiagnosticId};
|
||||||
use require_c_abi_if_variadic;
|
use require_c_abi_if_variadic;
|
||||||
use session::{CompileIncomplete, Session};
|
use session::{CompileIncomplete, config, Session};
|
||||||
use TypeAndSubsts;
|
use TypeAndSubsts;
|
||||||
use lint;
|
use lint;
|
||||||
use util::common::{ErrorReported, indenter};
|
use util::common::{ErrorReported, indenter};
|
||||||
|
@ -115,6 +116,7 @@ use std::collections::hash_map::Entry;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
|
use std::iter;
|
||||||
use std::ops::{self, Deref};
|
use std::ops::{self, Deref};
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -1064,6 +1066,24 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
|
||||||
}
|
}
|
||||||
fcx.demand_suptype(span, ret_ty, actual_return_ty);
|
fcx.demand_suptype(span, ret_ty, actual_return_ty);
|
||||||
|
|
||||||
|
if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() {
|
||||||
|
if id == fn_id {
|
||||||
|
match fcx.sess().entry_type.get() {
|
||||||
|
Some(config::EntryMain) => {
|
||||||
|
let term_id = fcx.tcx.require_lang_item(TerminationTraitLangItem);
|
||||||
|
|
||||||
|
let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty)));
|
||||||
|
let trait_ref = ty::TraitRef::new(term_id, substs);
|
||||||
|
let cause = traits::ObligationCause::new(span, fn_id,
|
||||||
|
ObligationCauseCode::MainFunctionType);
|
||||||
|
inherited.register_predicate(
|
||||||
|
traits::Obligation::new(cause, param_env, trait_ref.to_predicate()));
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(fcx, gen_ty)
|
(fcx, gen_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,6 @@ use syntax::ast;
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
use std::iter;
|
|
||||||
// NB: This module needs to be declared first so diagnostics are
|
// NB: This module needs to be declared first so diagnostics are
|
||||||
// registered before they are used.
|
// registered before they are used.
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
|
@ -200,21 +199,6 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
let se_ty = tcx.mk_fn_ptr(ty::Binder(
|
|
||||||
tcx.mk_fn_sig(
|
|
||||||
iter::empty(),
|
|
||||||
tcx.mk_nil(),
|
|
||||||
false,
|
|
||||||
hir::Unsafety::Normal,
|
|
||||||
Abi::Rust
|
|
||||||
)
|
|
||||||
));
|
|
||||||
|
|
||||||
require_same_types(
|
|
||||||
tcx,
|
|
||||||
&ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
|
|
||||||
se_ty,
|
|
||||||
tcx.mk_fn_ptr(tcx.fn_sig(main_def_id)));
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
span_bug!(main_span,
|
span_bug!(main_span,
|
||||||
|
|
|
@ -308,6 +308,7 @@
|
||||||
#![feature(str_char)]
|
#![feature(str_char)]
|
||||||
#![feature(str_internals)]
|
#![feature(str_internals)]
|
||||||
#![feature(str_utf16)]
|
#![feature(str_utf16)]
|
||||||
|
#![feature(termination_trait)]
|
||||||
#![feature(test, rustc_private)]
|
#![feature(test, rustc_private)]
|
||||||
#![feature(thread_local)]
|
#![feature(thread_local)]
|
||||||
#![feature(toowned_clone_into)]
|
#![feature(toowned_clone_into)]
|
||||||
|
@ -499,6 +500,11 @@ mod memchr;
|
||||||
// The runtime entry point and a few unstable public functions used by the
|
// The runtime entry point and a few unstable public functions used by the
|
||||||
// compiler
|
// compiler
|
||||||
pub mod rt;
|
pub mod rt;
|
||||||
|
// The trait to support returning arbitrary types in the main function
|
||||||
|
mod termination;
|
||||||
|
|
||||||
|
#[unstable(feature = "termination_trait", issue = "0")]
|
||||||
|
pub use self::termination::Termination;
|
||||||
|
|
||||||
// Include a number of private modules that exist solely to provide
|
// Include a number of private modules that exist solely to provide
|
||||||
// the rustdoc documentation for primitive types. Using `include!`
|
// the rustdoc documentation for primitive types. Using `include!`
|
||||||
|
|
|
@ -26,7 +26,50 @@
|
||||||
// Reexport some of our utilities which are expected by other crates.
|
// Reexport some of our utilities which are expected by other crates.
|
||||||
pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count};
|
pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count};
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(any(test, stage0)))]
|
||||||
|
#[lang = "start"]
|
||||||
|
fn lang_start<T: ::termination::Termination + 'static>
|
||||||
|
(main: fn() -> T, argc: isize, argv: *const *const u8) -> !
|
||||||
|
{
|
||||||
|
use panic;
|
||||||
|
use sys;
|
||||||
|
use sys_common;
|
||||||
|
use sys_common::thread_info;
|
||||||
|
use thread::Thread;
|
||||||
|
use process;
|
||||||
|
#[cfg(not(feature = "backtrace"))]
|
||||||
|
use mem;
|
||||||
|
|
||||||
|
sys::init();
|
||||||
|
|
||||||
|
process::exit(unsafe {
|
||||||
|
let main_guard = sys::thread::guard::init();
|
||||||
|
sys::stack_overflow::init();
|
||||||
|
|
||||||
|
// Next, set up the current Thread with the guard information we just
|
||||||
|
// created. Note that this isn't necessary in general for new threads,
|
||||||
|
// but we just do this to name the main thread and to give it correct
|
||||||
|
// info about the stack bounds.
|
||||||
|
let thread = Thread::new(Some("main".to_owned()));
|
||||||
|
thread_info::set(main_guard, thread);
|
||||||
|
|
||||||
|
// Store our args if necessary in a squirreled away location
|
||||||
|
sys::args::init(argc, argv);
|
||||||
|
|
||||||
|
// Let's run some code!
|
||||||
|
#[cfg(feature = "backtrace")]
|
||||||
|
let exit_code = panic::catch_unwind(|| {
|
||||||
|
::sys_common::backtrace::__rust_begin_short_backtrace(move || main().report())
|
||||||
|
});
|
||||||
|
#[cfg(not(feature = "backtrace"))]
|
||||||
|
let exit_code = panic::catch_unwind(mem::transmute::<_, fn()>(main).report());
|
||||||
|
|
||||||
|
sys_common::cleanup();
|
||||||
|
exit_code.unwrap_or(101)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(test), stage0))]
|
||||||
#[lang = "start"]
|
#[lang = "start"]
|
||||||
fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize {
|
fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize {
|
||||||
use panic;
|
use panic;
|
||||||
|
|
74
src/libstd/termination.rs
Normal file
74
src/libstd/termination.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use error::Error;
|
||||||
|
use libc;
|
||||||
|
|
||||||
|
/// A trait for implementing arbitrary return types in the `main` function.
|
||||||
|
///
|
||||||
|
/// The c-main function only supports to return integers as return type.
|
||||||
|
/// So, every type implementing the `Termination` trait has to be converted
|
||||||
|
/// to an integer.
|
||||||
|
///
|
||||||
|
/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
|
||||||
|
/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
|
||||||
|
#[cfg_attr(not(stage0), lang = "termination")]
|
||||||
|
#[unstable(feature = "termination_trait", issue = "0")]
|
||||||
|
pub trait Termination {
|
||||||
|
/// Is called to get the representation of the value as status code.
|
||||||
|
/// This status code is returned to the operating system.
|
||||||
|
fn report(self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "termination_trait", issue = "0")]
|
||||||
|
impl Termination for () {
|
||||||
|
fn report(self) -> i32 { libc::EXIT_SUCCESS }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "termination_trait", issue = "0")]
|
||||||
|
impl<T: Termination, E: Error> Termination for Result<T, E> {
|
||||||
|
fn report(self) -> i32 {
|
||||||
|
match self {
|
||||||
|
Ok(val) => val.report(),
|
||||||
|
Err(err) => {
|
||||||
|
print_error(err);
|
||||||
|
libc::EXIT_FAILURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "termination_trait", issue = "0")]
|
||||||
|
fn print_error<E: Error>(err: E) {
|
||||||
|
eprintln!("Error: {}", err.description());
|
||||||
|
|
||||||
|
if let Some(ref err) = err.cause() {
|
||||||
|
eprintln!("Caused by: {}", err.description());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "termination_trait", issue = "0")]
|
||||||
|
impl Termination for ! {
|
||||||
|
fn report(self) -> i32 { unreachable!(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "termination_trait", issue = "0")]
|
||||||
|
impl Termination for bool {
|
||||||
|
fn report(self) -> i32 {
|
||||||
|
if self { libc::EXIT_SUCCESS } else { libc::EXIT_FAILURE }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "termination_trait", issue = "0")]
|
||||||
|
impl Termination for i32 {
|
||||||
|
fn report(self) -> i32 {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
15
src/test/compile-fail/termination-trait-not-satisfied.rs
Normal file
15
src/test/compile-fail/termination-trait-not-satisfied.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
struct ReturnType {}
|
||||||
|
|
||||||
|
fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied
|
||||||
|
ReturnType {}
|
||||||
|
}
|
13
src/test/run-pass/termination-trait-for-empty.rs
Normal file
13
src/test/run-pass/termination-trait-for-empty.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(termination_trait)]
|
||||||
|
|
||||||
|
fn main() {}
|
15
src/test/run-pass/termination-trait-for-i32.rs
Normal file
15
src/test/run-pass/termination-trait-for-i32.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(termination_trait)]
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
17
src/test/run-pass/termination-trait-for-result.rs
Normal file
17
src/test/run-pass/termination-trait-for-result.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(termination_trait)]
|
||||||
|
|
||||||
|
use std::io::Error;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue