about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-12-27 15:41:51 +0000
committerbors <bors@rust-lang.org>2017-12-27 15:41:51 +0000
commitbfbb1f5ce1e6a85a03219767cfc5c9bab3f7bf9e (patch)
treeb72634f6bee5eb0e51d428fe53ecd1c28c11b907 /src
parent63efff5a71269ae22b8769e2e6f9aaa2f940f823 (diff)
parent09f94bea4aca7696b58dd7e6668ca27d71908984 (diff)
downloadrust-bfbb1f5ce1e6a85a03219767cfc5c9bab3f7bf9e.tar.gz
rust-bfbb1f5ce1e6a85a03219767cfc5c9bab3f7bf9e.zip
Auto merge of #46479 - bkchr:termination_trait, r=arielb1
Implements RFC 1937: `?` in `main`

This is the first part of the RFC 1937 that supports new
`Termination` trait in the rust `main` function.

Thanks @nikomatsakis, @arielb1 and all other people in the gitter channel for all your help!

The support for doctest and `#[test]` is still missing, bu as @nikomatsakis said, smaller pull requests are better :)
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/lang_items.rs2
-rw-r--r--src/librustc/session/code_stats.rs18
-rw-r--r--src/librustc_mir/monomorphize/collector.rs83
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs26
-rw-r--r--src/librustc_trans/base.rs24
-rw-r--r--src/librustc_typeck/check/mod.rs29
-rw-r--r--src/librustc_typeck/lib.rs17
-rw-r--r--src/libstd/lib.rs6
-rw-r--r--src/libstd/rt.rs52
-rw-r--r--src/libstd/sys_common/backtrace.rs2
-rw-r--r--src/libstd/termination.rs86
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/test/codegen-units/item-collection/cross-crate-closures.rs8
-rw-r--r--src/test/codegen-units/item-collection/cross-crate-generic-functions.rs9
-rw-r--r--src/test/codegen-units/item-collection/cross-crate-trait-method.rs9
-rw-r--r--src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs9
-rw-r--r--src/test/codegen-units/item-collection/function-as-argument.rs8
-rw-r--r--src/test/codegen-units/item-collection/generic-drop-glue.rs8
-rw-r--r--src/test/codegen-units/item-collection/generic-functions.rs8
-rw-r--r--src/test/codegen-units/item-collection/generic-impl.rs9
-rw-r--r--src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs8
-rw-r--r--src/test/codegen-units/item-collection/instantiation-through-vtable.rs8
-rw-r--r--src/test/codegen-units/item-collection/items-within-generic-items.rs8
-rw-r--r--src/test/codegen-units/item-collection/non-generic-closures.rs8
-rw-r--r--src/test/codegen-units/item-collection/non-generic-drop-glue.rs8
-rw-r--r--src/test/codegen-units/item-collection/non-generic-functions.rs8
-rw-r--r--src/test/codegen-units/item-collection/static-init.rs10
-rw-r--r--src/test/codegen-units/item-collection/statics-and-consts.rs9
-rw-r--r--src/test/codegen-units/item-collection/trait-implementations.rs8
-rw-r--r--src/test/codegen-units/item-collection/trait-method-as-argument.rs8
-rw-r--r--src/test/codegen-units/item-collection/trait-method-default-impl.rs8
-rw-r--r--src/test/codegen-units/item-collection/transitive-drop-glue.rs9
-rw-r--r--src/test/codegen-units/item-collection/tuple-drop-glue.rs8
-rw-r--r--src/test/codegen-units/item-collection/unsizing.rs9
-rw-r--r--src/test/codegen-units/partitioning/methods-are-with-self-type.rs9
-rw-r--r--src/test/codegen-units/partitioning/vtable-through-const.rs11
-rw-r--r--src/test/compile-fail/feature-gate-termination_trait.rs13
-rw-r--r--src/test/compile-fail/main-wrong-type-2.rs3
-rw-r--r--src/test/compile-fail/termination-trait-not-satisfied.rs17
-rw-r--r--src/test/run-make/sepcomp-inlining/foo.rs7
-rw-r--r--src/test/run-pass/termination-trait-for-empty.rs (renamed from src/test/compile-fail/E0580.rs)6
-rw-r--r--src/test/run-pass/termination-trait-for-i32.rs15
-rw-r--r--src/test/run-pass/termination-trait-for-result.rs17
-rw-r--r--src/test/ui/print_type_sizes/anonymous.rs7
-rw-r--r--src/test/ui/print_type_sizes/generics.rs6
-rw-r--r--src/test/ui/print_type_sizes/multiple_types.rs6
-rw-r--r--src/test/ui/print_type_sizes/niche-filling.rs5
-rw-r--r--src/test/ui/print_type_sizes/no_duplicates.rs6
-rw-r--r--src/test/ui/print_type_sizes/packed.rs5
-rw-r--r--src/test/ui/print_type_sizes/padding.rs6
-rw-r--r--src/test/ui/print_type_sizes/repr-align.rs5
-rw-r--r--src/test/ui/print_type_sizes/uninhabited.rs5
-rw-r--r--src/test/ui/print_type_sizes/variants.rs6
53 files changed, 575 insertions, 113 deletions
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index f8933d06360..dca676130b9 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -338,6 +338,8 @@ language_item_table! {
     U128ShloFnLangItem,              "u128_shlo",               u128_shlo_fn;
     I128ShroFnLangItem,              "i128_shro",               i128_shro_fn;
     U128ShroFnLangItem,              "u128_shro",               u128_shro_fn;
+
+    TerminationTraitLangItem,        "termination",             termination;
 }
 
 impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs
index 118b84113a0..64f405e0f24 100644
--- a/src/librustc/session/code_stats.rs
+++ b/src/librustc/session/code_stats.rs
@@ -155,11 +155,19 @@ impl CodeStats {
 
                     // Include field alignment in output only if it caused padding injection
                     if min_offset != offset {
-                        let pad = offset - min_offset;
-                        println!("print-type-size {}padding: {} bytes",
-                                 indent, pad);
-                        println!("print-type-size {}field `.{}`: {} bytes, alignment: {} bytes",
-                                 indent, name, size, align);
+                        if offset > min_offset {
+                            let pad = offset - min_offset;
+                            println!("print-type-size {}padding: {} bytes",
+                                     indent, pad);
+                            println!("print-type-size {}field `.{}`: {} bytes, \
+                                      alignment: {} bytes",
+                                     indent, name, size, align);
+                        } else {
+                            println!("print-type-size {}field `.{}`: {} bytes, \
+                                      offset: {} bytes, \
+                                      alignment: {} bytes",
+                                     indent, name, size, offset, align);
+                        }
                     } else {
                         println!("print-type-size {}field `.{}`: {} bytes",
                                  indent, name, size);
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 0b8666800a5..10fa379924b 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -194,11 +194,12 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::middle::const_val::ConstVal;
-use rustc::middle::lang_items::{ExchangeMallocFnLangItem};
+use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
 use rustc::traits;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, Kind};
 use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
 use rustc::ty::adjustment::CustomCoerceUnsized;
+use rustc::session::config;
 use rustc::mir::{self, Location};
 use rustc::mir::visit::Visitor as MirVisitor;
 use rustc::mir::mono::MonoItem;
@@ -212,6 +213,8 @@ use rustc_data_structures::bitvec::BitVector;
 
 use syntax::attr;
 
+use std::iter;
+
 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
 pub enum MonoItemCollectionMode {
     Eager,
@@ -329,6 +332,8 @@ fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             tcx.hir.local_def_id(node_id)
         });
 
+        debug!("collect_roots: entry_fn = {:?}", entry_fn);
+
         let mut visitor = RootCollector {
             tcx,
             mode,
@@ -951,16 +956,8 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
                 // actually used somewhere. Just declaring them is insufficient.
             }
             hir::ItemFn(..) => {
-                let tcx = self.tcx;
-                let def_id = tcx.hir.local_def_id(item.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));
-                }
+                let def_id = self.tcx.hir.local_def_id(item.id);
+                self.push_if_root(def_id);
             }
         }
     }
@@ -973,16 +970,8 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
         match ii.node {
             hir::ImplItemKind::Method(hir::MethodSig { .. }, _) => {
-                let tcx = self.tcx;
-                let def_id = tcx.hir.local_def_id(ii.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));
-                }
+                let def_id = self.tcx.hir.local_def_id(ii.id);
+                self.push_if_root(def_id);
             }
             _ => { /* Nothing to do here */ }
         }
@@ -1003,6 +992,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_mono_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 = main_ret_ty.no_late_bound_regions().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_mono_item(start_instance));
+    }
 }
 
 fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index b1fef274cba..55c194ae7a5 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -305,6 +305,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
                                             .or_insert_with(make_codegen_unit);
 
+        let mut can_be_internalized = true;
         let (linkage, visibility) = match trans_item.explicit_linkage(tcx) {
             Some(explicit_linkage) => (explicit_linkage, Visibility::Default),
             None => {
@@ -312,7 +313,28 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     MonoItem::Fn(ref instance) => {
                         let visibility = match instance.def {
                             InstanceDef::Item(def_id) => {
-                                if def_id.is_local() {
+                                // The `start_fn` lang item is actually a
+                                // monomorphized instance of a function in the
+                                // standard library, used for the `main`
+                                // function. We don't want to export it so we
+                                // tag it with `Hidden` visibility but this
+                                // symbol is only referenced from the actual
+                                // `main` symbol which we unfortunately don't
+                                // know anything about during
+                                // partitioning/collection. As a result we
+                                // forcibly keep this symbol out of the
+                                // `internalization_candidates` set.
+                                //
+                                // FIXME: eventually we don't want to always
+                                // force this symbol to have hidden
+                                // visibility, it should indeed be a candidate
+                                // for internalization, but we have to
+                                // understand that it's referenced from the
+                                // `main` symbol we'll generate later.
+                                if tcx.lang_items().start_fn() == Some(def_id) {
+                                    can_be_internalized = false;
+                                    Visibility::Hidden
+                                } else if def_id.is_local() {
                                     if tcx.is_exported_symbol(def_id) {
                                         Visibility::Default
                                     } else {
@@ -346,7 +368,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 }
             }
         };
-        if visibility == Visibility::Hidden {
+        if visibility == Visibility::Hidden && can_be_internalized {
             internalization_candidates.insert(trans_item);
         }
 
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 0efe5f9a5cb..680821d6d68 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -44,6 +44,7 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
 use rustc::ty::maps::Providers;
 use rustc::dep_graph::{DepNode, DepConstructor};
+use rustc::ty::subst::Kind;
 use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
 use rustc::util::common::{time, print_time_passes_entry};
 use rustc::session::config::{self, NoDebugInfo};
@@ -79,6 +80,7 @@ use std::str;
 use std::sync::Arc;
 use std::time::{Instant, Duration};
 use std::i32;
+use std::iter;
 use std::sync::mpsc;
 use syntax_pos::Span;
 use syntax_pos::symbol::InternedString;
@@ -540,18 +542,26 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) {
 
     let et = ccx.sess().entry_type.get().unwrap();
     match et {
-        config::EntryMain => create_entry_fn(ccx, span, main_llfn, true),
-        config::EntryStart => create_entry_fn(ccx, span, main_llfn, false),
+        config::EntryMain => create_entry_fn(ccx, span, main_llfn, main_def_id, true),
+        config::EntryStart => create_entry_fn(ccx, span, main_llfn, main_def_id, false),
         config::EntryNone => {}    // Do nothing.
     }
 
-    fn create_entry_fn(ccx: &CrateContext,
+    fn create_entry_fn<'ccx>(ccx: &'ccx CrateContext,
                        sp: Span,
                        rust_main: ValueRef,
+                       rust_main_def_id: DefId,
                        use_start_lang_item: bool) {
-        // Signature of native main(), corresponding to C's `int main(int, char **)`
         let llfty = Type::func(&[Type::c_int(ccx), Type::i8p(ccx).ptr_to()], &Type::c_int(ccx));
 
+        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 = main_ret_ty.no_late_bound_regions().unwrap();
+
         if declare::get_defined_value(ccx, "main").is_some() {
             // FIXME: We should be smart and show a better diagnostic here.
             ccx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times")
@@ -577,8 +587,8 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) {
 
         let (start_fn, args) = if use_start_lang_item {
             let start_def_id = ccx.tcx().require_lang_item(StartFnLangItem);
-            let start_instance = Instance::mono(ccx.tcx(), start_def_id);
-            let start_fn = callee::get_fn(ccx, start_instance);
+            let start_fn = callee::resolve_and_get_fn(ccx, start_def_id, ccx.tcx().mk_substs(
+                iter::once(Kind::from(main_ret_ty))));
             (start_fn, vec![bld.pointercast(rust_main, Type::i8p(ccx).ptr_to()),
                             arg_argc, arg_argv])
         } else {
@@ -587,8 +597,6 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) {
         };
 
         let result = bld.call(start_fn, &args, None);
-
-        // Return rust start function's result from native main()
         bld.ret(bld.intcast(result, Type::c_int(ccx), true));
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ab81d26e771..7a49c3549ab 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -96,14 +96,14 @@ use rustc::middle::region;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
 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::fold::TypeFoldable;
 use rustc::ty::maps::Providers;
 use rustc::ty::util::{Representability, IntTypeExt};
 use errors::{DiagnosticBuilder, DiagnosticId};
 use require_c_abi_if_variadic;
-use session::{CompileIncomplete, Session};
+use session::{CompileIncomplete, config, Session};
 use TypeAndSubsts;
 use lint;
 use util::common::{ErrorReported, indenter};
@@ -115,6 +115,7 @@ use std::collections::hash_map::Entry;
 use std::cmp;
 use std::fmt::Display;
 use std::mem::replace;
+use std::iter;
 use std::ops::{self, Deref};
 use syntax::abi::Abi;
 use syntax::ast;
@@ -1064,6 +1065,30 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     }
     fcx.demand_suptype(span, ret_ty, actual_return_ty);
 
+    if fcx.tcx.sess.features.borrow().termination_trait {
+        // If the termination trait language item is activated, check that the main return type
+        // implements the termination trait.
+        if let Some(term_id) = fcx.tcx.lang_items().termination() {
+            if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() {
+                if id == fn_id {
+                    match fcx.sess().entry_type.get() {
+                        Some(config::EntryMain) => {
+                            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)
 }
 
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 129511ee64c..0b2f59abf4f 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -116,6 +116,7 @@ use syntax::abi::Abi;
 use syntax_pos::Span;
 
 use std::iter;
+
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
 mod diagnostics;
@@ -200,10 +201,22 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 }
                 _ => ()
             }
+
+            let actual = tcx.fn_sig(main_def_id);
+            let expected_return_type = if tcx.lang_items().termination().is_some()
+                && tcx.sess.features.borrow().termination_trait {
+                // we take the return type of the given main function, the real check is done
+                // in `check_fn`
+                actual.output().skip_binder()
+            } else {
+                // standard () main return type
+                tcx.mk_nil()
+            };
+
             let se_ty = tcx.mk_fn_ptr(ty::Binder(
                 tcx.mk_fn_sig(
                     iter::empty(),
-                    tcx.mk_nil(),
+                    expected_return_type,
                     false,
                     hir::Unsafety::Normal,
                     Abi::Rust
@@ -214,7 +227,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 tcx,
                 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
                 se_ty,
-                tcx.mk_fn_ptr(tcx.fn_sig(main_def_id)));
+                tcx.mk_fn_ptr(actual));
         }
         _ => {
             span_bug!(main_span,
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 12e6231136e..171c108e3aa 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -308,6 +308,7 @@
 #![feature(str_char)]
 #![feature(str_internals)]
 #![feature(str_utf16)]
+#![feature(termination_trait)]
 #![feature(test, rustc_private)]
 #![feature(thread_local)]
 #![feature(toowned_clone_into)]
@@ -499,6 +500,11 @@ mod memchr;
 // The runtime entry point and a few unstable public functions used by the
 // compiler
 pub mod rt;
+// The trait to support returning arbitrary types in the main function
+mod termination;
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+pub use self::termination::Termination;
 
 // Include a number of private modules that exist solely to provide
 // the rustdoc documentation for primitive types. Using `include!`
diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs
index 40b24cedcdc..e2c1bba50c4 100644
--- a/src/libstd/rt.rs
+++ b/src/libstd/rt.rs
@@ -26,7 +26,57 @@
 // Reexport some of our utilities which are expected by other crates.
 pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count};
 
-#[cfg(not(test))]
+// To reduce the generated code of the new `lang_start`, this function is doing
+// the real work.
+#[cfg(not(any(test, stage0)))]
+fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe),
+                       argc: isize, argv: *const *const u8) -> isize {
+    use panic;
+    use sys;
+    use sys_common;
+    use sys_common::thread_info;
+    use thread::Thread;
+    #[cfg(not(feature = "backtrace"))]
+    use mem;
+
+    sys::init();
+
+    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())
+        });
+        #[cfg(not(feature = "backtrace"))]
+        let exit_code = panic::catch_unwind(move || main());
+
+        sys_common::cleanup();
+        exit_code.unwrap_or(101) as isize
+    }
+}
+
+#[cfg(not(any(test, stage0)))]
+#[lang = "start"]
+fn lang_start<T: ::termination::Termination + 'static>
+    (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize
+{
+    lang_start_internal(&move || main().report(), argc, argv)
+}
+
+#[cfg(all(not(test), stage0))]
 #[lang = "start"]
 fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize {
     use panic;
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
index b5cf6d7d34f..36cbce2df75 100644
--- a/src/libstd/sys_common/backtrace.rs
+++ b/src/libstd/sys_common/backtrace.rs
@@ -128,7 +128,7 @@ fn filter_frames(frames: &[Frame],
 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
 #[inline(never)]
 pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
-    where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
+    where F: FnOnce() -> T, F: Send, T: Send
 {
     f()
 }
diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs
new file mode 100644
index 00000000000..61137ba4922
--- /dev/null
+++ b/src/libstd/termination.rs
@@ -0,0 +1,86 @@
+// 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;
+#[cfg(target_arch = "wasm32")]
+mod exit {
+    pub const SUCCESS: i32 = 0;
+    pub const FAILURE: i32 = 1;
+}
+#[cfg(not(target_arch = "wasm32"))]
+mod exit {
+    use libc;
+    pub const SUCCESS: i32 = libc::EXIT_SUCCESS;
+    pub const FAILURE: i32 = libc::EXIT_FAILURE;
+}
+
+/// 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(any(stage0, test)), lang = "termination")]
+#[unstable(feature = "termination_trait", issue = "43301")]
+#[rustc_on_unimplemented =
+  "`main` can only return types that implement {Termination}, not `{Self}`"]
+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 = "43301")]
+impl Termination for () {
+    fn report(self) -> i32 { exit::SUCCESS }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+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);
+                exit::FAILURE
+            }
+        }
+    }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+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 = "43301")]
+impl Termination for ! {
+    fn report(self) -> i32 { unreachable!(); }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+impl Termination for bool {
+    fn report(self) -> i32 {
+        if self { exit::SUCCESS } else { exit::FAILURE }
+    }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+impl Termination for i32 {
+    fn report(self) -> i32 {
+        self
+    }
+}
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 1676925989c..7ae360678cd 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -444,6 +444,9 @@ declare_features! (
 
     // Nested `impl Trait`
     (active, nested_impl_trait, "1.24.0", Some(34511)),
+
+    // Termination trait in main (RFC 1937)
+    (active, termination_trait, "1.24.0", Some(43301)),
 );
 
 declare_features! (
diff --git a/src/test/codegen-units/item-collection/cross-crate-closures.rs b/src/test/codegen-units/item-collection/cross-crate-closures.rs
index 2b5ac7e8d80..320be278198 100644
--- a/src/test/codegen-units/item-collection/cross-crate-closures.rs
+++ b/src/test/codegen-units/item-collection/cross-crate-closures.rs
@@ -17,12 +17,14 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 // aux-build:cgu_extern_closures.rs
 extern crate cgu_extern_closures;
 
-//~ TRANS_ITEM fn cross_crate_closures::main[0]
-fn main() {
+//~ TRANS_ITEM fn cross_crate_closures::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
 
     //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0]
     //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0]::{{closure}}[0]
@@ -35,6 +37,8 @@ fn main() {
     // Nothing should be generated for this call, we just link to the instance
     // in the extern crate.
     let _ = cgu_extern_closures::non_inlined_fn(6, 7);
+
+    0
 }
 
 //~ TRANS_ITEM drop-glue i8
diff --git a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs
index eb4f9e8e28e..bcb3b7b1dad 100644
--- a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs
+++ b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs
@@ -12,13 +12,14 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 // aux-build:cgu_generic_function.rs
 extern crate cgu_generic_function;
 
-//~ TRANS_ITEM fn cross_crate_generic_functions::main[0]
-fn main()
-{
+//~ TRANS_ITEM fn cross_crate_generic_functions::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn cgu_generic_function::bar[0]<u32>
     //~ TRANS_ITEM fn cgu_generic_function::foo[0]<u32>
     let _ = cgu_generic_function::foo(1u32);
@@ -29,4 +30,6 @@ fn main()
 
     // This should not introduce a codegen item
     let _ = cgu_generic_function::exported_but_not_generic(3);
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/cross-crate-trait-method.rs b/src/test/codegen-units/item-collection/cross-crate-trait-method.rs
index 195125793be..910ae000848 100644
--- a/src/test/codegen-units/item-collection/cross-crate-trait-method.rs
+++ b/src/test/codegen-units/item-collection/cross-crate-trait-method.rs
@@ -12,15 +12,16 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 // aux-build:cgu_export_trait_method.rs
 extern crate cgu_export_trait_method;
 
 use cgu_export_trait_method::Trait;
 
-//~ TRANS_ITEM fn cross_crate_trait_method::main[0]
-fn main()
-{
+//~ TRANS_ITEM fn cross_crate_trait_method::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     // The object code of these methods is contained in the external crate, so
     // calling them should *not* introduce codegen items in the current crate.
     let _: (u32, u32) = Trait::without_default_impl(0);
@@ -55,4 +56,6 @@ fn main()
     let _: (char, char) = Trait::without_default_impl_generic('c');
     //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0]<bool>
     let _: (char, bool) = Trait::without_default_impl_generic(false);
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
index b8033b88fb7..52af8165032 100644
--- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -12,6 +12,8 @@
 // compile-flags:-Zprint-trans-items=eager
 // compile-flags:-Zinline-in-all-cgus
 
+#![feature(start)]
+
 //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic0[Internal]
 struct StructWithDtor(u32);
 
@@ -20,13 +22,16 @@ impl Drop for StructWithDtor {
     fn drop(&mut self) {}
 }
 
-//~ TRANS_ITEM fn drop_in_place_intrinsic::main[0]
-fn main() {
+//~ TRANS_ITEM fn drop_in_place_intrinsic::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
 
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic0[Internal]
     let x = [StructWithDtor(0), StructWithDtor(1)];
 
     drop_slice_in_place(&x);
+
+    0
 }
 
 //~ TRANS_ITEM fn drop_in_place_intrinsic::drop_slice_in_place[0]
diff --git a/src/test/codegen-units/item-collection/function-as-argument.rs b/src/test/codegen-units/item-collection/function-as-argument.rs
index c3d46ff5314..65707c1aa4d 100644
--- a/src/test/codegen-units/item-collection/function-as-argument.rs
+++ b/src/test/codegen-units/item-collection/function-as-argument.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 fn take_fn_once<T1, T2, F: FnOnce(T1, T2)>(f: F, x: T1, y: T2) {
     (f)(x, y)
@@ -23,8 +24,9 @@ fn take_fn_pointer<T1, T2>(f: fn(T1, T2), x: T1, y: T2) {
     (f)(x, y)
 }
 
-//~ TRANS_ITEM fn function_as_argument::main[0]
-fn main() {
+//~ TRANS_ITEM fn function_as_argument::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
 
     //~ TRANS_ITEM fn function_as_argument::take_fn_once[0]<u32, &str, fn(u32, &str)>
     //~ TRANS_ITEM fn function_as_argument::function[0]<u32, &str>
@@ -43,4 +45,6 @@ fn main() {
     //~ TRANS_ITEM fn function_as_argument::take_fn_pointer[0]<f32, i64>
     //~ TRANS_ITEM fn function_as_argument::function[0]<f32, i64>
     take_fn_pointer(function, 0f32, 0i64);
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs
index 65936d12e31..d3d9aa3aefc 100644
--- a/src/test/codegen-units/item-collection/generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs
@@ -13,6 +13,7 @@
 // compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
+#![feature(start)]
 
 struct StructWithDrop<T1, T2> {
     x: T1,
@@ -53,8 +54,9 @@ impl Drop for NonGenericWithDrop {
     fn drop(&mut self) {}
 }
 
-//~ TRANS_ITEM fn generic_drop_glue::main[0]
-fn main() {
+//~ TRANS_ITEM fn generic_drop_glue::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<i8, char>
     let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
@@ -94,4 +96,6 @@ fn main() {
         EnumNoDrop::A(x) => x,
         EnumNoDrop::B(x) => x as f64
     };
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/generic-functions.rs b/src/test/codegen-units/item-collection/generic-functions.rs
index afe6ffc8bfe..8efe4b2762a 100644
--- a/src/test/codegen-units/item-collection/generic-functions.rs
+++ b/src/test/codegen-units/item-collection/generic-functions.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 fn foo1<T1>(a: T1) -> (T1, u32) {
     (a, 1)
@@ -31,8 +32,9 @@ pub fn lifetime_only<'a>(a: &'a u32) -> &'a u32 {
     a
 }
 
-//~ TRANS_ITEM fn generic_functions::main[0]
-fn main() {
+//~ TRANS_ITEM fn generic_functions::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn generic_functions::foo1[0]<i32>
     let _ = foo1(2i32);
     //~ TRANS_ITEM fn generic_functions::foo1[0]<i64>
@@ -59,4 +61,6 @@ fn main() {
     let _ = foo3(0i16, "a", 2usize);
     //~ TRANS_ITEM fn generic_functions::foo3[0]<char, (), ()>
     let _ = foo3('v', (), ());
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/generic-impl.rs b/src/test/codegen-units/item-collection/generic-impl.rs
index 14316a55732..d1ee8ee624c 100644
--- a/src/test/codegen-units/item-collection/generic-impl.rs
+++ b/src/test/codegen-units/item-collection/generic-impl.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 struct Struct<T> {
     x: T,
@@ -50,9 +51,9 @@ impl<'a> LifeTimeOnly<'a> {
     pub fn non_instantiated<T>(&self) {}
 }
 
-
-//~ TRANS_ITEM fn generic_impl::main[0]
-fn main() {
+//~ TRANS_ITEM fn generic_impl::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<i32>
     //~ TRANS_ITEM fn generic_impl::id[0]<i32>
     //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0]<i32, i16>
@@ -76,4 +77,6 @@ fn main() {
     //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<generic_impl::Struct[0]<&str>>
     //~ TRANS_ITEM fn generic_impl::id[0]<generic_impl::Struct[0]<&str>>
     let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str"));
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs b/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
index c43c254f339..c07d26c3f8d 100644
--- a/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
+++ b/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 trait SomeTrait {
     fn foo(&self);
@@ -28,7 +29,10 @@ pub fn generic_function<T>(x: T) -> (T, i32) {
     (x, 0)
 }
 
-//~ TRANS_ITEM fn impl_in_non_instantiated_generic::main[0]
-fn main() {
+//~ TRANS_ITEM fn impl_in_non_instantiated_generic::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     0i64.foo();
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
index e32366d15c3..2e1138ef128 100644
--- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -13,6 +13,7 @@
 // compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
+#![feature(start)]
 
 trait Trait {
     fn foo(&self) -> u32;
@@ -28,8 +29,9 @@ impl<T> Trait for Struct<T> {
     fn bar(&self) {}
 }
 
-//~ TRANS_ITEM fn instantiation_through_vtable::main[0]
-fn main() {
+//~ TRANS_ITEM fn instantiation_through_vtable::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let s1 = Struct { _a: 0u32 };
 
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable0[Internal]
@@ -42,4 +44,6 @@ fn main() {
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u64>
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u64>
     let _ = &s1 as &Trait;
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/items-within-generic-items.rs b/src/test/codegen-units/item-collection/items-within-generic-items.rs
index 75d842d3c0b..04b54de3ce2 100644
--- a/src/test/codegen-units/item-collection/items-within-generic-items.rs
+++ b/src/test/codegen-units/item-collection/items-within-generic-items.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 fn generic_fn<T>(a: T) -> (T, i32) {
     //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[0]
@@ -31,12 +32,15 @@ fn generic_fn<T>(a: T) -> (T, i32) {
     return (a, x + nested_fn(0));
 }
 
-//~ TRANS_ITEM fn items_within_generic_items::main[0]
-fn main() {
+//~ TRANS_ITEM fn items_within_generic_items::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]<i64>
     let _ = generic_fn(0i64);
     //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]<u16>
     let _ = generic_fn(0u16);
     //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]<i8>
     let _ = generic_fn(0i8);
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/non-generic-closures.rs b/src/test/codegen-units/item-collection/non-generic-closures.rs
index 278e9189dd6..f0121d56cec 100644
--- a/src/test/codegen-units/item-collection/non-generic-closures.rs
+++ b/src/test/codegen-units/item-collection/non-generic-closures.rs
@@ -17,6 +17,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 //~ TRANS_ITEM fn non_generic_closures::temporary[0]
 fn temporary() {
@@ -52,12 +53,15 @@ fn assigned_to_variable_executed_directly() {
     f(4);
 }
 
-//~ TRANS_ITEM fn non_generic_closures::main[0]
-fn main() {
+//~ TRANS_ITEM fn non_generic_closures::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     temporary();
     assigned_to_variable_but_not_executed();
     assigned_to_variable_executed_directly();
     assigned_to_variable_executed_indirectly();
+
+    0
 }
 
 //~ TRANS_ITEM fn non_generic_closures::run_closure[0]
diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
index 5765f230e8b..bf084aa96ea 100644
--- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
@@ -13,6 +13,7 @@
 // compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
+#![feature(start)]
 
 //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue0[Internal]
 struct StructWithDrop {
@@ -42,8 +43,9 @@ enum EnumNoDrop {
     A(i32)
 }
 
-//~ TRANS_ITEM fn non_generic_drop_glue::main[0]
-fn main() {
+//~ TRANS_ITEM fn non_generic_drop_glue::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _ = StructWithDrop { x: 0 }.x;
     let _ = StructNoDrop { x: 0 }.x;
     let _ = match EnumWithDrop::A(0) {
@@ -52,4 +54,6 @@ fn main() {
     let _ = match EnumNoDrop::A(0) {
         EnumNoDrop::A(x) => x
     };
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/non-generic-functions.rs b/src/test/codegen-units/item-collection/non-generic-functions.rs
index 26f9eb11876..8c487db5c96 100644
--- a/src/test/codegen-units/item-collection/non-generic-functions.rs
+++ b/src/test/codegen-units/item-collection/non-generic-functions.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 //~ TRANS_ITEM fn non_generic_functions::foo[0]
 fn foo() {
@@ -69,11 +70,14 @@ impl Struct {
     }
 }
 
-//~ TRANS_ITEM fn non_generic_functions::main[0]
-fn main() {
+//~ TRANS_ITEM fn non_generic_functions::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     foo();
     bar();
     Struct::foo();
     let x = Struct { _x: 0 };
     x.bar();
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/static-init.rs b/src/test/codegen-units/item-collection/static-init.rs
index 3c9dcf32e0c..5ff7c3480b1 100644
--- a/src/test/codegen-units/item-collection/static-init.rs
+++ b/src/test/codegen-units/item-collection/static-init.rs
@@ -9,6 +9,9 @@
 // except according to those terms.
 
 // compile-flags:-Zprint-trans-items=eager
+// ignore-tidy-linelength
+
+#![feature(start)]
 
 pub static FN : fn() = foo::<i32>;
 
@@ -17,6 +20,9 @@ pub fn foo<T>() { }
 //~ TRANS_ITEM fn static_init::foo[0]<i32>
 //~ TRANS_ITEM static static_init::FN[0]
 
-fn main() { }
+//~ TRANS_ITEM fn static_init::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+    0
+}
 
-//~ TRANS_ITEM fn static_init::main[0]
diff --git a/src/test/codegen-units/item-collection/statics-and-consts.rs b/src/test/codegen-units/item-collection/statics-and-consts.rs
index 89bc620b7c5..11df1da3a78 100644
--- a/src/test/codegen-units/item-collection/statics-and-consts.rs
+++ b/src/test/codegen-units/item-collection/statics-and-consts.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 static STATIC1: i64 = {
     const STATIC1_CONST1: i64 = 2;
@@ -47,9 +48,13 @@ fn foo() {
     };
 }
 
-fn main() {
+//~ TRANS_ITEM fn statics_and_consts::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     foo();
     let _ = STATIC1;
+
+    0
 }
 
 //~ TRANS_ITEM static statics_and_consts::STATIC1[0]
@@ -58,5 +63,3 @@ fn main() {
 //~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[0]
 //~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[1]
 //~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[2]
-
-//~ TRANS_ITEM fn statics_and_consts::main[0]
diff --git a/src/test/codegen-units/item-collection/trait-implementations.rs b/src/test/codegen-units/item-collection/trait-implementations.rs
index e8a7d8f25b2..8eb33dd647f 100644
--- a/src/test/codegen-units/item-collection/trait-implementations.rs
+++ b/src/test/codegen-units/item-collection/trait-implementations.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 pub trait SomeTrait {
     fn foo(&self);
@@ -55,8 +56,9 @@ impl<T> SomeGenericTrait<T> for f32 {
     fn bar<T2>(&self, _: T, _: T2) {}
 }
 
-//~ TRANS_ITEM fn trait_implementations::main[0]
-fn main() {
+//~ TRANS_ITEM fn trait_implementations::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
    //~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::bar[0]<char>
    0i32.bar('x');
 
@@ -77,4 +79,6 @@ fn main() {
 
    //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str>
    0f32.bar("&str", "&str");
+
+   0
 }
diff --git a/src/test/codegen-units/item-collection/trait-method-as-argument.rs b/src/test/codegen-units/item-collection/trait-method-as-argument.rs
index 21c9c254e51..10b21630308 100644
--- a/src/test/codegen-units/item-collection/trait-method-as-argument.rs
+++ b/src/test/codegen-units/item-collection/trait-method-as-argument.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 trait Trait : Sized {
     fn foo(self) -> Self { self }
@@ -36,8 +37,9 @@ fn take_foo_mut<T, F: FnMut(T) -> T>(mut f: F, arg: T) -> T {
     (f)(arg)
 }
 
-//~ TRANS_ITEM fn trait_method_as_argument::main[0]
-fn main() {
+//~ TRANS_ITEM fn trait_method_as_argument::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0]<u32, fn(u32) -> u32>
     //~ TRANS_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0]
     //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0]<fn(u32) -> u32, (u32)>
@@ -63,4 +65,6 @@ fn main() {
     //~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0]<char, fn(char) -> char>
     //~ TRANS_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0]<fn(u32) -> u32, (u32)>
     take_foo_mut(Trait::foo, 'c');
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/trait-method-default-impl.rs b/src/test/codegen-units/item-collection/trait-method-default-impl.rs
index 5b24a219f35..a6ae3765b2e 100644
--- a/src/test/codegen-units/item-collection/trait-method-default-impl.rs
+++ b/src/test/codegen-units/item-collection/trait-method-default-impl.rs
@@ -12,6 +12,7 @@
 // compile-flags:-Zprint-trans-items=eager
 
 #![deny(dead_code)]
+#![feature(start)]
 
 trait SomeTrait {
     fn foo(&self) { }
@@ -46,8 +47,9 @@ impl<T1> SomeGenericTrait<T1> for u32 {
     // since nothing is monomorphic here, nothing should be generated unless used somewhere.
 }
 
-//~ TRANS_ITEM fn trait_method_default_impl::main[0]
-fn main() {
+//~ TRANS_ITEM fn trait_method_default_impl::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0]<i8, char>
     let _ = 1i8.bar('c');
 
@@ -65,4 +67,6 @@ fn main() {
 
     //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0]<u32, i16, ()>
     0u32.bar(0i16, ());
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
index be560690e51..57cd10187a2 100644
--- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
@@ -13,6 +13,7 @@
 // compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
+#![feature(start)]
 
 //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue0[Internal]
 struct Root(Intermediate);
@@ -34,9 +35,9 @@ impl<T> Drop for LeafGen<T> {
     fn drop(&mut self) {}
 }
 
-//~ TRANS_ITEM fn transitive_drop_glue::main[0]
-fn main() {
-
+//~ TRANS_ITEM fn transitive_drop_glue::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _ = Root(Intermediate(Leaf));
 
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue0[Internal]
@@ -50,4 +51,6 @@ fn main() {
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue0[Internal]
     //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<i16>
     let _ = RootGen(IntermediateGen(LeafGen(0i16)));
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
index ad1475a73f7..a5f2409b8ae 100644
--- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
@@ -13,6 +13,7 @@
 // compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
+#![feature(start)]
 
 //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue0[Internal]
 struct Dropped;
@@ -22,12 +23,15 @@ impl Drop for Dropped {
     fn drop(&mut self) {}
 }
 
-//~ TRANS_ITEM fn tuple_drop_glue::main[0]
-fn main() {
+//~ TRANS_ITEM fn tuple_drop_glue::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue0[Internal]
     let x = (0u32, Dropped);
 
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue0[Internal]
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue0[Internal]
     let x = (0i16, (Dropped, true));
+
+    0
 }
diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs
index d7e457cde8a..87d2581e1f8 100644
--- a/src/test/codegen-units/item-collection/unsizing.rs
+++ b/src/test/codegen-units/item-collection/unsizing.rs
@@ -15,6 +15,7 @@
 #![deny(dead_code)]
 #![feature(coerce_unsized)]
 #![feature(unsize)]
+#![feature(start)]
 
 use std::marker::Unsize;
 use std::ops::CoerceUnsized;
@@ -53,9 +54,9 @@ struct Wrapper<T: ?Sized>(*const T);
 
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
 
-//~ TRANS_ITEM fn unsizing::main[0]
-fn main()
-{
+//~ TRANS_ITEM fn unsizing::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     // simple case
     let bool_sized = &true;
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<bool> @@ unsizing0[Internal]
@@ -83,4 +84,6 @@ fn main()
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0]
     let _wrapper_sized = wrapper_sized as Wrapper<Trait>;
+
+    0
 }
diff --git a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs
index 1ea5aafd401..aa01289de59 100644
--- a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs
+++ b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs
@@ -19,6 +19,7 @@
 // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/methods-are-with-self-type
 
 #![allow(dead_code)]
+#![feature(start)]
 
 struct SomeType;
 
@@ -63,9 +64,9 @@ mod type2 {
     pub struct Struct;
 }
 
-//~ TRANS_ITEM fn methods_are_with_self_type::main[0]
-fn main()
-{
+//~ TRANS_ITEM fn methods_are_with_self_type::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::method[0]<u32, u64> @@ methods_are_with_self_type.volatile[WeakODR]
     SomeGenericType(0u32, 0u64).method();
     //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::associated_fn[0]<char, &str> @@ methods_are_with_self_type.volatile[WeakODR]
@@ -80,6 +81,8 @@ fn main()
     type1::Struct.default();
     //~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0]<methods_are_with_self_type::type2[0]::Struct[0]> @@ methods_are_with_self_type-type2.volatile[WeakODR]
     type2::Struct.default();
+
+    0
 }
 
 //~ TRANS_ITEM drop-glue i8
diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs
index 302f9312b57..d0acddda637 100644
--- a/src/test/codegen-units/partitioning/vtable-through-const.rs
+++ b/src/test/codegen-units/partitioning/vtable-through-const.rs
@@ -18,6 +18,8 @@
 // This test case makes sure, that references made through constants are
 // recorded properly in the InliningMap.
 
+#![feature(start)]
+
 mod mod1 {
     pub trait Trait1 {
         fn do_something(&self) {}
@@ -38,7 +40,7 @@ mod mod1 {
 
     fn id<T>(x: T) -> T { x }
 
-    // These are referenced, so they produce trans-items (see main())
+    // These are referenced, so they produce trans-items (see start())
     pub const TRAIT1_REF: &'static Trait1 = &0u32 as &Trait1;
     pub const TRAIT1_GEN_REF: &'static Trait1Gen<u8> = &0u32 as &Trait1Gen<u8>;
     pub const ID_CHAR: fn(char) -> char = id::<char>;
@@ -68,8 +70,9 @@ mod mod1 {
     pub const ID_I64: fn(i64) -> i64 = id::<i64>;
 }
 
-//~ TRANS_ITEM fn vtable_through_const::main[0] @@ vtable_through_const[Internal]
-fn main() {
+//~ TRANS_ITEM fn vtable_through_const::start[0]
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ vtable_through_const[Internal]
 
     // Since Trait1::do_something() is instantiated via its default implementation,
@@ -90,4 +93,6 @@ fn main() {
 
     //~ TRANS_ITEM fn vtable_through_const::mod1[0]::id[0]<char> @@ vtable_through_const-mod1.volatile[External]
     mod1::ID_CHAR('x');
+
+    0
 }
diff --git a/src/test/compile-fail/feature-gate-termination_trait.rs b/src/test/compile-fail/feature-gate-termination_trait.rs
new file mode 100644
index 00000000000..5a56445b64e
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-termination_trait.rs
@@ -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.
+
+fn main() -> i32 { //~ ERROR main function has wrong type [E0580]
+    0
+}
diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs
index 9d74d1a9049..a63162cf73d 100644
--- a/src/test/compile-fail/main-wrong-type-2.rs
+++ b/src/test/compile-fail/main-wrong-type-2.rs
@@ -7,8 +7,9 @@
 // <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() -> char {
-//~^ ERROR: main function has wrong type [E0580]
+//~^ ERROR: the trait bound `char: std::Termination` is not satisfied
     ' '
 }
diff --git a/src/test/compile-fail/termination-trait-not-satisfied.rs b/src/test/compile-fail/termination-trait-not-satisfied.rs
new file mode 100644
index 00000000000..788c38c55be
--- /dev/null
+++ b/src/test/compile-fail/termination-trait-not-satisfied.rs
@@ -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)]
+
+struct ReturnType {}
+
+fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied
+    ReturnType {}
+}
diff --git a/src/test/run-make/sepcomp-inlining/foo.rs b/src/test/run-make/sepcomp-inlining/foo.rs
index 20fd18b8295..5b62c1b0626 100644
--- a/src/test/run-make/sepcomp-inlining/foo.rs
+++ b/src/test/run-make/sepcomp-inlining/foo.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(start)]
+
 #[inline]
 fn inlined() -> u32 {
     1234
@@ -29,7 +31,10 @@ mod b {
     }
 }
 
-fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     a::f();
     b::f();
+
+    0
 }
diff --git a/src/test/compile-fail/E0580.rs b/src/test/run-pass/termination-trait-for-empty.rs
index a2ef7da78a8..5e534da0128 100644
--- a/src/test/compile-fail/E0580.rs
+++ b/src/test/run-pass/termination-trait-for-empty.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,4 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn main() -> i32 { 0 } //~ ERROR E0580
+#![feature(termination_trait)]
+
+fn main() {}
diff --git a/src/test/run-pass/termination-trait-for-i32.rs b/src/test/run-pass/termination-trait-for-i32.rs
new file mode 100644
index 00000000000..fa7cb023b44
--- /dev/null
+++ b/src/test/run-pass/termination-trait-for-i32.rs
@@ -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
+}
diff --git a/src/test/run-pass/termination-trait-for-result.rs b/src/test/run-pass/termination-trait-for-result.rs
new file mode 100644
index 00000000000..751db0fb500
--- /dev/null
+++ b/src/test/run-pass/termination-trait-for-result.rs
@@ -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(())
+}
diff --git a/src/test/ui/print_type_sizes/anonymous.rs b/src/test/ui/print_type_sizes/anonymous.rs
index cf0bedee2ab..56c05f566c9 100644
--- a/src/test/ui/print_type_sizes/anonymous.rs
+++ b/src/test/ui/print_type_sizes/anonymous.rs
@@ -15,7 +15,10 @@
 // that one cannot control the sizes of these types with the same sort
 // of enum-variant manipulation tricks.
 
-pub fn main() {
+#![feature(start)]
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _byte: u8 = 0;
     let _word: usize = 0;
     let _tuple: (u8, usize)= (0, 0);
@@ -25,4 +28,6 @@ pub fn main() {
 
     fn id(x: u8) -> u8 { x };
     fn bye(_: u8) -> ! { loop { } }
+
+    0
 }
diff --git a/src/test/ui/print_type_sizes/generics.rs b/src/test/ui/print_type_sizes/generics.rs
index 7bc4822359e..d0e5bd1d92a 100644
--- a/src/test/ui/print_type_sizes/generics.rs
+++ b/src/test/ui/print_type_sizes/generics.rs
@@ -15,6 +15,8 @@
 // monomorphized, in the MIR of the original function in which they
 // occur, to have their size reported.
 
+#![feature(start)]
+
 // In an ad-hoc attempt to avoid the injection of unwinding code
 // (which clutters the output of `-Z print-type-sizes` with types from
 // `unwind::libunwind`):
@@ -66,9 +68,11 @@ pub fn f1<T:Copy>(x: T) {
         Pair::new(FiftyBytes::new(), FiftyBytes::new());
 }
 
-pub fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _b: Pair<u8> = Pair::new(0, 0);
     let _s: Pair<SevenBytes> = Pair::new(SevenBytes::new(), SevenBytes::new());
     let _z: ZeroSized = ZeroSized;
     f1::<SevenBytes>(SevenBytes::new());
+    0
 }
diff --git a/src/test/ui/print_type_sizes/multiple_types.rs b/src/test/ui/print_type_sizes/multiple_types.rs
index a9f29449015..a50b28f3c49 100644
--- a/src/test/ui/print_type_sizes/multiple_types.rs
+++ b/src/test/ui/print_type_sizes/multiple_types.rs
@@ -14,6 +14,8 @@
 // This file illustrates that when multiple structural types occur in
 // a function, every one of them is included in the output.
 
+#![feature(start)]
+
 pub struct SevenBytes([u8;  7]);
 pub struct FiftyBytes([u8; 50]);
 
@@ -22,8 +24,10 @@ pub enum Enum {
     Large(FiftyBytes),
 }
 
-pub fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _e: Enum;
     let _f: FiftyBytes;
     let _s: SevenBytes;
+    0
 }
diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs
index 08b58704022..7f234e243e9 100644
--- a/src/test/ui/print_type_sizes/niche-filling.rs
+++ b/src/test/ui/print_type_sizes/niche-filling.rs
@@ -21,6 +21,7 @@
 // aligned (while on most it is 8-byte aligned) and so the resulting
 // padding and overall computed sizes can be quite different.
 
+#![feature(start)]
 #![feature(nonzero)]
 #![allow(dead_code)]
 
@@ -76,7 +77,8 @@ pub enum Enum4<A, B, C, D> {
     Four(D)
 }
 
-pub fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _x: MyOption<NonZero<u32>> = Default::default();
     let _y: EmbeddedDiscr = Default::default();
     let _z: MyOption<IndirectNonZero<u32>> = Default::default();
@@ -87,4 +89,5 @@ pub fn main() {
     let _e: Enum4<(), char, (), ()> = Enum4::One(());
     let _f: Enum4<(), (), bool, ()> = Enum4::One(());
     let _g: Enum4<(), (), (), MyOption<u8>> = Enum4::One(());
+    0
 }
diff --git a/src/test/ui/print_type_sizes/no_duplicates.rs b/src/test/ui/print_type_sizes/no_duplicates.rs
index 40c41aae910..d9b90260364 100644
--- a/src/test/ui/print_type_sizes/no_duplicates.rs
+++ b/src/test/ui/print_type_sizes/no_duplicates.rs
@@ -15,12 +15,16 @@
 // (even if multiple functions), it is only printed once in the
 // print-type-sizes output.
 
+#![feature(start)]
+
 pub struct SevenBytes([u8; 7]);
 
 pub fn f1() {
     let _s: SevenBytes = SevenBytes([0; 7]);
 }
 
-pub fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _s: SevenBytes = SevenBytes([0; 7]);
+    0
 }
diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs
index 1ee6395ac6c..a4288f67899 100644
--- a/src/test/ui/print_type_sizes/packed.rs
+++ b/src/test/ui/print_type_sizes/packed.rs
@@ -20,6 +20,7 @@
 // padding and overall computed sizes can be quite different.
 
 #![allow(dead_code)]
+#![feature(start)]
 
 #[derive(Default)]
 #[repr(packed)]
@@ -42,7 +43,9 @@ struct Padded {
     d: u8,
 }
 
-pub fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _c: Packed = Default::default();
     let _d: Padded = Default::default();
+    0
 }
diff --git a/src/test/ui/print_type_sizes/padding.rs b/src/test/ui/print_type_sizes/padding.rs
index b3cd2132343..b4661efdd27 100644
--- a/src/test/ui/print_type_sizes/padding.rs
+++ b/src/test/ui/print_type_sizes/padding.rs
@@ -19,6 +19,7 @@
 // aligned (while on most it is 8-byte aligned) and so the resulting
 // padding and overall computed sizes can be quite different.
 
+#![feature(start)]
 #![allow(dead_code)]
 
 struct S {
@@ -37,4 +38,7 @@ enum E2 {
     B(S),
 }
 
-fn main() { }
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+    0
+}
diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs
index 1bf76da8115..108b8dbba01 100644
--- a/src/test/ui/print_type_sizes/repr-align.rs
+++ b/src/test/ui/print_type_sizes/repr-align.rs
@@ -20,6 +20,7 @@
 // padding and overall computed sizes can be quite different.
 #![feature(attr_literals)]
 #![feature(repr_align)]
+#![feature(start)]
 #![allow(dead_code)]
 
 #[repr(align(16))]
@@ -39,6 +40,8 @@ struct S {
     d: i8,
 }
 
-fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _s: S = Default::default();
+    0
 }
diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs
index fae6cd4009c..4d0396903e5 100644
--- a/src/test/ui/print_type_sizes/uninhabited.rs
+++ b/src/test/ui/print_type_sizes/uninhabited.rs
@@ -12,8 +12,11 @@
 // must-compile-successfully
 
 #![feature(never_type)]
+#![feature(start)]
 
-pub fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _x: Option<!> = None;
     let _y: Result<u32, !> = Ok(42);
+    0
 }
diff --git a/src/test/ui/print_type_sizes/variants.rs b/src/test/ui/print_type_sizes/variants.rs
index 2725bb09b4b..e4d54162e73 100644
--- a/src/test/ui/print_type_sizes/variants.rs
+++ b/src/test/ui/print_type_sizes/variants.rs
@@ -19,6 +19,8 @@
 // 2. For an enum, the print-type-sizes output will also include the
 //    size of each variant.
 
+#![feature(start)]
+
 pub struct SevenBytes([u8;  7]);
 pub struct FiftyBytes([u8; 50]);
 
@@ -27,6 +29,8 @@ pub enum Enum {
     Large(FiftyBytes),
 }
 
-pub fn main() {
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
     let _e: Enum;
+    0
 }