From 56c90dc31e86bbaf486826a21a33d7c56e8f742f Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 14 Dec 2024 09:13:12 +0100
Subject: [PATCH] remove support for the #[start] attribute

---
 compiler/rustc_ast/src/entry.rs               |  10 +-
 compiler/rustc_ast_passes/src/feature_gate.rs |  12 --
 .../rustc_builtin_macros/src/test_harness.rs  |   7 +-
 .../rustc_codegen_cranelift/src/main_shim.rs  |  21 ++--
 .../build_system/src/test.rs                  |  26 ----
 .../example/alloc_example.rs                  |   7 +-
 .../example/mini_core_hello_world.rs          |   2 +-
 .../rustc_codegen_gcc/example/mod_bench.rs    |  36 ------
 compiler/rustc_codegen_gcc/src/context.rs     |   1 -
 .../rustc_codegen_gcc/tests/run/abort1.rs     |   7 +-
 .../rustc_codegen_gcc/tests/run/abort2.rs     |   7 +-
 compiler/rustc_codegen_gcc/tests/run/array.rs |   7 +-
 .../rustc_codegen_gcc/tests/run/assign.rs     |   7 +-
 .../rustc_codegen_gcc/tests/run/closure.rs    |   7 +-
 .../rustc_codegen_gcc/tests/run/condition.rs  |   7 +-
 .../rustc_codegen_gcc/tests/run/empty_main.rs |   7 +-
 compiler/rustc_codegen_gcc/tests/run/exit.rs  |   7 +-
 .../rustc_codegen_gcc/tests/run/exit_code.rs  |   7 +-
 .../rustc_codegen_gcc/tests/run/fun_ptr.rs    |   7 +-
 .../rustc_codegen_gcc/tests/run/mut_ref.rs    |   7 +-
 .../rustc_codegen_gcc/tests/run/operations.rs |   7 +-
 .../rustc_codegen_gcc/tests/run/ptr_cast.rs   |   7 +-
 .../tests/run/return-tuple.rs                 |   7 +-
 compiler/rustc_codegen_gcc/tests/run/slice.rs |   7 +-
 .../rustc_codegen_gcc/tests/run/static.rs     |   7 +-
 .../rustc_codegen_gcc/tests/run/structs.rs    |   7 +-
 compiler/rustc_codegen_gcc/tests/run/tuple.rs |   7 +-
 compiler/rustc_codegen_llvm/src/context.rs    |   1 -
 compiler/rustc_codegen_ssa/messages.ftl       |   2 +-
 compiler/rustc_codegen_ssa/src/base.rs        |  11 +-
 .../src/error_codes/E0132.md                  |  33 +----
 .../src/error_codes/E0138.md                  |  26 +---
 .../src/error_codes/E0647.md                  |  14 +--
 compiler/rustc_error_codes/src/lib.rs         |   4 +
 compiler/rustc_feature/src/builtin_attrs.rs   |   1 -
 compiler/rustc_feature/src/removed.rs         |   5 +-
 compiler/rustc_feature/src/unstable.rs        |   2 -
 compiler/rustc_hir/src/lang_items.rs          |   4 +
 compiler/rustc_hir_analysis/messages.ftl      |  15 ---
 .../rustc_hir_analysis/src/check/entry.rs     |  83 +------------
 compiler/rustc_hir_analysis/src/errors.rs     |  42 -------
 compiler/rustc_middle/src/traits/mod.rs       |   3 -
 compiler/rustc_passes/messages.ftl            |   5 -
 compiler/rustc_passes/src/check_attr.rs       |   2 -
 compiler/rustc_passes/src/entry.rs            |  27 +---
 compiler/rustc_passes/src/errors.rs           |  11 --
 compiler/rustc_session/src/config.rs          |   1 -
 compiler/rustc_trait_selection/messages.ftl   |   3 -
 .../src/error_reporting/infer/mod.rs          |   6 -
 .../src/error_reporting/traits/suggestions.rs |   1 -
 compiler/rustc_trait_selection/src/errors.rs  |   7 --
 src/doc/rustc/src/platform-support/nto-qnx.md |   2 +-
 .../src/language-features/lang-items.md       |   9 +-
 .../src/language-features/start.md            |  59 ---------
 .../tests/ui/borrow_as_ptr_no_std.fixed       |  13 +-
 .../clippy/tests/ui/borrow_as_ptr_no_std.rs   |  13 +-
 .../tests/ui/borrow_as_ptr_no_std.stderr      |   4 +-
 .../clippy/tests/ui/box_default_no_std.rs     |  13 +-
 src/tools/clippy/tests/ui/crashes/ice-7410.rs |  13 +-
 .../no_std_main_recursion.rs                  |  32 -----
 .../ui/crate_level_checks/no_std_swap.fixed   |   3 +-
 .../ui/crate_level_checks/no_std_swap.rs      |   3 +-
 .../ui/crate_level_checks/no_std_swap.stderr  |   2 +-
 src/tools/clippy/tests/ui/def_id_nocore.rs    |   2 +-
 .../clippy/tests/ui/empty_loop_no_std.rs      |  20 +--
 .../clippy/tests/ui/empty_loop_no_std.stderr  |  12 +-
 .../ui/floating_point_arithmetic_nostd.rs     |  13 +-
 .../ui/missing_const_for_fn/cant_be_const.rs  |  10 --
 .../tests/ui/missing_spin_loop_no_std.fixed   |  13 +-
 .../tests/ui/missing_spin_loop_no_std.rs      |  13 +-
 .../tests/ui/missing_spin_loop_no_std.stderr  |   2 +-
 .../tests/ui/result_unit_error_no_std.rs      |   7 +-
 .../tests/ui/result_unit_error_no_std.stderr  |   2 +-
 .../clippy/tests/ui/zero_ptr_no_std.fixed     |  13 +-
 src/tools/clippy/tests/ui/zero_ptr_no_std.rs  |  13 +-
 .../clippy/tests/ui/zero_ptr_no_std.stderr    |   6 +-
 src/tools/miri/src/bin/miri.rs                |  12 +-
 src/tools/miri/src/eval.rs                    |  20 +--
 src/tools/miri/src/lib.rs                     |   4 +-
 .../test-cargo-miri/no-std-smoke/src/main.rs  |   5 +-
 .../fail/alloc/alloc_error_handler_custom.rs  |   7 +-
 .../alloc/alloc_error_handler_custom.stderr   |   2 +-
 .../fail/alloc/alloc_error_handler_no_std.rs  |   7 +-
 .../alloc/alloc_error_handler_no_std.stderr   |   2 +-
 .../tests/fail/alloc/no_global_allocator.rs   |   6 +-
 .../fail/alloc/no_global_allocator.stderr     |   2 +-
 src/tools/miri/tests/fail/panic/no_std.rs     |   7 +-
 src/tools/miri/tests/fail/panic/no_std.stderr |   2 +-
 .../miri/tests/pass/alloc-access-tracking.rs  |   6 +-
 .../tests/pass/alloc-access-tracking.stderr   |   8 +-
 src/tools/miri/tests/pass/miri-alloc.rs       |   6 +-
 src/tools/miri/tests/pass/miri_start.stdout   |   1 -
 src/tools/miri/tests/pass/no_std.rs           |  19 ---
 .../{miri_start.rs => no_std_miri_start.rs}   |   4 +-
 ...no_std.stdout => no_std_miri_start.stdout} |   0
 src/tools/miri/tests/pass/start.rs            |   8 --
 src/tools/miri/tests/pass/start.stdout        |   1 -
 src/tools/tidy/src/issues.txt                 |   5 -
 src/tools/tidy/src/ui_tests.rs                |   2 +-
 .../item-collection/cross-crate-closures.rs   |   8 +-
 .../cross-crate-generic-functions.rs          |   6 +-
 .../cross-crate-trait-method.rs               |   6 +-
 .../drop_in_place_intrinsic.rs                |   6 +-
 .../item-collection/function-as-argument.rs   |   6 +-
 .../item-collection/generic-drop-glue.rs      |   6 +-
 .../item-collection/generic-functions.rs      |   6 +-
 .../item-collection/generic-impl.rs           |   6 +-
 .../impl-in-non-instantiated-generic.rs       |   6 +-
 .../instantiation-through-vtable.rs           |   6 +-
 .../items-within-generic-items.rs             |   6 +-
 .../item-collection/non-generic-closures.rs   |   8 +-
 .../item-collection/non-generic-drop-glue.rs  |   6 +-
 .../item-collection/non-generic-functions.rs  |   6 +-
 .../item-collection/static-init.rs            |  10 +-
 .../item-collection/statics-and-consts.rs     |   6 +-
 .../item-collection/trait-implementations.rs  |   6 +-
 .../trait-method-as-argument.rs               |   6 +-
 .../trait-method-default-impl.rs              |   6 +-
 .../item-collection/transitive-drop-glue.rs   |   6 +-
 .../item-collection/tuple-drop-glue.rs        |   6 +-
 .../codegen-units/item-collection/unsizing.rs |   6 +-
 .../methods-are-with-self-type.rs             |   1 +
 .../partitioning/vtable-through-const.rs      |  18 +--
 tests/codegen/gdb_debug_script_load.rs        |  28 ++++-
 tests/codegen/mainsubprogramstart.rs          |  14 ---
 tests/run-make/crate-circular-deps-link/c.rs  |   6 +-
 tests/run-make/fmt-write-bloat/main.rs        |   6 +-
 tests/run-make/no-alloc-shim/foo.rs           |   2 +-
 tests/run-make/sepcomp-inlining/foo.rs        |   5 +-
 tests/ui/array-slice-vec/vec-macro-no-std.rs  |  12 +-
 tests/ui/async-await/issue-68523-start.rs     |   9 --
 tests/ui/async-await/issue-68523-start.stderr |   9 --
 tests/ui/attr-start.rs                        |   8 --
 tests/ui/duplicate/dupe-symbols-7.stderr      |   2 +-
 tests/ui/duplicate/dupe-symbols-8.stderr      |   2 +-
 tests/ui/error-codes/E0132.rs                 |   7 --
 tests/ui/error-codes/E0132.stderr             |   9 --
 tests/ui/error-codes/E0138.rs                 |   8 --
 tests/ui/error-codes/E0138.stderr             |  12 --
 tests/ui/error-codes/E0647.rs                 |   9 --
 tests/ui/error-codes/E0647.stderr             |   9 --
 tests/ui/extern/extern-prelude-core.rs        |   6 +-
 tests/ui/feature-gates/feature-gate-start.rs  |   3 -
 .../feature-gates/feature-gate-start.stderr   |  13 --
 ...sue-43106-gating-of-builtin-attrs-error.rs |  21 ----
 ...43106-gating-of-builtin-attrs-error.stderr | 117 ++++++------------
 tests/ui/for-loop-while/for-loop-no-std.rs    |  11 +-
 tests/ui/format-no-std.rs                     |   9 +-
 tests/ui/issues/issue-50714-1.rs              |  11 --
 tests/ui/issues/issue-50714-1.stderr          |   9 --
 tests/ui/issues/issue-9575.rs                 |   7 --
 tests/ui/issues/issue-9575.stderr             |  12 --
 tests/ui/lang-items/issue-19660.rs            |  15 ---
 tests/ui/lang-items/issue-19660.stderr        |   4 -
 tests/ui/lang-items/lang-item-missing.rs      |   9 +-
 .../missing-copy-lang-item-issue-19660.rs     |  15 +++
 .../missing-copy-lang-item-issue-19660.stderr |   8 ++
 tests/ui/lint/dead-code/lint-dead-code-2.rs   |  11 +-
 .../ui/lint/dead-code/lint-dead-code-2.stderr |  10 +-
 tests/ui/print_type_sizes/anonymous.rs        |   7 +-
 tests/ui/privacy/privacy1.rs                  |   4 +-
 tests/ui/privacy/privacy2.rs                  |   4 +-
 tests/ui/privacy/privacy3.rs                  |   4 +-
 tests/ui/privacy/privacy4.rs                  |   4 +-
 .../rfc-2091-track-caller/error-with-start.rs |   7 --
 .../error-with-start.stderr                   |  10 --
 .../issue-108645-target-feature-on-start.rs   |   9 --
 ...ssue-108645-target-feature-on-start.stderr |  11 --
 tests/ui/runtime/native-print-no-runtime.rs   |   9 --
 .../auxiliary/assert-sigpipe-disposition.rs   |  15 +--
 tests/ui/runtime/running-with-no-runtime.rs   |   6 +-
 tests/ui/sanitizer/memory-eager.rs            |   6 +-
 tests/ui/sanitizer/memory-passing.rs          |   6 +-
 tests/ui/sanitizer/memory.rs                  |   8 +-
 .../ui/test-attrs/test-runner-hides-start.rs  |   7 --
 tests/ui/use/use.rs                           |   5 +-
 176 files changed, 454 insertions(+), 1260 deletions(-)
 delete mode 100644 compiler/rustc_codegen_gcc/example/mod_bench.rs
 delete mode 100644 src/doc/unstable-book/src/language-features/start.md
 delete mode 100644 src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs
 delete mode 100644 src/tools/miri/tests/pass/miri_start.stdout
 delete mode 100644 src/tools/miri/tests/pass/no_std.rs
 rename src/tools/miri/tests/pass/{miri_start.rs => no_std_miri_start.rs} (81%)
 rename src/tools/miri/tests/pass/{no_std.stdout => no_std_miri_start.stdout} (100%)
 delete mode 100644 src/tools/miri/tests/pass/start.rs
 delete mode 100644 src/tools/miri/tests/pass/start.stdout
 delete mode 100644 tests/codegen/mainsubprogramstart.rs
 delete mode 100644 tests/ui/async-await/issue-68523-start.rs
 delete mode 100644 tests/ui/async-await/issue-68523-start.stderr
 delete mode 100644 tests/ui/attr-start.rs
 delete mode 100644 tests/ui/error-codes/E0132.rs
 delete mode 100644 tests/ui/error-codes/E0132.stderr
 delete mode 100644 tests/ui/error-codes/E0138.rs
 delete mode 100644 tests/ui/error-codes/E0138.stderr
 delete mode 100644 tests/ui/error-codes/E0647.rs
 delete mode 100644 tests/ui/error-codes/E0647.stderr
 delete mode 100644 tests/ui/feature-gates/feature-gate-start.rs
 delete mode 100644 tests/ui/feature-gates/feature-gate-start.stderr
 delete mode 100644 tests/ui/issues/issue-50714-1.rs
 delete mode 100644 tests/ui/issues/issue-50714-1.stderr
 delete mode 100644 tests/ui/issues/issue-9575.rs
 delete mode 100644 tests/ui/issues/issue-9575.stderr
 delete mode 100644 tests/ui/lang-items/issue-19660.rs
 delete mode 100644 tests/ui/lang-items/issue-19660.stderr
 create mode 100644 tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
 create mode 100644 tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
 delete mode 100644 tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs
 delete mode 100644 tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr
 delete mode 100644 tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs
 delete mode 100644 tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr
 delete mode 100644 tests/ui/runtime/native-print-no-runtime.rs
 delete mode 100644 tests/ui/test-attrs/test-runner-hides-start.rs

diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs
index ab1413d6080e5..12cbb3b2a15f7 100644
--- a/compiler/rustc_ast/src/entry.rs
+++ b/compiler/rustc_ast/src/entry.rs
@@ -18,12 +18,6 @@ pub enum EntryPointType {
     /// fn main() {}
     /// ```
     RustcMainAttr,
-    /// This is a function with the `#[start]` attribute.
-    /// ```ignore (clashes with test entrypoint)
-    /// #[start]
-    /// fn main() {}
-    /// ```
-    Start,
     /// This function is **not** an entrypoint but simply named `main` (not at the root).
     /// This is only used for diagnostics.
     /// ```
@@ -40,9 +34,7 @@ pub fn entry_point_type(
     at_root: bool,
     name: Option<Symbol>,
 ) -> EntryPointType {
-    if attr::contains_name(attrs, sym::start) {
-        EntryPointType::Start
-    } else if attr::contains_name(attrs, sym::rustc_main) {
+    if attr::contains_name(attrs, sym::rustc_main) {
         EntryPointType::RustcMainAttr
     } else if let Some(name) = name
         && name == sym::main
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 94746212138dc..7aea049b89f9a 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -230,18 +230,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
-            ast::ItemKind::Fn(..) => {
-                if attr::contains_name(&i.attrs, sym::start) {
-                    gate!(
-                        &self,
-                        start,
-                        i.span,
-                        "`#[start]` functions are experimental and their signature may change \
-                         over time"
-                    );
-                }
-            }
-
             ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
                 for attr in attr::filter_by_name(&i.attrs, sym::repr) {
                     for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 4644659894368..31b068bd33dae 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -204,11 +204,11 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
         ast::mut_visit::walk_item(self, item);
         self.depth -= 1;
 
-        // Remove any #[rustc_main] or #[start] from the AST so it doesn't
+        // Remove any #[rustc_main] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
         match entry_point_type(&item, self.depth == 0) {
-            EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
+            EntryPointType::MainNamed | EntryPointType::RustcMainAttr => {
                 let allow_dead_code = attr::mk_attr_nested_word(
                     &self.sess.psess.attr_id_generator,
                     ast::AttrStyle::Outer,
@@ -217,8 +217,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
                     sym::dead_code,
                     self.def_site,
                 );
-                item.attrs
-                    .retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start));
+                item.attrs.retain(|attr| !attr.has_name(sym::rustc_main));
                 item.attrs.push(allow_dead_code);
             }
             EntryPointType::None | EntryPointType::OtherMain => {}
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index e6bf0d5b47e4c..f684349689542 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -1,7 +1,7 @@
 use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
 use rustc_hir::LangItem;
 use rustc_middle::ty::{AssocKind, GenericArg};
-use rustc_session::config::{EntryFnType, sigpipe};
+use rustc_session::config::EntryFnType;
 use rustc_span::{DUMMY_SP, Ident};
 
 use crate::prelude::*;
@@ -14,10 +14,9 @@ pub(crate) fn maybe_create_entry_wrapper(
     is_jit: bool,
     is_primary_cgu: bool,
 ) {
-    let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) {
+    let (main_def_id, sigpipe) = match tcx.entry_fn(()) {
         Some((def_id, entry_ty)) => (def_id, match entry_ty {
-            EntryFnType::Main { sigpipe } => (true, sigpipe),
-            EntryFnType::Start => (false, sigpipe::DEFAULT),
+            EntryFnType::Main { sigpipe } => sigpipe,
         }),
         None => return,
     };
@@ -31,14 +30,13 @@ pub(crate) fn maybe_create_entry_wrapper(
         return;
     }
 
-    create_entry_fn(tcx, module, main_def_id, is_jit, is_main_fn, sigpipe);
+    create_entry_fn(tcx, module, main_def_id, is_jit, sigpipe);
 
     fn create_entry_fn(
         tcx: TyCtxt<'_>,
         m: &mut dyn Module,
         rust_main_def_id: DefId,
         ignore_lang_start_wrapper: bool,
-        is_main_fn: bool,
         sigpipe: u8,
     ) {
         let main_ret_ty = tcx.fn_sig(rust_main_def_id).no_bound_vars().unwrap().output();
@@ -94,8 +92,8 @@ pub(crate) fn maybe_create_entry_wrapper(
 
             let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);
 
-            let result = if is_main_fn && ignore_lang_start_wrapper {
-                // regular main fn, but ignoring #[lang = "start"] as we are running in the jit
+            let result = if ignore_lang_start_wrapper {
+                // ignoring #[lang = "start"] as we are running in the jit
                 // FIXME set program arguments somehow
                 let call_inst = bcx.ins().call(main_func_ref, &[]);
                 let call_results = bcx.func.dfg.inst_results(call_inst).to_owned();
@@ -133,7 +131,8 @@ pub(crate) fn maybe_create_entry_wrapper(
                     types::I64 => bcx.ins().sextend(types::I64, res),
                     _ => unimplemented!("16bit systems are not yet supported"),
                 }
-            } else if is_main_fn {
+            } else {
+                // Regular main fn invoked via start lang item.
                 let start_def_id = tcx.require_lang_item(LangItem::Start, None);
                 let start_instance = Instance::expect_resolve(
                     tcx,
@@ -150,10 +149,6 @@ pub(crate) fn maybe_create_entry_wrapper(
                 let call_inst =
                     bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]);
                 bcx.inst_results(call_inst)[0]
-            } else {
-                // using user-defined start fn
-                let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]);
-                bcx.inst_results(call_inst)[0]
             };
 
             bcx.ins().return_(&[result]);
diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs
index 7cc7336612c79..0e790a4befc9b 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/test.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs
@@ -426,19 +426,6 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> {
     run_command_with_env(&command, None, Some(env))?;
     maybe_run_command_in_vm(&[&cargo_target_dir.join("track-caller-attribute")], env, args)?;
 
-    // FIXME: create a function "display_if_not_quiet" or something along the line.
-    println!("[AOT] mod_bench");
-    let mut command = args.config_info.rustc_command_vec();
-    command.extend_from_slice(&[
-        &"example/mod_bench.rs",
-        &"--crate-type",
-        &"bin",
-        &"--target",
-        &args.config_info.target_triple,
-    ]);
-    run_command_with_env(&command, None, Some(env))?;
-    // FIXME: the compiled binary is not run.
-
     Ok(())
 }
 
@@ -696,19 +683,6 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
     Ok(())
 }
 
-// echo "[BENCH COMPILE] mod_bench"
-//
-// COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline"
-// COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o $cargo_target_dir/mod_bench_llvm_0 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o $cargo_target_dir/mod_bench_llvm_1 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o $cargo_target_dir/mod_bench_llvm_2 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o $cargo_target_dir/mod_bench_llvm_3 -Cpanic=abort"
-//
-// Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow
-// hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3"
-// echo "[BENCH RUN] mod_bench"
-// hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_*
-
 fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> {
     if !args.is_using_gcc_master_branch() {
         println!("Not using GCC master branch. Skipping `extended_rand_tests`.");
diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs
index 6ed8b9157f21a..9a0b46d5b221a 100644
--- a/compiler/rustc_codegen_gcc/example/alloc_example.rs
+++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs
@@ -1,5 +1,6 @@
-#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
+#![feature(core_intrinsics, alloc_error_handler, lang_items)]
 #![no_std]
+#![no_main]
 #![allow(internal_features)]
 
 extern crate alloc;
@@ -37,8 +38,8 @@ unsafe extern "C" fn _Unwind_Resume() {
     core::intrinsics::unreachable();
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let world: Box<&str> = Box::new("Hello World!\0");
     unsafe {
         puts(*world as *const str as *const u8);
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 1d51e0a1856ba..4cbe66c5e4c69 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -1,7 +1,7 @@
 // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
 
 #![feature(
-    no_core, unboxed_closures, start, lang_items, never_type, linkage,
+    no_core, unboxed_closures, lang_items, never_type, linkage,
     extern_types, thread_local
 )]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs
deleted file mode 100644
index e8a9cade74745..0000000000000
--- a/compiler/rustc_codegen_gcc/example/mod_bench.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#![feature(start, core_intrinsics, lang_items)]
-#![no_std]
-#![allow(internal_features)]
-
-#[link(name = "c")]
-extern "C" {}
-
-#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
-    core::intrinsics::abort();
-}
-
-#[lang="eh_personality"]
-fn eh_personality(){}
-
-// Required for rustc_codegen_llvm
-#[no_mangle]
-unsafe extern "C" fn _Unwind_Resume() {
-    core::intrinsics::unreachable();
-}
-
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    for i in 2..100_000_000 {
-        black_box((i + 1) % i);
-    }
-
-    0
-}
-
-#[inline(never)]
-fn black_box(i: u32) {
-    if i != 1 {
-        core::intrinsics::abort();
-    }
-}
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index c81c53359fd18..30732c74eb3ef 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -513,7 +513,6 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         } else {
             // If the symbol already exists, it is an error: for example, the user wrote
             // #[no_mangle] extern "C" fn main(..) {..}
-            // instead of #[start]
             None
         }
     }
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
index 696197d73772f..385e41a68817f 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: signal
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -49,7 +50,7 @@ fn test_fail() -> ! {
     unsafe { intrinsics::abort() };
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     test_fail();
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
index 714cd6c0f3817..6c66a930e0741 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: signal
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -50,8 +51,8 @@ fn fail() -> i32 {
     0
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     fail();
     0
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs
index c3c08c29c6dba..e18a4ced6bc46 100644
--- a/compiler/rustc_codegen_gcc/tests/run/array.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/array.rs
@@ -7,10 +7,11 @@
 //     5
 //     10
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -28,8 +29,8 @@ fn make_array() -> [u8; 3] {
     [42, 10, 5]
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let array = [42, 7, 5];
     let array2 = make_array();
     unsafe {
diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs
index 2a47f0c2966e5..4d414c577a657 100644
--- a/compiler/rustc_codegen_gcc/tests/run/assign.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs
@@ -6,10 +6,11 @@
 //     10
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -142,8 +143,8 @@ fn inc(num: isize) -> isize {
 }
 
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     argc = inc(argc);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs
index 46c47bc54ed01..c7a236f74f9e6 100644
--- a/compiler/rustc_codegen_gcc/tests/run/closure.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs
@@ -8,10 +8,11 @@
 //     Int argument: 2
 //     Both args: 11
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -22,8 +23,8 @@ mod libc {
     }
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let string = "Arg: %d\n\0";
     let mut closure = || {
         unsafe {
diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs
index 039ef94eaa717..b02359702ed2e 100644
--- a/compiler/rustc_codegen_gcc/tests/run/condition.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs
@@ -5,10 +5,11 @@
 //   stdout: true
 //     1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -19,8 +20,8 @@ mod libc {
     }
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         if argc == 1 {
             libc::printf(b"true\n\0" as *const u8 as *const i8);
diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
index e66a859ad698e..042e44080c53a 100644
--- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 0
 
-#![feature(auto_traits, lang_items, no_core, start)]
+#![feature(auto_traits, lang_items, no_core)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     0
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs
index bf1cbeef30205..9a7c91c0adb20 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 2
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 mod libc {
     #[link(name = "c")]
@@ -41,8 +42,8 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::exit(2);
     }
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
index be7a233efdaaf..c50d2b0d7107c 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 1
 
-#![feature(auto_traits, lang_items, no_core, start)]
+#![feature(auto_traits, lang_items, no_core)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     1
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
index ed1bf72bb2754..98b351e504495 100644
--- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -26,8 +27,8 @@ fn call_func(func: fn(i16) -> i8, param: i16) -> i8 {
     func(param)
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         let result = call_func(i16_as_i8, argc as i16) as isize;
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, result);
diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
index 3ae793382164b..9be64f991ee08 100644
--- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
@@ -8,10 +8,11 @@
 //     11
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -148,8 +149,8 @@ fn update_num(num: &mut isize) {
     *num = *num + 5;
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let mut test = test(argc);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs
index 0e44fc580b8c4..c92d3cc0b8fbf 100644
--- a/compiler/rustc_codegen_gcc/tests/run/operations.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs
@@ -6,10 +6,11 @@
 //     10
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, arbitrary_self_types, rustc_attrs)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -231,8 +232,8 @@ pub fn panic_const_mul_overflow() -> ! {
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc);
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc);
diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
index 2b8812ad51c5e..0ba49e7187fca 100644
--- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -24,8 +25,8 @@ fn make_array() -> [u8; 3] {
     [42, 10, 5]
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         let ptr = ONE as *mut usize;
         let value = ptr as usize;
diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
index f2a5a2e4384df..3cc1e274001e7 100644
--- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
@@ -6,11 +6,12 @@
 //     10
 //     42
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 #[lang = "copy"]
 pub unsafe trait Copy {}
@@ -61,8 +62,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u3
     )
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42);
     unsafe {
         libc::printf(b"%d\n\0" as *const u8 as *const i8, c);
diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs
index fba93fc155495..825fcb8a081e7 100644
--- a/compiler/rustc_codegen_gcc/tests/run/slice.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 5
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -26,8 +27,8 @@ fn index_slice(s: &[u32]) -> u32 {
     }
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let array = [42, 7, 5];
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array));
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
index a17ea2a48936d..80c8782c4b1a6 100644
--- a/compiler/rustc_codegen_gcc/tests/run/static.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/static.rs
@@ -9,11 +9,12 @@
 //      12
 //      1
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -98,8 +99,8 @@ static mut WITH_REF: WithRef = WithRef {
     refe: unsafe { &TEST },
 };
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT);
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs
index d6455667400c9..59b8f358863f2 100644
--- a/compiler/rustc_codegen_gcc/tests/run/structs.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs
@@ -5,11 +5,12 @@
 //   stdout: 1
 //     2
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -55,8 +56,8 @@ fn one() -> isize {
     1
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let test = Test {
         field: one(),
     };
diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
index 8a7d85ae867e8..ed60a56a68c4c 100644
--- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
@@ -4,11 +4,12 @@
 //   status: 0
 //   stdout: 3
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -42,8 +43,8 @@ mod libc {
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let test: (isize, isize, isize) = (3, 1, 4);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index d8fbe51b975a0..9a42cd94ac033 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -748,7 +748,6 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         } else {
             // If the symbol already exists, it is an error: for example, the user wrote
             // #[no_mangle] extern "C" fn main(..) {..}
-            // instead of #[start]
             None
         }
     }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 484f467068a14..a4c50dcc1356e 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -211,7 +211,7 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but
 codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
 
 codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
-    .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+    .help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
 codegen_ssa_no_field = no field `{$name}`
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 544578b29f107..83724af604d14 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -490,8 +490,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let ptr_ty = cx.type_ptr();
         let (arg_argc, arg_argv) = get_argc_argv(&mut bx);
 
-        let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type
-        {
+        let EntryFnType::Main { sigpipe } = entry_type;
+        let (start_fn, start_ty, args, instance) = {
             let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
             let start_instance = ty::Instance::expect_resolve(
                 cx.tcx(),
@@ -512,10 +512,6 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 vec![rust_main, arg_argc, arg_argv, arg_sigpipe],
                 Some(start_instance),
             )
-        } else {
-            debug!("using user-defined start fn");
-            let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty);
-            (rust_main, start_ty, vec![arg_argc, arg_argv], None)
         };
 
         let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
@@ -530,7 +526,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-/// Obtain the `argc` and `argv` values to pass to the rust start function.
+/// Obtain the `argc` and `argv` values to pass to the rust start function
+/// (i.e., the "start" lang item).
 fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) {
     if bx.cx().sess().target.os.contains("uefi") {
         // Params for UEFI
diff --git a/compiler/rustc_error_codes/src/error_codes/E0132.md b/compiler/rustc_error_codes/src/error_codes/E0132.md
index 51258739b89cb..cbb14510ed75a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0132.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0132.md
@@ -1,32 +1,3 @@
-A function with the `start` attribute was declared with type parameters.
-
-Erroneous code example:
-
-```compile_fail,E0132
-#![feature(start)]
-
-#[start]
-fn f<T>() {}
-```
-
-It is not possible to declare type parameters on a function that has the `start`
-attribute. Such a function must have the following type signature (for more
-information, view [the unstable book][1]):
+#### Note: this error code is no longer emitted by the compiler.
 
-[1]: https://doc.rust-lang.org/unstable-book/language-features/start.html
-
-```
-# let _:
-fn(isize, *const *const u8) -> isize;
-```
-
-Example:
-
-```
-#![feature(start)]
-
-#[start]
-fn my_start(argc: isize, argv: *const *const u8) -> isize {
-    0
-}
-```
+A function with the `start` attribute was declared with type parameters.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0138.md b/compiler/rustc_error_codes/src/error_codes/E0138.md
index 3f5eaea9f989e..2e6ba546a16c7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0138.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0138.md
@@ -1,25 +1,3 @@
-More than one function was declared with the `#[start]` attribute.
-
-Erroneous code example:
-
-```compile_fail,E0138
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize {}
+#### Note: this error code is no longer emitted by the compiler.
 
-#[start]
-fn f(argc: isize, argv: *const *const u8) -> isize {}
-// error: multiple 'start' functions
-```
-
-This error indicates that the compiler found multiple functions with the
-`#[start]` attribute. This is an error because there must be a unique entry
-point into a Rust program. Example:
-
-```
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok!
-```
+More than one function was declared with the `#[start]` attribute.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0647.md b/compiler/rustc_error_codes/src/error_codes/E0647.md
index 59bb47ba62a9f..e2f14b81aa6c4 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0647.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0647.md
@@ -1,13 +1,3 @@
-The `start` function was defined with a where clause.
-
-Erroneous code example:
+#### Note: this error code is no longer emitted by the compiler.
 
-```compile_fail,E0647
-#![feature(start)]
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize where (): Copy {
-    //^ error: `#[start]` function is not allowed to have a where clause
-    0
-}
-```
+The `start` function was defined with a where clause.
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 29f3277d3997e..0a30bdb48a09c 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -24,6 +24,10 @@
 //
 // Both columns are necessary because it's not possible in Rust to create a new identifier such as
 // `E0123` from an integer literal such as `0123`, unfortunately.
+//
+// Do *not* remove entries from this list. Instead, just add a note th the corresponding markdown
+// file saying that this error is not emitted by the compiler any more (see E0001.md for an
+// example), and remove all code examples that do not build any more.
 #[macro_export]
 macro_rules! error_codes {
     ($macro:path) => (
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index c28a4360f6f91..77268b12f908e 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -448,7 +448,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     // Entry point:
-    ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
 
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 9aa59375706b4..944665c9ee5b5 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -220,8 +220,9 @@ declare_features! (
     (removed, rustc_diagnostic_macros, "1.38.0", None, None),
     /// Allows identifying crates that contain sanitizer runtimes.
     (removed, sanitizer_runtime, "1.17.0", None, None),
-    (removed, simd, "1.0.0", Some(27731),
-     Some("removed in favor of `#[repr(simd)]`")),
+    (removed, simd, "1.0.0", Some(27731), Some("removed in favor of `#[repr(simd)]`")),
+    /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
+    (removed, start, "1.0.0", Some(29633), Some("not portable enough and never RFC'd")),
     /// Allows `#[link(kind = "static-nobundle", ...)]`.
     (removed, static_nobundle, "1.16.0", Some(37403),
      Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index fb83487c9394b..a9635a383fb05 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -300,8 +300,6 @@ declare_features! (
     (internal, rustdoc_internals, "1.58.0", Some(90418)),
     /// Allows using the `rustdoc::missing_doc_code_examples` lint
     (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)),
-    /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
-    (unstable, start, "1.0.0", Some(29633)),
     /// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
     /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library
     /// feature with the same name exists.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index fae3b778d7bdd..02bc069fc5f27 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -332,6 +332,10 @@ language_item_table! {
     FallbackSurfaceDrop,     sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn,             GenericRequirement::None;
     AllocLayout,             sym::alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
 
+    /// For all binary crates without `#![no_main]`, Rust will generate a "main" function.
+    /// The exact name and signature are target-dependent. The "main" function will invoke
+    /// this lang item, passing it the `argc` and `argv` (or null, if those don't exist
+    /// on the current target) as well as the user-defined `fn main` from the binary crate.
     Start,                   sym::start,               start_fn,                   Target::Fn,             GenericRequirement::Exact(1);
 
     EhPersonality,           sym::eh_personality,      eh_personality,             Target::Fn,             GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index d7ab6eca84b3d..512d379687bcf 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -489,21 +489,6 @@ hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is hi
 hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable
     .help = add `#![feature(min_specialization)]` to the crate attributes to enable
 
-hir_analysis_start_function_parameters = `#[start]` function is not allowed to have type parameters
-    .label = `#[start]` function cannot have type parameters
-
-hir_analysis_start_function_where = `#[start]` function is not allowed to have a `where` clause
-    .label = `#[start]` function cannot have a `where` clause
-
-hir_analysis_start_not_async = `#[start]` function is not allowed to be `async`
-    .label = `#[start]` is not allowed to be `async`
-
-hir_analysis_start_not_target_feature = `#[start]` function is not allowed to have `#[target_feature]`
-    .label = `#[start]` function is not allowed to have `#[target_feature]`
-
-hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
-    .label = `#[start]` function is not allowed to be `#[track_caller]`
-
 hir_analysis_static_specialize = cannot specialize on `'static` lifetime
 
 hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 332ac2fa0c0d7..25c2f8554b7f4 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_session::config::EntryFnType;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_span::{Span, sym};
@@ -18,7 +18,6 @@ use crate::errors;
 pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
     match tcx.entry_fn(()) {
         Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
-        Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
         _ => {}
     }
 }
@@ -192,83 +191,3 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         });
     }
 }
-
-fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
-    let start_def_id = start_def_id.expect_local();
-    let start_id = tcx.local_def_id_to_hir_id(start_def_id);
-    let start_span = tcx.def_span(start_def_id);
-    let start_t = tcx.type_of(start_def_id).instantiate_identity();
-    match start_t.kind() {
-        ty::FnDef(..) => {
-            if let Node::Item(it) = tcx.hir_node(start_id) {
-                if let hir::ItemKind::Fn { sig, generics, .. } = &it.kind {
-                    let mut error = false;
-                    if !generics.params.is_empty() {
-                        tcx.dcx().emit_err(errors::StartFunctionParameters { span: generics.span });
-                        error = true;
-                    }
-                    if generics.has_where_clause_predicates {
-                        tcx.dcx().emit_err(errors::StartFunctionWhere {
-                            span: generics.where_clause_span,
-                        });
-                        error = true;
-                    }
-                    if sig.header.asyncness.is_async() {
-                        let span = tcx.def_span(it.owner_id);
-                        tcx.dcx().emit_err(errors::StartAsync { span });
-                        error = true;
-                    }
-
-                    let attrs = tcx.hir().attrs(start_id);
-                    for attr in attrs {
-                        if attr.has_name(sym::track_caller) {
-                            tcx.dcx().emit_err(errors::StartTrackCaller {
-                                span: attr.span,
-                                start: start_span,
-                            });
-                            error = true;
-                        }
-                        if attr.has_name(sym::target_feature)
-                            // Calling functions with `#[target_feature]` is
-                            // not unsafe on WASM, see #84988
-                            && !tcx.sess.target.is_like_wasm
-                            && !tcx.sess.opts.actually_rustdoc
-                        {
-                            tcx.dcx().emit_err(errors::StartTargetFeature {
-                                span: attr.span,
-                                start: start_span,
-                            });
-                            error = true;
-                        }
-                    }
-
-                    if error {
-                        return;
-                    }
-                }
-            }
-
-            let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
-                [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
-                tcx.types.isize,
-                false,
-                hir::Safety::Safe,
-                ExternAbi::Rust,
-            ));
-
-            let _ = check_function_signature(
-                tcx,
-                ObligationCause::new(
-                    start_span,
-                    start_def_id,
-                    ObligationCauseCode::StartFunctionType,
-                ),
-                start_def_id.into(),
-                expected_sig,
-            );
-        }
-        _ => {
-            span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
-        }
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 00ba1741ed729..a0f365142baed 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -619,48 +619,6 @@ pub(crate) struct TargetFeatureOnMain {
     pub main: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_track_caller)]
-pub(crate) struct StartTrackCaller {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub start: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_target_feature)]
-pub(crate) struct StartTargetFeature {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub start: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_async, code = E0752)]
-pub(crate) struct StartAsync {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_function_where, code = E0647)]
-pub(crate) struct StartFunctionWhere {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_function_parameters, code = E0132)]
-pub(crate) struct StartFunctionParameters {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(hir_analysis_main_function_return_type_generic, code = E0131)]
 pub(crate) struct MainFunctionReturnTypeGeneric {
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index db2bb8a7248a6..55d78e083e079 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -345,9 +345,6 @@ pub enum ObligationCauseCode<'tcx> {
     /// `main` has wrong type
     MainFunctionType,
 
-    /// `start` has wrong type
-    StartFunctionType,
-
     /// language function has wrong type
     LangFunctionType(Symbol),
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3ed600a717f53..133d84572e6d3 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -502,11 +502,6 @@ passes_multiple_rustc_main =
     .first = first `#[rustc_main]` function
     .additional = additional `#[rustc_main]` function
 
-passes_multiple_start_functions =
-    multiple `start` functions
-    .label = multiple `start` functions
-    .previous = previous `#[start]` function here
-
 passes_must_not_suspend =
     `must_not_suspend` attribute should be applied to a struct, enum, union, or trait
     .label = is not a struct, enum, union, or trait
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 1b2b8ac5dd9e7..dbb87443eed51 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -275,7 +275,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | sym::lang
                     | sym::needs_allocator
                     | sym::default_lib_allocator
-                    | sym::start
                     | sym::custom_mir,
                     ..
                 ] => {}
@@ -2655,7 +2654,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         sym::repr,
         sym::path,
         sym::automatically_derived,
-        sym::start,
         sym::rustc_main,
         sym::derive,
         sym::test,
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 4949a4316a7b0..22291c9282db7 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -10,9 +10,7 @@ use rustc_session::RemapFileNameExt;
 use rustc_session::config::{CrateType, EntryFnType, RemapPathScopeComponents, sigpipe};
 use rustc_span::{Span, Symbol, sym};
 
-use crate::errors::{
-    AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr,
-};
+use crate::errors::{AttrOnlyInFunctions, ExternMain, MultipleRustcMain, NoMainErr};
 
 struct EntryContext<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -20,9 +18,6 @@ struct EntryContext<'tcx> {
     /// The function has the `#[rustc_main]` attribute.
     rustc_main_fn: Option<(LocalDefId, Span)>,
 
-    /// The function that has the attribute `#[start]` on it.
-    start_fn: Option<(LocalDefId, Span)>,
-
     /// The functions that one might think are `main` but aren't, e.g.
     /// main functions not defined at the top level. For diagnostics.
     non_main_fns: Vec<Span>,
@@ -40,8 +35,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
         return None;
     }
 
-    let mut ctxt =
-        EntryContext { tcx, rustc_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
+    let mut ctxt = EntryContext { tcx, rustc_main_fn: None, non_main_fns: Vec::new() };
 
     for id in tcx.hir().items() {
         check_and_search_item(id, &mut ctxt);
@@ -57,7 +51,7 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti
 
 fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
     if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) {
-        for attr in [sym::start, sym::rustc_main] {
+        for attr in [sym::rustc_main] {
             if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
                 ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr });
             }
@@ -91,24 +85,11 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
                 });
             }
         }
-        EntryPointType::Start => {
-            if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
-            } else {
-                ctxt.tcx.dcx().emit_err(MultipleStartFunctions {
-                    span: ctxt.tcx.def_span(id.owner_id),
-                    labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()),
-                    previous: ctxt.start_fn.unwrap().1,
-                });
-            }
-        }
     }
 }
 
 fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
-    if let Some((def_id, _)) = visitor.start_fn {
-        Some((def_id.to_def_id(), EntryFnType::Start))
-    } else if let Some((local_def_id, _)) = visitor.rustc_main_fn {
+    if let Some((local_def_id, _)) = visitor.rustc_main_fn {
         let def_id = local_def_id.to_def_id();
         Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }))
     } else {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index c3043ac60aa69..3d38b00e99f2c 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1313,17 +1313,6 @@ pub(crate) struct MultipleRustcMain {
     pub additional: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(passes_multiple_start_functions, code = E0138)]
-pub(crate) struct MultipleStartFunctions {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub labeled: Span,
-    #[label(passes_previous)]
-    pub previous: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(passes_extern_main)]
 pub(crate) struct ExternMain {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 5192ad61af2b1..08b18e328300d 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1275,7 +1275,6 @@ pub enum EntryFnType {
         /// and an `include!()`.
         sigpipe: u8,
     },
-    Start,
 }
 
 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index b82bb27eb795a..750d2756b4a42 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -261,7 +261,6 @@ trait_selection_oc_fn_lang_correct_type = {$lang_item_name ->
         *[lang_item_name] lang item `{$lang_item_name}`
     } function has wrong type
 trait_selection_oc_fn_main_correct_type = `main` function has wrong type
-trait_selection_oc_fn_start_correct_type = `#[start]` function has wrong type
 trait_selection_oc_generic = mismatched types
 
 trait_selection_oc_if_else_different = `if` and `else` have incompatible types
@@ -396,7 +395,6 @@ trait_selection_subtype = ...so that the {$requirement ->
     [if_else_different] `if` and `else` have incompatible types
     [no_else] `if` missing an `else` returns `()`
     [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
     [fn_lang_correct_type] lang item function has the correct type
     [intrinsic_correct_type] intrinsic has the correct type
     [method_correct_type] method receiver has the correct type
@@ -410,7 +408,6 @@ trait_selection_subtype_2 = ...so that {$requirement ->
     [if_else_different] `if` and `else` have incompatible types
     [no_else] `if` missing an `else` returns `()`
     [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
     [fn_lang_correct_type] lang item function has the correct type
     [intrinsic_correct_type] intrinsic has the correct type
     [method_correct_type] method receiver has the correct type
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 7032f7b9d318e..ceef199cc6125 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -2310,7 +2310,6 @@ impl<'tcx> ObligationCause<'tcx> {
             | ObligationCauseCode::MatchExpressionArm(_)
             | ObligationCauseCode::IfExpression { .. }
             | ObligationCauseCode::LetElse
-            | ObligationCauseCode::StartFunctionType
             | ObligationCauseCode::LangFunctionType(_)
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver => FailureCode::Error0308,
@@ -2368,9 +2367,6 @@ impl<'tcx> ObligationCause<'tcx> {
             ObligationCauseCode::MainFunctionType => {
                 ObligationCauseFailureCode::FnMainCorrectType { span }
             }
-            ObligationCauseCode::StartFunctionType => {
-                ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }
-            }
             &ObligationCauseCode::LangFunctionType(lang_item_name) => {
                 ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
             }
@@ -2413,7 +2409,6 @@ impl<'tcx> ObligationCause<'tcx> {
                 "const is compatible with trait"
             }
             ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
-            ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type",
             ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type",
             ObligationCauseCode::IntrinsicType => "intrinsic has the correct type",
             ObligationCauseCode::MethodReceiver => "method receiver has the correct type",
@@ -2434,7 +2429,6 @@ impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
                 "const_compat"
             }
             ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
-            ObligationCauseCode::StartFunctionType => "fn_start_correct_type",
             ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type",
             ObligationCauseCode::IntrinsicType => "intrinsic_correct_type",
             ObligationCauseCode::MethodReceiver => "method_correct_type",
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 9d85ca1dd4dd7..80f37180f1390 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2740,7 +2740,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             | ObligationCauseCode::IfExpression { .. }
             | ObligationCauseCode::IfExpressionWithNoElse
             | ObligationCauseCode::MainFunctionType
-            | ObligationCauseCode::StartFunctionType
             | ObligationCauseCode::LangFunctionType(_)
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 53a4e5031c6dd..0bf91ad35c152 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1695,13 +1695,6 @@ pub enum ObligationCauseFailureCode {
         #[primary_span]
         span: Span,
     },
-    #[diag(trait_selection_oc_fn_start_correct_type, code = E0308)]
-    FnStartCorrectType {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
     #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)]
     FnLangCorrectType {
         #[primary_span]
diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md
index 1c240d1255a3d..96e3b58f47150 100644
--- a/src/doc/rustc/src/platform-support/nto-qnx.md
+++ b/src/doc/rustc/src/platform-support/nto-qnx.md
@@ -78,7 +78,7 @@ extern "C" {
 }
 
 #[no_mangle]
-pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     const HELLO: &'static str = "Hello World, the answer is %d\n\0";
     unsafe {
         printf(HELLO.as_ptr() as *const _, 42);
diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md
index 32b882e763d65..1122bbc5a8786 100644
--- a/src/doc/unstable-book/src/language-features/lang-items.md
+++ b/src/doc/unstable-book/src/language-features/lang-items.md
@@ -46,14 +46,15 @@ allocation. A freestanding program that uses the `Box` sugar for dynamic
 allocations via `malloc` and `free`:
 
 ```rust,ignore (libc-is-finicky)
-#![feature(lang_items, start, core_intrinsics, rustc_private, panic_unwind, rustc_attrs)]
+#![feature(lang_items, core_intrinsics, rustc_private, panic_unwind, rustc_attrs)]
 #![allow(internal_features)]
 #![no_std]
+#![no_main]
 
 extern crate libc;
 extern crate unwind;
 
-use core::ffi::c_void;
+use core::ffi::{c_int, c_void};
 use core::intrinsics;
 use core::panic::PanicInfo;
 use core::ptr::NonNull;
@@ -91,8 +92,8 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
     p
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: c_int, _argv: *const *const u8) -> c_int {
     let _x = Box::new(1);
 
     0
diff --git a/src/doc/unstable-book/src/language-features/start.md b/src/doc/unstable-book/src/language-features/start.md
deleted file mode 100644
index 09e4875a2e4f7..0000000000000
--- a/src/doc/unstable-book/src/language-features/start.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# `start`
-
-The tracking issue for this feature is: [#29633]
-
-[#29633]: https://github.com/rust-lang/rust/issues/29633
-
-------------------------
-
-Allows you to mark a function as the entry point of the executable, which is
-necessary in `#![no_std]` environments.
-
-The function marked `#[start]` is passed the command line parameters in the same
-format as the C main function (aside from the integer types being used).
-It has to be non-generic and have the following signature:
-
-```rust,ignore (only-for-syntax-highlight)
-# let _:
-fn(isize, *const *const u8) -> isize
-# ;
-```
-
-This feature should not be confused with the `start` *lang item* which is
-defined by the `std` crate and is written `#[lang = "start"]`.
-
-## Usage together with the `std` crate
-
-`#[start]` can be used in combination with the `std` crate, in which case the
-normal `main` function (which would get called from the `std` crate) won't be
-used as an entry point.
-The initialization code in `std` will be skipped this way.
-
-Example:
-
-```rust
-#![feature(start)]
-
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    0
-}
-```
-
-Unwinding the stack past the `#[start]` function is currently considered
-Undefined Behavior (for any unwinding implementation):
-
-```rust,ignore (UB)
-#![feature(start)]
-
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    std::panic::catch_unwind(|| {
-        panic!(); // panic safely gets caught or safely aborts execution
-    });
-
-    panic!(); // UB!
-
-    0
-}
-```
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
index f66554de30005..26c6a5033d162 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
@@ -1,10 +1,9 @@
 #![warn(clippy::borrow_as_ptr)]
-#![feature(lang_items, start, libc)]
 #![no_std]
+#![crate_type = "lib"]
 
 #[clippy::msrv = "1.75"]
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let val = 1;
     let _p = core::ptr::addr_of!(val);
 
@@ -12,11 +11,3 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _p_mut = core::ptr::addr_of_mut!(val_mut);
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
index 1fc254aafa775..d8d8b4c380ce5 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
@@ -1,10 +1,9 @@
 #![warn(clippy::borrow_as_ptr)]
-#![feature(lang_items, start, libc)]
 #![no_std]
+#![crate_type = "lib"]
 
 #[clippy::msrv = "1.75"]
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let val = 1;
     let _p = &val as *const i32;
 
@@ -12,11 +11,3 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _p_mut = &mut val_mut as *mut i32;
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
index 6802c86ec95a5..488e0bd96776f 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
@@ -1,5 +1,5 @@
 error: borrow as raw pointer
-  --> tests/ui/borrow_as_ptr_no_std.rs:9:14
+  --> tests/ui/borrow_as_ptr_no_std.rs:8:14
    |
 LL |     let _p = &val as *const i32;
    |              ^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of!(val)`
@@ -8,7 +8,7 @@ LL |     let _p = &val as *const i32;
    = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`
 
 error: borrow as raw pointer
-  --> tests/ui/borrow_as_ptr_no_std.rs:12:18
+  --> tests/ui/borrow_as_ptr_no_std.rs:11:18
    |
 LL |     let _p_mut = &mut val_mut as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of_mut!(val_mut)`
diff --git a/src/tools/clippy/tests/ui/box_default_no_std.rs b/src/tools/clippy/tests/ui/box_default_no_std.rs
index 4326abc9a5410..edb701fcd084d 100644
--- a/src/tools/clippy/tests/ui/box_default_no_std.rs
+++ b/src/tools/clippy/tests/ui/box_default_no_std.rs
@@ -1,6 +1,6 @@
-#![feature(lang_items, start, libc)]
 #![warn(clippy::box_default)]
 #![no_std]
+#![crate_type = "lib"]
 
 pub struct NotBox<T> {
     _value: T,
@@ -18,16 +18,7 @@ impl<T: Default> Default for NotBox<T> {
     }
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _p = NotBox::new(isize::default());
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7410.rs b/src/tools/clippy/tests/ui/crashes/ice-7410.rs
index ccf6d7ff94f23..addbca54e80aa 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7410.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-7410.rs
@@ -1,7 +1,7 @@
 //@compile-flags: -Clink-arg=-nostartfiles
 //@ignore-target: apple windows
 
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 #![allow(clippy::if_same_then_else)]
 #![allow(clippy::redundant_pattern_matching)]
@@ -15,18 +15,9 @@ impl Drop for S {
     fn drop(&mut self) {}
 }
 
-#[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
+pub fn main(argc: isize, argv: *const *const u8) -> isize {
     if let Some(_) = Some(S) {
     } else {
     }
     0
 }
-
-#[panic_handler]
-fn panic(_info: &PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs
deleted file mode 100644
index 9e5b2a4890348..0000000000000
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//@compile-flags: -Clink-arg=-nostartfiles
-//@ignore-target: apple
-
-#![feature(lang_items, start, libc)]
-#![no_std]
-
-use core::panic::PanicInfo;
-use core::sync::atomic::{AtomicUsize, Ordering};
-
-static N: AtomicUsize = AtomicUsize::new(0);
-
-#[warn(clippy::main_recursion)]
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    let x = N.load(Ordering::Relaxed);
-    N.store(x + 1, Ordering::Relaxed);
-
-    if x < 3 {
-        main(_argc, _argv);
-    }
-
-    0
-}
-
-#[allow(clippy::empty_loop)]
-#[panic_handler]
-fn panic(_info: &PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
index 32bccd3a0ffc6..e09a913ef06cd 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
@@ -1,11 +1,10 @@
 #![no_std]
-#![feature(lang_items, start, libc)]
 #![crate_type = "lib"]
 
 use core::panic::PanicInfo;
 
 #[warn(clippy::all)]
-fn main() {
+pub fn main() {
     let mut a = 42;
     let mut b = 1337;
 
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
index 8ed45a3346550..536e71b4a25ac 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
@@ -1,11 +1,10 @@
 #![no_std]
-#![feature(lang_items, start, libc)]
 #![crate_type = "lib"]
 
 use core::panic::PanicInfo;
 
 #[warn(clippy::all)]
-fn main() {
+pub fn main() {
     let mut a = 42;
     let mut b = 1337;
 
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
index bcc8684f7c2bd..3e37bd95ef340 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
@@ -1,5 +1,5 @@
 error: this looks like you are trying to swap `a` and `b`
-  --> tests/ui/crate_level_checks/no_std_swap.rs:12:5
+  --> tests/ui/crate_level_checks/no_std_swap.rs:11:5
    |
 LL | /     a = b;
 ...  |
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index c9650312db878..03f5ca31f5f07 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -1,6 +1,6 @@
 //@ignore-target: apple
 
-#![feature(no_core, lang_items, start)]
+#![feature(no_core, lang_items)]
 #![no_core]
 #![allow(clippy::missing_safety_doc)]
 
diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs
index 1bb895bda75d7..9bfcbfba9697f 100644
--- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs
+++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs
@@ -2,27 +2,11 @@
 //@ignore-target: apple
 
 #![warn(clippy::empty_loop)]
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 
-use core::panic::PanicInfo;
-
-#[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
+pub fn main(argc: isize, argv: *const *const u8) -> isize {
     // This should trigger the lint
     loop {}
     //~^ ERROR: empty `loop {}` wastes CPU cycles
 }
-
-#[panic_handler]
-fn panic(_info: &PanicInfo) -> ! {
-    // This should NOT trigger the lint
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {
-    // This should also trigger the lint
-    loop {}
-    //~^ ERROR: empty `loop {}` wastes CPU cycles
-}
diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
index f4a18204c3cef..f36fb9d9e3f21 100644
--- a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
+++ b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
@@ -1,5 +1,5 @@
 error: empty `loop {}` wastes CPU cycles
-  --> tests/ui/empty_loop_no_std.rs:13:5
+  --> tests/ui/empty_loop_no_std.rs:10:5
    |
 LL |     loop {}
    |     ^^^^^^^
@@ -8,13 +8,5 @@ LL |     loop {}
    = note: `-D clippy::empty-loop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]`
 
-error: empty `loop {}` wastes CPU cycles
-  --> tests/ui/empty_loop_no_std.rs:26:5
-   |
-LL |     loop {}
-   |     ^^^^^^^
-   |
-   = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
index 8ea75fae89b65..81e4e0380dad9 100644
--- a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
+++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
@@ -1,4 +1,4 @@
-#![feature(lang_items, start)]
+#![crate_type = "lib"]
 #![warn(clippy::imprecise_flops)]
 #![warn(clippy::suboptimal_flops)]
 #![no_std]
@@ -17,15 +17,6 @@ fn fake_abs1(num: f64) -> f64 {
     if num >= 0.0 { num } else { -num }
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index d2f9e34a5ceb3..fdde68790a8c7 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -6,7 +6,6 @@
 //@aux-build:../auxiliary/proc_macros.rs
 
 #![warn(clippy::missing_const_for_fn)]
-#![feature(start)]
 #![feature(type_alias_impl_trait)]
 
 extern crate helper;
@@ -71,15 +70,6 @@ mod with_test_fn {
     }
 }
 
-// Allowing on this function, because it would lint, which we don't want in this case.
-// if we have `#[start]` and `#[test]` check `is_entrypoint_fn(cx, def_id.to_def_id())` is stopped
-// working
-#[allow(clippy::missing_const_for_fn)]
-#[start]
-fn init(num: isize, something: *const *const u8) -> isize {
-    1
-}
-
 trait Foo {
     // This should not be suggested to be made const
     // (rustc doesn't allow const trait methods)
diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed
index 497e0e243174e..771ab1ab21a82 100644
--- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed
+++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed
@@ -1,22 +1,13 @@
 #![warn(clippy::missing_spin_loop)]
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 
 use core::sync::atomic::{AtomicBool, Ordering};
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     // This should trigger the lint
     let b = AtomicBool::new(true);
     // This should lint with `core::hint::spin_loop()`
     while b.load(Ordering::Acquire) { core::hint::spin_loop() }
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs
index 1c85a9c58d651..bf890fc4066b5 100644
--- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs
+++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs
@@ -1,22 +1,13 @@
 #![warn(clippy::missing_spin_loop)]
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 
 use core::sync::atomic::{AtomicBool, Ordering};
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     // This should trigger the lint
     let b = AtomicBool::new(true);
     // This should lint with `core::hint::spin_loop()`
     while b.load(Ordering::Acquire) {}
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
index 7911620d32c50..d4b9485be4612 100644
--- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
+++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
@@ -1,5 +1,5 @@
 error: busy-waiting loop should at least have a spin loop hint
-  --> tests/ui/missing_spin_loop_no_std.rs:12:37
+  --> tests/ui/missing_spin_loop_no_std.rs:11:37
    |
 LL |     while b.load(Ordering::Acquire) {}
    |                                     ^^ help: try: `{ core::hint::spin_loop() }`
diff --git a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
index 1e7a028a7fc02..c9f4996c36899 100644
--- a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
+++ b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
@@ -1,5 +1,6 @@
-#![feature(lang_items, start, libc)]
+#![feature(lang_items, libc)]
 #![no_std]
+#![no_main]
 #![warn(clippy::result_unit_err)]
 
 #[clippy::msrv = "1.80"]
@@ -12,8 +13,8 @@ pub fn returns_unit_error_lint() -> Result<u32, ()> {
     Err(())
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     0
 }
 
diff --git a/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr b/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr
index 33692e6055438..a7807f089ab2c 100644
--- a/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr
+++ b/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr
@@ -1,5 +1,5 @@
 error: this returns a `Result<_, ()>`
-  --> tests/ui/result_unit_error_no_std.rs:11:1
+  --> tests/ui/result_unit_error_no_std.rs:12:1
    |
 LL | pub fn returns_unit_error_lint() -> Result<u32, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
index 4f4d19e883d1b..25143eee8cc30 100644
--- a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
@@ -1,19 +1,10 @@
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 #![deny(clippy::zero_ptr)]
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _ = core::ptr::null::<usize>();
     let _ = core::ptr::null_mut::<f64>();
     let _: *const u8 = core::ptr::null();
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
index 54954d8d13fe7..965733b45d92e 100644
--- a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
@@ -1,19 +1,10 @@
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 #![deny(clippy::zero_ptr)]
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _ = 0 as *const usize;
     let _ = 0 as *mut f64;
     let _: *const u8 = 0 as *const _;
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
index 42a1a41ca94f4..014bf312bf325 100644
--- a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
@@ -1,5 +1,5 @@
 error: `0 as *const _` detected
-  --> tests/ui/zero_ptr_no_std.rs:7:13
+  --> tests/ui/zero_ptr_no_std.rs:6:13
    |
 LL |     let _ = 0 as *const usize;
    |             ^^^^^^^^^^^^^^^^^ help: try: `core::ptr::null::<usize>()`
@@ -11,13 +11,13 @@ LL | #![deny(clippy::zero_ptr)]
    |         ^^^^^^^^^^^^^^^^
 
 error: `0 as *mut _` detected
-  --> tests/ui/zero_ptr_no_std.rs:8:13
+  --> tests/ui/zero_ptr_no_std.rs:7:13
    |
 LL |     let _ = 0 as *mut f64;
    |             ^^^^^^^^^^^^^ help: try: `core::ptr::null_mut::<f64>()`
 
 error: `0 as *const _` detected
-  --> tests/ui/zero_ptr_no_std.rs:9:24
+  --> tests/ui/zero_ptr_no_std.rs:8:24
    |
 LL |     let _: *const u8 = 0 as *const _;
    |                        ^^^^^^^^^^^^^ help: try: `core::ptr::null()`
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 9055aa3027172..22c15c8405fdf 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -33,7 +33,7 @@ use std::sync::atomic::{AtomicI32, Ordering};
 use std::sync::{Arc, Once};
 
 use miri::{
-    BacktraceStyle, BorrowTrackerMethod, MiriConfig, ProvenanceMode, RetagFields, ValidationMode,
+    BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType,ProvenanceMode, RetagFields, ValidationMode,
 };
 use rustc_abi::ExternAbi;
 use rustc_data_structures::sync;
@@ -51,7 +51,7 @@ use rustc_middle::query::LocalCrate;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::util::Providers;
-use rustc_session::config::{CrateType, EntryFnType, ErrorOutputType, OptLevel};
+use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
 use rustc_span::def_id::DefId;
@@ -73,9 +73,9 @@ impl MiriCompilerCalls {
     }
 }
 
-fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) {
-    if let Some(entry_def) = tcx.entry_fn(()) {
-        return entry_def;
+fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) {
+    if let Some((def_id, entry_type)) = tcx.entry_fn(()) {
+        return (def_id, MiriEntryFnType::Rustc(entry_type));
     }
     // Look for a symbol in the local crate named `miri_start`, and treat that as the entry point.
     let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
@@ -102,7 +102,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) {
         .is_ok();
 
         if correct_func_sig {
-            (*id, EntryFnType::Start)
+            (*id, MiriEntryFnType::MiriStart)
         } else {
             tcx.dcx().fatal(
                 "`miri_start` must have the following signature:\n\
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index eaf4b30c66069..c8f04e252072e 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -19,6 +19,12 @@ use crate::diagnostics::report_leaks;
 use crate::shims::tls;
 use crate::*;
 
+#[derive(Copy, Clone, Debug)]
+pub enum MiriEntryFnType {
+    MiriStart,
+    Rustc(EntryFnType),
+}
+
 /// When the main thread would exit, we will yield to any other thread that is ready to execute.
 /// But we must only do that a finite number of times, or a background thread running `loop {}`
 /// will hang the program.
@@ -272,7 +278,7 @@ impl<'tcx> MainThreadState<'tcx> {
 pub fn create_ecx<'tcx>(
     tcx: TyCtxt<'tcx>,
     entry_id: DefId,
-    entry_type: EntryFnType,
+    entry_type: MiriEntryFnType,
     config: &MiriConfig,
 ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
     let typing_env = ty::TypingEnv::fully_monomorphized();
@@ -300,7 +306,7 @@ pub fn create_ecx<'tcx>(
     // Setup first stack frame.
     let entry_instance = ty::Instance::mono(tcx, entry_id);
 
-    // First argument is constructed later, because it's skipped if the entry function uses #[start].
+    // First argument is constructed later, because it's skipped for `miri_start.`
 
     // Second argument (argc): length of `config.args`.
     let argc =
@@ -373,11 +379,9 @@ pub fn create_ecx<'tcx>(
     // Call start function.
 
     match entry_type {
-        EntryFnType::Main { .. } => {
+        MiriEntryFnType::Rustc(EntryFnType::Main { .. }) => {
             let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| {
-                tcx.dcx().fatal(
-                    "could not find start function. Make sure the entry point is marked with `#[start]`."
-                );
+                tcx.dcx().fatal("could not find start lang item");
             });
             let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
             let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
@@ -413,7 +417,7 @@ pub fn create_ecx<'tcx>(
                 StackPopCleanup::Root { cleanup: true },
             )?;
         }
-        EntryFnType::Start => {
+        MiriEntryFnType::MiriStart => {
             ecx.call_function(
                 entry_instance,
                 ExternAbi::Rust,
@@ -434,7 +438,7 @@ pub fn create_ecx<'tcx>(
 pub fn eval_entry<'tcx>(
     tcx: TyCtxt<'tcx>,
     entry_id: DefId,
-    entry_type: EntryFnType,
+    entry_type: MiriEntryFnType,
     config: MiriConfig,
 ) -> Option<i32> {
     // Copy setting before we move `config`.
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index e02d51afceff0..381fd2944812e 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -133,8 +133,8 @@ pub use crate::diagnostics::{
     EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error,
 };
 pub use crate::eval::{
-    AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, ValidationMode,
-    create_ecx, eval_entry,
+    AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith,
+    ValidationMode, create_ecx, eval_entry,
 };
 pub use crate::helpers::{AccessKind, EvalContextExt as _};
 pub use crate::intrinsics::EvalContextExt as _;
diff --git a/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs b/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs
index 3a207b7d50aa2..d9f1b27bf553e 100644
--- a/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs
+++ b/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs
@@ -1,6 +1,5 @@
 // Copied from tests/pass/no-std.rs
 
-#![feature(start)]
 #![no_std]
 
 // Plumbing to let us use `writeln!` to host stdout:
@@ -22,8 +21,8 @@ impl Write for Host {
     }
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_: isize, _: *const *const u8) -> isize {
     writeln!(Host, "hello, world!").unwrap();
     0
 }
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs
index babdb73f093a1..8d41002735cc9 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs
@@ -1,8 +1,9 @@
 //@compile-flags: -Cpanic=abort
-#![feature(start, core_intrinsics)]
+#![feature(core_intrinsics)]
 #![feature(alloc_error_handler)]
 #![feature(allocator_api)]
 #![no_std]
+#![no_main]
 
 extern crate alloc;
 
@@ -43,7 +44,7 @@ mod plumbing {
     static GLOBAL: NoAlloc = NoAlloc;
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     handle_alloc_error(Layout::for_value(&0));
 }
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr
index d12e119bce3dd..1a9e757433994 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr
@@ -16,7 +16,7 @@ LL | fn alloc_error_handler(layout: Layout) -> ! {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `start`
+note: inside `miri_start`
   --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC
    |
 LL |     handle_alloc_error(Layout::for_value(&0));
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs
index 18a8a61f22f65..f73f8e3e7e196 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs
@@ -1,8 +1,9 @@
 //@compile-flags: -Cpanic=abort
-#![feature(start, core_intrinsics)]
+#![feature(core_intrinsics)]
 #![feature(alloc_error_handler)]
 #![feature(allocator_api)]
 #![no_std]
+#![no_main]
 
 extern crate alloc;
 
@@ -41,7 +42,7 @@ mod plumbing {
     static GLOBAL: NoAlloc = NoAlloc;
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     handle_alloc_error(Layout::for_value(&0));
 }
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr
index f495d65a8b017..6b4266b9a8b5d 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr
@@ -12,7 +12,7 @@ LL |     core::intrinsics::abort();
    = note: inside `alloc::alloc::__alloc_error_handler::__rdl_oom` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `start`
+note: inside `miri_start`
   --> tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC
    |
 LL |     handle_alloc_error(Layout::for_value(&0));
diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.rs b/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
index 0952b2c46bac6..f76aebaa3e37e 100644
--- a/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
+++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
@@ -2,15 +2,15 @@
 //@normalize-stderr-test: "OS `.*`" -> "$$OS"
 // Make sure we pretend the allocation symbols don't exist when there is no allocator
 
-#![feature(start)]
 #![no_std]
+#![no_main]
 
 extern "Rust" {
     fn __rust_alloc(size: usize, align: usize) -> *mut u8;
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     unsafe {
         __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function `__rust_alloc`
     }
diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
index e08a747f7fafc..541af64b894da 100644
--- a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
+++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
@@ -7,7 +7,7 @@ LL |         __rust_alloc(1, 1);
    = help: if this is a basic API commonly used on this target, please report an issue with Miri
    = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
    = note: BACKTRACE:
-   = note: inside `start` at tests/fail/alloc/no_global_allocator.rs:LL:CC
+   = note: inside `miri_start` at tests/fail/alloc/no_global_allocator.rs:LL:CC
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/panic/no_std.rs b/src/tools/miri/tests/fail/panic/no_std.rs
index 4d32b6d746190..cd8a3251fef20 100644
--- a/src/tools/miri/tests/fail/panic/no_std.rs
+++ b/src/tools/miri/tests/fail/panic/no_std.rs
@@ -1,14 +1,15 @@
 //@compile-flags: -Cpanic=abort
-#![feature(start, core_intrinsics)]
+#![feature(core_intrinsics)]
 #![no_std]
+#![no_main]
 
 use core::fmt::Write;
 
 #[path = "../../utils/mod.no_std.rs"]
 mod utils;
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     panic!("blarg I am dead")
 }
 
diff --git a/src/tools/miri/tests/fail/panic/no_std.stderr b/src/tools/miri/tests/fail/panic/no_std.stderr
index c1cd53e310f9a..d54f2a58776a8 100644
--- a/src/tools/miri/tests/fail/panic/no_std.stderr
+++ b/src/tools/miri/tests/fail/panic/no_std.stderr
@@ -8,7 +8,7 @@ LL |     core::intrinsics::abort();
    |
    = note: BACKTRACE:
    = note: inside `panic_handler` at tests/fail/panic/no_std.rs:LL:CC
-note: inside `start`
+note: inside `miri_start`
   --> tests/fail/panic/no_std.rs:LL:CC
    |
 LL |     panic!("blarg I am dead")
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs
index 50e217918b060..c47063bef03c7 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.rs
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs
@@ -1,5 +1,5 @@
-#![feature(start)]
 #![no_std]
+#![no_main]
 //@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort
 //@normalize-stderr-test: "id 21" -> "id $$ALLOC"
 //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations)
@@ -9,8 +9,8 @@ extern "Rust" {
     fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     unsafe {
         let ptr = miri_alloc(123, 1);
         *ptr = 42; // Crucially, only a write is printed here, no read!
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.stderr b/src/tools/miri/tests/pass/alloc-access-tracking.stderr
index 451f5de25d3b1..0c85afd831b6a 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.stderr
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.stderr
@@ -5,7 +5,7 @@ LL |         let ptr = miri_alloc(123, 1);
    |                   ^^^^^^^^^^^^^^^^^^ created Miri bare-metal heap allocation of 123 bytes (alignment ALIGN bytes) with id $ALLOC
    |
    = note: BACKTRACE:
-   = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
+   = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
 
 note: tracking was triggered
   --> tests/pass/alloc-access-tracking.rs:LL:CC
@@ -14,7 +14,7 @@ LL |         *ptr = 42; // Crucially, only a write is printed here, no read!
    |         ^^^^^^^^^ write access to allocation with id $ALLOC
    |
    = note: BACKTRACE:
-   = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
+   = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
 
 note: tracking was triggered
   --> tests/pass/alloc-access-tracking.rs:LL:CC
@@ -23,7 +23,7 @@ LL |         assert_eq!(*ptr, 42);
    |         ^^^^^^^^^^^^^^^^^^^^ read access to allocation with id $ALLOC
    |
    = note: BACKTRACE:
-   = note: inside `start` at RUSTLIB/core/src/macros/mod.rs:LL:CC
+   = note: inside `miri_start` at RUSTLIB/core/src/macros/mod.rs:LL:CC
    = note: this note originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: tracking was triggered
@@ -33,5 +33,5 @@ LL |         miri_dealloc(ptr, 123, 1);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ freed allocation with id $ALLOC
    |
    = note: BACKTRACE:
-   = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
+   = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
 
diff --git a/src/tools/miri/tests/pass/miri-alloc.rs b/src/tools/miri/tests/pass/miri-alloc.rs
index 17f6d5d05a529..20269d8ced039 100644
--- a/src/tools/miri/tests/pass/miri-alloc.rs
+++ b/src/tools/miri/tests/pass/miri-alloc.rs
@@ -1,5 +1,5 @@
-#![feature(start)]
 #![no_std]
+#![no_main]
 //@compile-flags: -Cpanic=abort
 // windows tls dtors go through libstd right now, thus this test
 // cannot pass. When windows tls dtors go through the special magic
@@ -11,8 +11,8 @@ extern "Rust" {
     fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     unsafe {
         let ptr = miri_alloc(123, 1);
         core::ptr::write_bytes(ptr, 0u8, 123);
diff --git a/src/tools/miri/tests/pass/miri_start.stdout b/src/tools/miri/tests/pass/miri_start.stdout
deleted file mode 100644
index 1c9e8489b575c..0000000000000
--- a/src/tools/miri/tests/pass/miri_start.stdout
+++ /dev/null
@@ -1 +0,0 @@
-Hello from miri_start!
diff --git a/src/tools/miri/tests/pass/no_std.rs b/src/tools/miri/tests/pass/no_std.rs
deleted file mode 100644
index fc1c16f5fb956..0000000000000
--- a/src/tools/miri/tests/pass/no_std.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//@compile-flags: -Cpanic=abort
-#![feature(start)]
-#![no_std]
-
-use core::fmt::Write;
-
-#[path = "../utils/mod.no_std.rs"]
-mod utils;
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    writeln!(utils::MiriStdout, "hello, world!").unwrap();
-    0
-}
-
-#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
diff --git a/src/tools/miri/tests/pass/miri_start.rs b/src/tools/miri/tests/pass/no_std_miri_start.rs
similarity index 81%
rename from src/tools/miri/tests/pass/miri_start.rs
rename to src/tools/miri/tests/pass/no_std_miri_start.rs
index 756a1f60be151..cf9636b9d8c2c 100644
--- a/src/tools/miri/tests/pass/miri_start.rs
+++ b/src/tools/miri/tests/pass/no_std_miri_start.rs
@@ -1,6 +1,6 @@
 //@compile-flags: -Cpanic=abort
-#![no_main]
 #![no_std]
+#![no_main]
 
 use core::fmt::Write;
 
@@ -9,7 +9,7 @@ mod utils;
 
 #[no_mangle]
 fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
-    writeln!(utils::MiriStdout, "Hello from miri_start!").unwrap();
+    writeln!(utils::MiriStdout, "hello, world!").unwrap();
     0
 }
 
diff --git a/src/tools/miri/tests/pass/no_std.stdout b/src/tools/miri/tests/pass/no_std_miri_start.stdout
similarity index 100%
rename from src/tools/miri/tests/pass/no_std.stdout
rename to src/tools/miri/tests/pass/no_std_miri_start.stdout
diff --git a/src/tools/miri/tests/pass/start.rs b/src/tools/miri/tests/pass/start.rs
deleted file mode 100644
index f25d62fa8c335..0000000000000
--- a/src/tools/miri/tests/pass/start.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(start)]
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    println!("Hello from start!");
-
-    0
-}
diff --git a/src/tools/miri/tests/pass/start.stdout b/src/tools/miri/tests/pass/start.stdout
deleted file mode 100644
index d7f627d237c3e..0000000000000
--- a/src/tools/miri/tests/pass/start.stdout
+++ /dev/null
@@ -1 +0,0 @@
-Hello from start!
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 54de2ef83148f..de3380502bfcd 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -183,7 +183,6 @@ ui/async-await/issue-67252-unnamed-future.rs
 ui/async-await/issue-67651.rs
 ui/async-await/issue-67765-async-diagnostic.rs
 ui/async-await/issue-68112.rs
-ui/async-await/issue-68523-start.rs
 ui/async-await/issue-68523.rs
 ui/async-await/issue-69446-fnmut-capture.rs
 ui/async-await/issue-70594.rs
@@ -2395,7 +2394,6 @@ ui/issues/issue-50618.rs
 ui/issues/issue-5062.rs
 ui/issues/issue-5067.rs
 ui/issues/issue-50688.rs
-ui/issues/issue-50714-1.rs
 ui/issues/issue-50714.rs
 ui/issues/issue-50761.rs
 ui/issues/issue-50781.rs
@@ -2630,7 +2628,6 @@ ui/issues/issue-9259.rs
 ui/issues/issue-92741.rs
 ui/issues/issue-9382.rs
 ui/issues/issue-9446.rs
-ui/issues/issue-9575.rs
 ui/issues/issue-9719.rs
 ui/issues/issue-9725.rs
 ui/issues/issue-9737.rs
@@ -2645,7 +2642,6 @@ ui/issues/issue-9968.rs
 ui/issues/issue-99838.rs
 ui/iterators/issue-28098.rs
 ui/iterators/issue-58952-filter-type-length.rs
-ui/lang-items/issue-19660.rs
 ui/lang-items/issue-83471.rs
 ui/lang-items/issue-87573.rs
 ui/late-bound-lifetimes/issue-36381.rs
@@ -3702,7 +3698,6 @@ ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs
 ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs
 ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs
 ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs
-ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs
 ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs
 ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs
 ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 401169c838f71..908cf9f324fbc 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1667;
+const ISSUES_ENTRY_LIMIT: u32 = 1663;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/codegen-units/item-collection/cross-crate-closures.rs b/tests/codegen-units/item-collection/cross-crate-closures.rs
index cb86cf18c0cf2..75a77cc2671dc 100644
--- a/tests/codegen-units/item-collection/cross-crate-closures.rs
+++ b/tests/codegen-units/item-collection/cross-crate-closures.rs
@@ -3,14 +3,14 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![no_main]
 
 //@ aux-build:cgu_extern_closures.rs
 extern crate cgu_extern_closures;
 
-//~ MONO_ITEM fn start @@ cross_crate_closures-cgu.0[Internal]
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+//~ MONO_ITEM fn main @@ cross_crate_closures-cgu.0[External]
+#[no_mangle]
+extern "C" fn main(_: core::ffi::c_int, _: *const *const u8) -> core::ffi::c_int {
     //~ MONO_ITEM fn cgu_extern_closures::inlined_fn @@ cross_crate_closures-cgu.0[Internal]
     //~ MONO_ITEM fn cgu_extern_closures::inlined_fn::{closure#0} @@ cross_crate_closures-cgu.0[Internal]
     let _ = cgu_extern_closures::inlined_fn(1, 2);
diff --git a/tests/codegen-units/item-collection/cross-crate-generic-functions.rs b/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
index d36f7067b3277..4382bfdf8d81d 100644
--- a/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
+++ b/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
@@ -1,14 +1,14 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //@ aux-build:cgu_generic_function.rs
 extern crate cgu_generic_function;
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn cgu_generic_function::bar::<u32>
     //~ MONO_ITEM fn cgu_generic_function::foo::<u32>
     let _ = cgu_generic_function::foo(1u32);
diff --git a/tests/codegen-units/item-collection/cross-crate-trait-method.rs b/tests/codegen-units/item-collection/cross-crate-trait-method.rs
index 9977776031559..917354166f54e 100644
--- a/tests/codegen-units/item-collection/cross-crate-trait-method.rs
+++ b/tests/codegen-units/item-collection/cross-crate-trait-method.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no -Copt-level=0
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //@ aux-build:cgu_export_trait_method.rs
 extern crate cgu_export_trait_method;
@@ -9,8 +9,8 @@ extern crate cgu_export_trait_method;
 use cgu_export_trait_method::Trait;
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub 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);
diff --git a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
index d87ad41e70d58..e1887b93b93a0 100644
--- a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 //@ compile-flags:-Zinline-mir=no
 
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDtor> - shim(Some(StructWithDtor)) @@ drop_in_place_intrinsic-cgu.0[Internal]
 struct StructWithDtor(u32);
@@ -14,8 +14,8 @@ impl Drop for StructWithDtor {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn std::ptr::drop_in_place::<[StructWithDtor; 2]> - shim(Some([StructWithDtor; 2])) @@ drop_in_place_intrinsic-cgu.0[Internal]
     let x = [StructWithDtor(0), StructWithDtor(1)];
 
diff --git a/tests/codegen-units/item-collection/function-as-argument.rs b/tests/codegen-units/item-collection/function-as-argument.rs
index 4be713dc3673b..146a53bb9119d 100644
--- a/tests/codegen-units/item-collection/function-as-argument.rs
+++ b/tests/codegen-units/item-collection/function-as-argument.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 fn take_fn_once<T1, T2, F: FnOnce(T1, T2)>(f: F, x: T1, y: T2) {
     (f)(x, y)
@@ -14,8 +14,8 @@ fn take_fn_pointer<T1, T2>(f: fn(T1, T2), x: T1, y: T2) {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn take_fn_once::<u32, &str, fn(u32, &str) {function::<u32, &str>}>
     //~ MONO_ITEM fn function::<u32, &str>
     //~ MONO_ITEM fn <fn(u32, &str) {function::<u32, &str>} as std::ops::FnOnce<(u32, &str)>>::call_once - shim(fn(u32, &str) {function::<u32, &str>})
diff --git a/tests/codegen-units/item-collection/generic-drop-glue.rs b/tests/codegen-units/item-collection/generic-drop-glue.rs
index d861d269fae4a..6ecf98a032f52 100644
--- a/tests/codegen-units/item-collection/generic-drop-glue.rs
+++ b/tests/codegen-units/item-collection/generic-drop-glue.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 struct StructWithDrop<T1, T2> {
     x: T1,
@@ -44,8 +44,8 @@ impl Drop for NonGenericWithDrop {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDrop<i8, char>> - shim(Some(StructWithDrop<i8, char>)) @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn <StructWithDrop<i8, char> as std::ops::Drop>::drop
     let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
diff --git a/tests/codegen-units/item-collection/generic-functions.rs b/tests/codegen-units/item-collection/generic-functions.rs
index 2d7c70c9c4c77..4a890790702ad 100644
--- a/tests/codegen-units/item-collection/generic-functions.rs
+++ b/tests/codegen-units/item-collection/generic-functions.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 fn foo1<T1>(a: T1) -> (T1, u32) {
     (a, 1)
@@ -22,8 +22,8 @@ pub fn lifetime_only<'a>(a: &'a u32) -> &'a u32 {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn foo1::<i32>
     let _ = foo1(2i32);
     //~ MONO_ITEM fn foo1::<i64>
diff --git a/tests/codegen-units/item-collection/generic-impl.rs b/tests/codegen-units/item-collection/generic-impl.rs
index f6e49f6e6dfc3..5a43bd64b2ac6 100644
--- a/tests/codegen-units/item-collection/generic-impl.rs
+++ b/tests/codegen-units/item-collection/generic-impl.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 struct Struct<T> {
     x: T,
@@ -38,8 +38,8 @@ impl<'a> LifeTimeOnly<'a> {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn Struct::<i32>::new
     //~ MONO_ITEM fn id::<i32>
     //~ MONO_ITEM fn Struct::<i32>::get::<i16>
diff --git a/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs b/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
index 0b7f30187b586..d916fa6a8254c 100644
--- a/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
+++ b/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 trait SomeTrait {
     fn foo(&self);
@@ -19,8 +19,8 @@ pub fn generic_function<T>(x: T) -> (T, i32) {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     0i64.foo();
 
     0
diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs
index 59dd4311a03b2..9087fc6410ab5 100644
--- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -2,7 +2,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-in-all-cgus -Zmir-opt-level=0
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 trait Trait {
     fn foo(&self) -> u32;
@@ -21,8 +21,8 @@ impl<T> Trait for Struct<T> {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     let s1 = Struct { _a: 0u32 };
 
     //~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u32>> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal]
diff --git a/tests/codegen-units/item-collection/items-within-generic-items.rs b/tests/codegen-units/item-collection/items-within-generic-items.rs
index 7798d2b46d22a..56d21d5895c83 100644
--- a/tests/codegen-units/item-collection/items-within-generic-items.rs
+++ b/tests/codegen-units/item-collection/items-within-generic-items.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Copt-level=0
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 fn generic_fn<T>(a: T) -> (T, i32) {
     //~ MONO_ITEM fn generic_fn::nested_fn
@@ -22,8 +22,8 @@ fn generic_fn<T>(a: T) -> (T, i32) {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn generic_fn::<i64>
     let _ = generic_fn(0i64);
     //~ MONO_ITEM fn generic_fn::<u16>
diff --git a/tests/codegen-units/item-collection/non-generic-closures.rs b/tests/codegen-units/item-collection/non-generic-closures.rs
index 8847a249b1ea8..4dbc0b62b9785 100644
--- a/tests/codegen-units/item-collection/non-generic-closures.rs
+++ b/tests/codegen-units/item-collection/non-generic-closures.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn temporary @@ non_generic_closures-cgu.0[Internal]
 fn temporary() {
@@ -40,9 +40,9 @@ fn assigned_to_variable_executed_directly() {
     f(4);
 }
 
-//~ MONO_ITEM fn start @@ non_generic_closures-cgu.0[Internal]
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+//~ MONO_ITEM fn start @@ non_generic_closures-cgu.0[External]
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     temporary();
     assigned_to_variable_but_not_executed();
     assigned_to_variable_executed_directly();
diff --git a/tests/codegen-units/item-collection/non-generic-drop-glue.rs b/tests/codegen-units/item-collection/non-generic-drop-glue.rs
index f7bb2f3f2f4d1..c4d7942ba1ed9 100644
--- a/tests/codegen-units/item-collection/non-generic-drop-glue.rs
+++ b/tests/codegen-units/item-collection/non-generic-drop-glue.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDrop> - shim(Some(StructWithDrop)) @@ non_generic_drop_glue-cgu.0[Internal]
 struct StructWithDrop {
@@ -34,8 +34,8 @@ enum EnumNoDrop {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     let _ = StructWithDrop { x: 0 }.x;
     let _ = StructNoDrop { x: 0 }.x;
     let _ = match EnumWithDrop::A(0) {
diff --git a/tests/codegen-units/item-collection/non-generic-functions.rs b/tests/codegen-units/item-collection/non-generic-functions.rs
index d4d7d221827d8..4b86b1088f1ba 100644
--- a/tests/codegen-units/item-collection/non-generic-functions.rs
+++ b/tests/codegen-units/item-collection/non-generic-functions.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn foo
 fn foo() {
@@ -62,8 +62,8 @@ impl Struct {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     foo();
     bar();
     Struct::foo();
diff --git a/tests/codegen-units/item-collection/static-init.rs b/tests/codegen-units/item-collection/static-init.rs
index 44b80ef73a404..5e3d06790a2d6 100644
--- a/tests/codegen-units/item-collection/static-init.rs
+++ b/tests/codegen-units/item-collection/static-init.rs
@@ -1,16 +1,16 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
-#![feature(start)]
+#![crate_type = "lib"]
 
-pub static FN: fn() = foo::<i32>;
+static FN: fn() = foo::<i32>;
 
-pub fn foo<T>() {}
+fn foo<T>() {}
 
 //~ MONO_ITEM fn foo::<i32>
 //~ MONO_ITEM static FN
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     0
 }
diff --git a/tests/codegen-units/item-collection/statics-and-consts.rs b/tests/codegen-units/item-collection/statics-and-consts.rs
index 1e3782f0c6e6d..54297a4085131 100644
--- a/tests/codegen-units/item-collection/statics-and-consts.rs
+++ b/tests/codegen-units/item-collection/statics-and-consts.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 static STATIC1: i64 = {
     const STATIC1_CONST1: i64 = 2;
@@ -38,8 +38,8 @@ fn foo() {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     foo();
     let _ = STATIC1;
 
diff --git a/tests/codegen-units/item-collection/trait-implementations.rs b/tests/codegen-units/item-collection/trait-implementations.rs
index e4c444499e05e..3b67d4f22bd2a 100644
--- a/tests/codegen-units/item-collection/trait-implementations.rs
+++ b/tests/codegen-units/item-collection/trait-implementations.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 pub trait SomeTrait {
     fn foo(&self);
@@ -42,8 +42,8 @@ impl<T> SomeGenericTrait<T> for f32 {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn <i32 as SomeTrait>::bar::<char>
     0i32.bar('x');
 
diff --git a/tests/codegen-units/item-collection/trait-method-as-argument.rs b/tests/codegen-units/item-collection/trait-method-as-argument.rs
index 10cf2a0e967e2..d425ea199888a 100644
--- a/tests/codegen-units/item-collection/trait-method-as-argument.rs
+++ b/tests/codegen-units/item-collection/trait-method-as-argument.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 trait Trait: Sized {
     fn foo(self) -> Self {
@@ -30,8 +30,8 @@ fn take_foo_mut<T, F: FnMut(T) -> T>(mut f: F, arg: T) -> T {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn take_foo_once::<u32, fn(u32) -> u32 {<u32 as Trait>::foo}>
     //~ MONO_ITEM fn <u32 as Trait>::foo
     //~ MONO_ITEM fn <fn(u32) -> u32 {<u32 as Trait>::foo} as std::ops::FnOnce<(u32,)>>::call_once - shim(fn(u32) -> u32 {<u32 as Trait>::foo})
diff --git a/tests/codegen-units/item-collection/trait-method-default-impl.rs b/tests/codegen-units/item-collection/trait-method-default-impl.rs
index fd73786a40216..cd0a4b8903171 100644
--- a/tests/codegen-units/item-collection/trait-method-default-impl.rs
+++ b/tests/codegen-units/item-collection/trait-method-default-impl.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 trait SomeTrait {
     fn foo(&self) {}
@@ -39,8 +39,8 @@ impl<T1> SomeGenericTrait<T1> for u32 {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn <i8 as SomeTrait>::bar::<char>
     let _ = 1i8.bar('c');
 
diff --git a/tests/codegen-units/item-collection/transitive-drop-glue.rs b/tests/codegen-units/item-collection/transitive-drop-glue.rs
index 7c879dee1a199..18954fab86f66 100644
--- a/tests/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/tests/codegen-units/item-collection/transitive-drop-glue.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Root> - shim(Some(Root)) @@ transitive_drop_glue-cgu.0[Internal]
 struct Root(#[allow(dead_code)] Intermediate);
@@ -26,8 +26,8 @@ impl<T> Drop for LeafGen<T> {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     let _ = Root(Intermediate(Leaf));
 
     //~ MONO_ITEM fn std::ptr::drop_in_place::<RootGen<u32>> - shim(Some(RootGen<u32>)) @@ transitive_drop_glue-cgu.0[Internal]
diff --git a/tests/codegen-units/item-collection/tuple-drop-glue.rs b/tests/codegen-units/item-collection/tuple-drop-glue.rs
index 9d8b0cdd3844a..2e70d0151eb7c 100644
--- a/tests/codegen-units/item-collection/tuple-drop-glue.rs
+++ b/tests/codegen-units/item-collection/tuple-drop-glue.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Dropped> - shim(Some(Dropped)) @@ tuple_drop_glue-cgu.0[Internal]
 struct Dropped;
@@ -14,8 +14,8 @@ impl Drop for Dropped {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn std::ptr::drop_in_place::<(u32, Dropped)> - shim(Some((u32, Dropped))) @@ tuple_drop_glue-cgu.0[Internal]
     let x = (0u32, Dropped);
 
diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs
index 5ea8b47962a84..23e6003dc19fd 100644
--- a/tests/codegen-units/item-collection/unsizing.rs
+++ b/tests/codegen-units/item-collection/unsizing.rs
@@ -5,7 +5,7 @@
 #![deny(dead_code)]
 #![feature(coerce_unsized)]
 #![feature(unsize)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 use std::marker::Unsize;
 use std::ops::CoerceUnsized;
@@ -45,8 +45,8 @@ struct Wrapper<T: ?Sized>(#[allow(dead_code)] *const T);
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     // simple case
     let bool_sized = &true;
     //~ MONO_ITEM fn std::ptr::drop_in_place::<bool> - shim(None) @@ unsizing-cgu.0[Internal]
diff --git a/tests/codegen-units/partitioning/methods-are-with-self-type.rs b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
index 7c9045e8f1a76..94d06829c6c35 100644
--- a/tests/codegen-units/partitioning/methods-are-with-self-type.rs
+++ b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
@@ -46,6 +46,7 @@ mod type2 {
 }
 
 //~ MONO_ITEM fn start @@ methods_are_with_self_type[External]
+#[no_mangle]
 pub fn start() {
     //~ MONO_ITEM fn mod1::<impl SomeGenericType<u32, u64>>::method @@ methods_are_with_self_type.volatile[External]
     SomeGenericType(0u32, 0u64).method();
diff --git a/tests/codegen-units/partitioning/vtable-through-const.rs b/tests/codegen-units/partitioning/vtable-through-const.rs
index a9186cea9c89b..3880bba6f6b32 100644
--- a/tests/codegen-units/partitioning/vtable-through-const.rs
+++ b/tests/codegen-units/partitioning/vtable-through-const.rs
@@ -2,11 +2,13 @@
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 //@ compile-flags:-Zinline-in-all-cgus
+// Need to disable optimizations to ensure consistent output across all CI runners.
+//@ compile-flags:-Copt-level=0
 
 // This test case makes sure, that references made through constants are
 // recorded properly in the InliningMap.
 
-#![feature(start)]
+#![crate_type = "lib"]
 
 mod mod1 {
     struct NeedsDrop;
@@ -51,8 +53,8 @@ mod mod1 {
         fn do_something_else(&self) {}
     }
 
-    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something @@ vtable_through_const-mod1.volatile[Internal]
-    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something_else @@ vtable_through_const-mod1.volatile[Internal]
+    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something @@ vtable_through_const-mod1.volatile[External]
+    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something_else @@ vtable_through_const-mod1.volatile[External]
     impl Trait2 for NeedsDrop {}
 
     pub trait Trait2Gen<T> {
@@ -76,9 +78,9 @@ mod mod1 {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn <mod1::NeedsDrop as std::ops::Drop>::drop @@ vtable_through_const-fallback.cgu[Internal]
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
+    //~ MONO_ITEM fn <mod1::NeedsDrop as std::ops::Drop>::drop @@ vtable_through_const-fallback.cgu[External]
     //~ MONO_ITEM fn std::ptr::drop_in_place::<mod1::NeedsDrop> - shim(Some(mod1::NeedsDrop)) @@ vtable_through_const-fallback.cgu[External]
 
     // Since Trait1::do_something() is instantiated via its default implementation,
@@ -95,8 +97,8 @@ fn start(_: isize, _: *const *const u8) -> isize {
     // Same as above
     //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait1Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[External]
     //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait1Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[External]
-    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[Internal]
-    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[Internal]
+    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[External]
+    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[External]
     mod1::TRAIT1_GEN_REF.do_something(0u8);
 
     //~ MONO_ITEM fn mod1::id::<char> @@ vtable_through_const-mod1.volatile[External]
diff --git a/tests/codegen/gdb_debug_script_load.rs b/tests/codegen/gdb_debug_script_load.rs
index 30d518c0bcb83..3e92eba10b121 100644
--- a/tests/codegen/gdb_debug_script_load.rs
+++ b/tests/codegen/gdb_debug_script_load.rs
@@ -4,14 +4,34 @@
 //@ ignore-wasm
 //@ ignore-emscripten
 
-//@ compile-flags: -g -C no-prepopulate-passes
+//@ compile-flags: -g -C no-prepopulate-passes -Cpanic=abort
 
-#![feature(start)]
+#![feature(lang_items)]
+#![no_std]
 
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[no_mangle]
+extern "C" fn rust_eh_personality() {
+    loop {}
+}
+
+// Needs rustc to generate `main` as that's where the magic load is inserted.
+// IOW, we cannot write this test with `#![no_main]`.
 // CHECK-LABEL: @main
 // CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[lang = "start"]
+fn lang_start<T: 'static>(
+    _main: fn() -> T,
+    _argc: isize,
+    _argv: *const *const u8,
+    _sigpipe: u8,
+) -> isize {
     return 0;
 }
+
+fn main() {}
diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs
deleted file mode 100644
index 0bcb311644d07..0000000000000
--- a/tests/codegen/mainsubprogramstart.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ ignore-apple
-//@ ignore-wasi wasi codegens the main symbol differently
-
-//@ compile-flags: -g -C no-prepopulate-passes
-
-#![feature(start)]
-
-// CHECK-LABEL: @main
-// CHECK: {{.*}}DISubprogram{{.*}}name: "start",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    return 0;
-}
diff --git a/tests/run-make/crate-circular-deps-link/c.rs b/tests/run-make/crate-circular-deps-link/c.rs
index 9d72657aa593e..cfe00a2a34783 100644
--- a/tests/run-make/crate-circular-deps-link/c.rs
+++ b/tests/run-make/crate-circular-deps-link/c.rs
@@ -1,5 +1,5 @@
 #![crate_type = "bin"]
-#![feature(start)]
+#![no_main]
 #![no_std]
 
 extern crate a;
@@ -24,8 +24,8 @@ unsafe impl GlobalAlloc for Allocator {
 #[global_allocator]
 static ALLOCATOR: Allocator = Allocator;
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let mut v = Vec::new();
     for i in 0..argc {
         v.push(i);
diff --git a/tests/run-make/fmt-write-bloat/main.rs b/tests/run-make/fmt-write-bloat/main.rs
index 6f206d6515a37..b50461c0a0279 100644
--- a/tests/run-make/fmt-write-bloat/main.rs
+++ b/tests/run-make/fmt-write-bloat/main.rs
@@ -1,5 +1,5 @@
 #![feature(lang_items)]
-#![feature(start)]
+#![no_main]
 #![no_std]
 
 use core::fmt;
@@ -17,8 +17,8 @@ impl fmt::Write for Dummy {
     }
 }
 
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let _ = writeln!(Dummy, "Hello World");
     0
 }
diff --git a/tests/run-make/no-alloc-shim/foo.rs b/tests/run-make/no-alloc-shim/foo.rs
index a3daec3db391a..42606961f8bb2 100644
--- a/tests/run-make/no-alloc-shim/foo.rs
+++ b/tests/run-make/no-alloc-shim/foo.rs
@@ -35,7 +35,7 @@ unsafe impl GlobalAlloc for Alloc {
 static __rust_no_alloc_shim_is_unstable: u8 = 0;
 
 #[no_mangle]
-extern "C" fn main(_argc: usize, _argv: *const *const i8) -> i32 {
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const i8) -> i32 {
     unsafe {
         assert_eq!(alloc::alloc::alloc(Layout::new::<()>()), core::ptr::null_mut());
     }
diff --git a/tests/run-make/sepcomp-inlining/foo.rs b/tests/run-make/sepcomp-inlining/foo.rs
index 2fe5f9cb72661..9101ee691a4e0 100644
--- a/tests/run-make/sepcomp-inlining/foo.rs
+++ b/tests/run-make/sepcomp-inlining/foo.rs
@@ -1,4 +1,4 @@
-#![feature(start)]
+#![crate_type = "lib"]
 
 #[inline]
 fn inlined() -> u32 {
@@ -21,8 +21,7 @@ mod b {
     }
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn start(_: isize, _: *const *const u8) -> isize {
     a::f();
     b::f();
 
diff --git a/tests/ui/array-slice-vec/vec-macro-no-std.rs b/tests/ui/array-slice-vec/vec-macro-no-std.rs
index 1b5ab536dcb2f..ea0df0bea71df 100644
--- a/tests/ui/array-slice-vec/vec-macro-no-std.rs
+++ b/tests/ui/array-slice-vec/vec-macro-no-std.rs
@@ -1,21 +1,21 @@
 //@ run-pass
-
 //@ ignore-emscripten no no_std executables
+//@ ignore-wasm different `main` convention
 
-#![feature(lang_items, start, rustc_private)]
 #![no_std]
+#![no_main]
 
+// Import global allocator and panic handler.
 extern crate std as other;
 
-#[macro_use]
-extern crate alloc;
+#[macro_use] extern crate alloc;
 
 use alloc::vec::Vec;
 
 // Issue #16806
 
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let x: Vec<u8> = vec![0, 1, 2];
     match x.last() {
         Some(&2) => (),
diff --git a/tests/ui/async-await/issue-68523-start.rs b/tests/ui/async-await/issue-68523-start.rs
deleted file mode 100644
index ee3baf4990c39..0000000000000
--- a/tests/ui/async-await/issue-68523-start.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ edition:2018
-
-#![feature(start)]
-
-#[start]
-pub async fn start(_: isize, _: *const *const u8) -> isize {
-//~^ ERROR `#[start]` function is not allowed to be `async`
-    0
-}
diff --git a/tests/ui/async-await/issue-68523-start.stderr b/tests/ui/async-await/issue-68523-start.stderr
deleted file mode 100644
index 5b76ab56e2459..0000000000000
--- a/tests/ui/async-await/issue-68523-start.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0752]: `#[start]` function is not allowed to be `async`
-  --> $DIR/issue-68523-start.rs:6:1
-   |
-LL | pub async fn start(_: isize, _: *const *const u8) -> isize {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `#[start]` is not allowed to be `async`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0752`.
diff --git a/tests/ui/attr-start.rs b/tests/ui/attr-start.rs
deleted file mode 100644
index 232f50955b2ee..0000000000000
--- a/tests/ui/attr-start.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ run-pass
-
-#![feature(start)]
-
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    return 0;
-}
diff --git a/tests/ui/duplicate/dupe-symbols-7.stderr b/tests/ui/duplicate/dupe-symbols-7.stderr
index ab9167e005a37..aa6213af2e4f5 100644
--- a/tests/ui/duplicate/dupe-symbols-7.stderr
+++ b/tests/ui/duplicate/dupe-symbols-7.stderr
@@ -4,7 +4,7 @@ error: entry symbol `main` declared multiple times
 LL | fn main(){}
    | ^^^^^^^^^
    |
-   = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+   = help: did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/duplicate/dupe-symbols-8.stderr b/tests/ui/duplicate/dupe-symbols-8.stderr
index d7d419c9aa402..0f47d3683b5a5 100644
--- a/tests/ui/duplicate/dupe-symbols-8.stderr
+++ b/tests/ui/duplicate/dupe-symbols-8.stderr
@@ -4,7 +4,7 @@ error: entry symbol `main` declared multiple times
 LL | fn main() {
    | ^^^^^^^^^
    |
-   = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+   = help: did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0132.rs b/tests/ui/error-codes/E0132.rs
deleted file mode 100644
index fb5e5d7b95a3c..0000000000000
--- a/tests/ui/error-codes/E0132.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(start)]
-
-#[start]
-fn f< T >() {} //~ ERROR E0132
-
-fn main() {
-}
diff --git a/tests/ui/error-codes/E0132.stderr b/tests/ui/error-codes/E0132.stderr
deleted file mode 100644
index b1990afa3ae18..0000000000000
--- a/tests/ui/error-codes/E0132.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0132]: `#[start]` function is not allowed to have type parameters
-  --> $DIR/E0132.rs:4:5
-   |
-LL | fn f< T >() {}
-   |     ^^^^^ `#[start]` function cannot have type parameters
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0132`.
diff --git a/tests/ui/error-codes/E0138.rs b/tests/ui/error-codes/E0138.rs
deleted file mode 100644
index 6f3c36282e884..0000000000000
--- a/tests/ui/error-codes/E0138.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
-
-#[start]
-fn f(argc: isize, argv: *const *const u8) -> isize { 0 }
-//~^ ERROR E0138
diff --git a/tests/ui/error-codes/E0138.stderr b/tests/ui/error-codes/E0138.stderr
deleted file mode 100644
index 04877ab4082cb..0000000000000
--- a/tests/ui/error-codes/E0138.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0138]: multiple `start` functions
-  --> $DIR/E0138.rs:7:1
-   |
-LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
-   | ---------------------------------------------------- previous `#[start]` function here
-...
-LL | fn f(argc: isize, argv: *const *const u8) -> isize { 0 }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0138`.
diff --git a/tests/ui/error-codes/E0647.rs b/tests/ui/error-codes/E0647.rs
deleted file mode 100644
index fc085511cbcb0..0000000000000
--- a/tests/ui/error-codes/E0647.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![no_std]
-#![feature(start)]
-
-extern crate std;
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize where (): Copy { //~ ERROR [E0647]
-    0
-}
diff --git a/tests/ui/error-codes/E0647.stderr b/tests/ui/error-codes/E0647.stderr
deleted file mode 100644
index 4b444e5a39726..0000000000000
--- a/tests/ui/error-codes/E0647.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0647]: `#[start]` function is not allowed to have a `where` clause
-  --> $DIR/E0647.rs:7:50
-   |
-LL | fn start(_: isize, _: *const *const u8) -> isize where (): Copy {
-   |                                                  ^^^^^^^^^^^^^^ `#[start]` function cannot have a `where` clause
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0647`.
diff --git a/tests/ui/extern/extern-prelude-core.rs b/tests/ui/extern/extern-prelude-core.rs
index ced1e5c391535..5108c02517c3d 100644
--- a/tests/ui/extern/extern-prelude-core.rs
+++ b/tests/ui/extern/extern-prelude-core.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-#![feature(lang_items, start)]
+#![feature(lang_items)]
 #![no_std]
 
 extern crate std as other;
@@ -11,8 +11,6 @@ mod foo {
     }
 }
 
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
+fn main() {
     foo::test();
-    0
 }
diff --git a/tests/ui/feature-gates/feature-gate-start.rs b/tests/ui/feature-gates/feature-gate-start.rs
deleted file mode 100644
index e617f1c47594d..0000000000000
--- a/tests/ui/feature-gates/feature-gate-start.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-#[start]
-fn foo(_: isize, _: *const *const u8) -> isize { 0 }
-//~^ ERROR `#[start]` functions are experimental
diff --git a/tests/ui/feature-gates/feature-gate-start.stderr b/tests/ui/feature-gates/feature-gate-start.stderr
deleted file mode 100644
index b1859c43718c8..0000000000000
--- a/tests/ui/feature-gates/feature-gate-start.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: `#[start]` functions are experimental and their signature may change over time
-  --> $DIR/feature-gate-start.rs:2:1
-   |
-LL | fn foo(_: isize, _: *const *const u8) -> isize { 0 }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #29633 <https://github.com/rust-lang/rust/issues/29633> for more information
-   = help: add `#![feature(start)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
index afffb3b144375..02a56c7e6aa6c 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -14,8 +14,6 @@
 #![rustc_main] //~ ERROR: the `#[rustc_main]` attribute is used internally to specify
 //~^ ERROR: `rustc_main` attribute cannot be used at crate level
 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-#![start]
-//~^ ERROR: `start` attribute cannot be used at crate level
 #![repr()]
 //~^ ERROR: `repr` attribute cannot be used at crate level
 #![path = "3800"]
@@ -38,7 +36,6 @@ mod inline {
     //~| NOTE the inner attribute doesn't annotate this module
     //~| NOTE the inner attribute doesn't annotate this module
     //~| NOTE the inner attribute doesn't annotate this module
-    //~| NOTE the inner attribute doesn't annotate this module
 
     mod inner { #![inline] }
     //~^ ERROR attribute should be applied to function or closure
@@ -123,24 +120,6 @@ mod export_name {
     }
 }
 
-#[start]
-//~^ ERROR: `start` attribute can only be used on functions
-mod start {
-    mod inner { #![start] }
-    //~^ ERROR: `start` attribute can only be used on functions
-
-    // for `fn f()` case, see feature-gate-start.rs
-
-    #[start] struct S;
-    //~^ ERROR: `start` attribute can only be used on functions
-
-    #[start] type T = S;
-    //~^ ERROR: `start` attribute can only be used on functions
-
-    #[start] impl S { }
-    //~^ ERROR: `start` attribute can only be used on functions
-}
-
 #[repr(C)]
 //~^ ERROR: attribute should be applied to a struct, enum, or union
 mod repr {
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index db8c5295a2daa..648bafe646094 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -8,7 +8,7 @@ LL | #![rustc_main]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5
    |
 LL |     #[inline = "2100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^
@@ -17,38 +17,8 @@ LL |     #[inline = "2100"] fn f() { }
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:126:1
-   |
-LL | #[start]
-   | ^^^^^^^^
-
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:17
-   |
-LL |     mod inner { #![start] }
-   |                 ^^^^^^^^^
-
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:134:5
-   |
-LL |     #[start] struct S;
-   |     ^^^^^^^^
-
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:5
-   |
-LL |     #[start] type T = S;
-   |     ^^^^^^^^
-
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:140:5
-   |
-LL |     #[start] impl S { }
-   |     ^^^^^^^^
-
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
    |
 LL |   #[inline]
    |   ^^^^^^^^^
@@ -59,7 +29,7 @@ LL | | }
    | |_- not a function or closure
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:66:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:1
    |
 LL |   #[no_link]
    |   ^^^^^^^^^^
@@ -73,7 +43,7 @@ LL | | }
    | |_- not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:92:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:1
    |
 LL |   #[export_name = "2200"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +57,7 @@ LL | | }
    | |_- not a free function, impl method or static
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:144:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8
    |
 LL |   #[repr(C)]
    |          ^
@@ -100,7 +70,7 @@ LL | | }
    | |_- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:168:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8
    |
 LL |   #[repr(Rust)]
    |          ^^^^
@@ -113,19 +83,19 @@ LL | | }
    | |_- not a struct, enum, or union
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1
    |
 LL | #![no_link]
    | ^^^^^^^^^^^ not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
    |
 LL | #![export_name = "2200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
    |
 LL | #![inline]
    | ^^^^^^^^^^ not a function or closure
@@ -160,23 +130,8 @@ LL - #![rustc_main]
 LL + #[rustc_main]
    |
 
-error: `start` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
-   |
-LL | #![start]
-   | ^^^^^^^^^
-...
-LL | mod inline {
-   |     ------ the inner attribute doesn't annotate this module
-   |
-help: perhaps you meant to use an outer attribute
-   |
-LL - #![start]
-LL + #[start]
-   |
-
 error: `repr` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
    |
 LL | #![repr()]
    | ^^^^^^^^^^
@@ -191,7 +146,7 @@ LL + #[repr()]
    |
 
 error: `path` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
    |
 LL | #![path = "3800"]
    | ^^^^^^^^^^^^^^^^^
@@ -206,7 +161,7 @@ LL + #[path = "3800"]
    |
 
 error: `automatically_derived` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
    |
 LL | #![automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -221,144 +176,144 @@ LL + #[automatically_derived]
    |
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:43:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17
    |
 LL |     mod inner { #![inline] }
    |     ------------^^^^^^^^^^-- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:53:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5
    |
 LL |     #[inline] struct S;
    |     ^^^^^^^^^ --------- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:57:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5
    |
 LL |     #[inline] type T = S;
    |     ^^^^^^^^^ ----------- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:61:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5
    |
 LL |     #[inline] impl S { }
    |     ^^^^^^^^^ ---------- not a function or closure
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:71:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:17
    |
 LL |     mod inner { #![no_link] }
    |     ------------^^^^^^^^^^^-- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:75:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5
    |
 LL |     #[no_link] fn f() { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:79:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5
    |
 LL |     #[no_link] struct S;
    |     ^^^^^^^^^^ --------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:83:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5
    |
 LL |     #[no_link]type T = S;
    |     ^^^^^^^^^^----------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:87:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:5
    |
 LL |     #[no_link] impl S { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:97:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:17
    |
 LL |     mod inner { #![export_name="2200"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:103:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5
    |
 LL |     #[export_name = "2200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:107:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5
    |
 LL |     #[export_name = "2200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:111:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:108:5
    |
 LL |     #[export_name = "2200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:116:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9
    |
 LL |         #[export_name = "2200"] fn foo();
    |         ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:9
    |
 LL |         #[export_name = "2200"] fn bar() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:148:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25
    |
 LL |     mod inner { #![repr(C)] }
    |     --------------------^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:152:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12
    |
 LL |     #[repr(C)] fn f() { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:158:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12
    |
 LL |     #[repr(C)] type T = S;
    |            ^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:162:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12
    |
 LL |     #[repr(C)] impl S { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:172:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25
    |
 LL |     mod inner { #![repr(Rust)] }
    |     --------------------^^^^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:176:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12
    |
 LL |     #[repr(Rust)] fn f() { }
    |            ^^^^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:182:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12
    |
 LL |     #[repr(Rust)] type T = S;
    |            ^^^^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:186:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12
    |
 LL |     #[repr(Rust)] impl S { }
    |            ^^^^   ---------- not a struct, enum, or union
 
-error: aborting due to 44 previous errors
+error: aborting due to 38 previous errors
 
 Some errors have detailed explanations: E0517, E0518, E0658.
 For more information about an error, try `rustc --explain E0517`.
diff --git a/tests/ui/for-loop-while/for-loop-no-std.rs b/tests/ui/for-loop-while/for-loop-no-std.rs
index 4511146dc75f4..8255d7b4200c0 100644
--- a/tests/ui/for-loop-while/for-loop-no-std.rs
+++ b/tests/ui/for-loop-while/for-loop-no-std.rs
@@ -1,14 +1,19 @@
 //@ run-pass
+//@ ignore-emscripten no no_std executables
+//@ ignore-wasm different `main` convention
 #![allow(unused_imports)]
-#![feature(lang_items, start)]
 #![no_std]
+#![no_main]
 
+// Import global allocator and panic handler.
 extern crate std as other;
 
 #[macro_use] extern crate alloc;
 
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
+use alloc::string::ToString;
+
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     for _ in [1,2,3].iter() { }
     0
 }
diff --git a/tests/ui/format-no-std.rs b/tests/ui/format-no-std.rs
index 27c31f48a006c..657b210a9a0b4 100644
--- a/tests/ui/format-no-std.rs
+++ b/tests/ui/format-no-std.rs
@@ -1,17 +1,20 @@
 //@ run-pass
 //@ ignore-emscripten no no_std executables
+//@ ignore-wasm different `main` convention
 
-#![feature(lang_items, start)]
+#![feature(lang_items)]
 #![no_std]
+#![no_main]
 
+// Import global allocator and panic handler.
 extern crate std as other;
 
 #[macro_use] extern crate alloc;
 
 use alloc::string::ToString;
 
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let s = format!("{}", 1_isize);
     assert_eq!(s, "1".to_string());
 
diff --git a/tests/ui/issues/issue-50714-1.rs b/tests/ui/issues/issue-50714-1.rs
deleted file mode 100644
index a25940ce1cbef..0000000000000
--- a/tests/ui/issues/issue-50714-1.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Regression test for issue 50714, make sure that this isn't a linker error.
-
-#![no_std]
-#![feature(start)]
-
-extern crate std;
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { //~ ERROR [E0647]
-    0
-}
diff --git a/tests/ui/issues/issue-50714-1.stderr b/tests/ui/issues/issue-50714-1.stderr
deleted file mode 100644
index 7593ac3834697..0000000000000
--- a/tests/ui/issues/issue-50714-1.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0647]: `#[start]` function is not allowed to have a `where` clause
-  --> $DIR/issue-50714-1.rs:9:50
-   |
-LL | fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq {
-   |                                                  ^^^^^^^^^^^^^^^^^ `#[start]` function cannot have a `where` clause
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0647`.
diff --git a/tests/ui/issues/issue-9575.rs b/tests/ui/issues/issue-9575.rs
deleted file mode 100644
index 06b252990b642..0000000000000
--- a/tests/ui/issues/issue-9575.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(start)]
-
-#[start]
-fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize {
-    //~^ `#[start]` function has wrong type
-   0
-}
diff --git a/tests/ui/issues/issue-9575.stderr b/tests/ui/issues/issue-9575.stderr
deleted file mode 100644
index 2f6e2687d24c9..0000000000000
--- a/tests/ui/issues/issue-9575.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0308]: `#[start]` function has wrong type
-  --> $DIR/issue-9575.rs:4:1
-   |
-LL | fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
-   |
-   = note: expected signature `fn(isize, *const *const u8) -> _`
-              found signature `fn(isize, *const *const u8, *const u8) -> _`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/issue-19660.rs b/tests/ui/lang-items/issue-19660.rs
deleted file mode 100644
index aff57df7ece98..0000000000000
--- a/tests/ui/lang-items/issue-19660.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ error-pattern: requires `copy` lang_item
-
-#![feature(lang_items, start, no_core)]
-#![no_core]
-
-#[lang = "sized"]
-trait Sized { }
-
-struct S;
-
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
-    let _ = S;
-    0
-}
diff --git a/tests/ui/lang-items/issue-19660.stderr b/tests/ui/lang-items/issue-19660.stderr
deleted file mode 100644
index e5a8a143d0301..0000000000000
--- a/tests/ui/lang-items/issue-19660.stderr
+++ /dev/null
@@ -1,4 +0,0 @@
-error: requires `copy` lang_item
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lang-items/lang-item-missing.rs b/tests/ui/lang-items/lang-item-missing.rs
index 8762594202a1c..5b832a5bb8f01 100644
--- a/tests/ui/lang-items/lang-item-missing.rs
+++ b/tests/ui/lang-items/lang-item-missing.rs
@@ -3,10 +3,11 @@
 
 //@ error-pattern: requires `sized` lang_item
 
-#![feature(start, no_core)]
+#![feature(lang_items, no_core)]
 #![no_core]
+#![no_main]
 
-#[start]
-fn start(argc: isize, argv: *const *const u8) -> isize {
-    0
+#[no_mangle]
+extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
+    loop {}
 }
diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
new file mode 100644
index 0000000000000..9b634ee8ee3e4
--- /dev/null
+++ b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
@@ -0,0 +1,15 @@
+//@ error-pattern: requires `copy` lang_item
+
+#![feature(lang_items, no_core)]
+#![no_core]
+#![no_main]
+
+#[lang = "sized"]
+trait Sized { }
+
+struct S;
+
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
+    argc
+}
diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
new file mode 100644
index 0000000000000..3dc7716ecd2a6
--- /dev/null
+++ b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
@@ -0,0 +1,8 @@
+error: requires `copy` lang_item
+  --> $DIR/missing-copy-lang-item-issue-19660.rs:14:5
+   |
+LL |     argc
+   |     ^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/dead-code/lint-dead-code-2.rs b/tests/ui/lint/dead-code/lint-dead-code-2.rs
index 6bfa4d96f710b..c82088ec54be9 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-2.rs
+++ b/tests/ui/lint/dead-code/lint-dead-code-2.rs
@@ -1,6 +1,6 @@
 #![allow(unused_variables)]
 #![deny(dead_code)]
-#![feature(rustc_attrs, start)]
+#![feature(rustc_attrs)]
 
 struct Foo;
 
@@ -21,21 +21,16 @@ fn live_fn() {}
 
 fn dead_fn() {} //~ ERROR: function `dead_fn` is never used
 
-#[rustc_main]
-fn dead_fn2() {} //~ ERROR: function `dead_fn2` is never used
-
 fn used_fn() {}
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[rustc_main]
+fn actual_main() {
     used_fn();
     let foo = Foo;
     foo.bar2();
-    0
 }
 
 // this is not main
 fn main() { //~ ERROR: function `main` is never used
     dead_fn();
-    dead_fn2();
 }
diff --git a/tests/ui/lint/dead-code/lint-dead-code-2.stderr b/tests/ui/lint/dead-code/lint-dead-code-2.stderr
index 85af553c9867f..4a5f3b8a68771 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-2.stderr
+++ b/tests/ui/lint/dead-code/lint-dead-code-2.stderr
@@ -10,17 +10,11 @@ note: the lint level is defined here
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
 
-error: function `dead_fn2` is never used
-  --> $DIR/lint-dead-code-2.rs:25:4
-   |
-LL | fn dead_fn2() {}
-   |    ^^^^^^^^
-
 error: function `main` is never used
-  --> $DIR/lint-dead-code-2.rs:38:4
+  --> $DIR/lint-dead-code-2.rs:34:4
    |
 LL | fn main() {
    |    ^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/print_type_sizes/anonymous.rs b/tests/ui/print_type_sizes/anonymous.rs
index a3a3222808802..7819e5ea767ed 100644
--- a/tests/ui/print_type_sizes/anonymous.rs
+++ b/tests/ui/print_type_sizes/anonymous.rs
@@ -1,14 +1,13 @@
-//@ compile-flags: -Z print-type-sizes
+//@ compile-flags: -Z print-type-sizes --crate-type=lib
 //@ build-pass
 
 // All of the types that occur in this function are uninteresting, in
 // that one cannot control the sizes of these types with the same sort
 // of enum-variant manipulation tricks.
 
-#![feature(start)]
+#![no_std]
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn main() -> isize {
     let _byte: u8 = 0;
     let _word: usize = 0;
     let _tuple: (u8, usize)= (0, 0);
diff --git a/tests/ui/privacy/privacy1.rs b/tests/ui/privacy/privacy1.rs
index 31f3960100371..9436441ecc6a7 100644
--- a/tests/ui/privacy/privacy1.rs
+++ b/tests/ui/privacy/privacy1.rs
@@ -1,4 +1,4 @@
-#![feature(lang_items, start, no_core)]
+#![feature(lang_items, no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
 #[lang="sized"]
@@ -173,4 +173,4 @@ pub mod mytest {
     }
 }
 
-#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
+fn main() {}
diff --git a/tests/ui/privacy/privacy2.rs b/tests/ui/privacy/privacy2.rs
index 33292a65c5d89..ab6d805544eeb 100644
--- a/tests/ui/privacy/privacy2.rs
+++ b/tests/ui/privacy/privacy2.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
-#![feature(start, no_core)]
+#![feature(no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
 // Test to make sure that globs don't leak in regular `use` statements.
@@ -26,4 +26,4 @@ fn test2() {
     //~^ ERROR `foo` is private
 }
 
-#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
+fn main() {}
diff --git a/tests/ui/privacy/privacy3.rs b/tests/ui/privacy/privacy3.rs
index fb1f432410dd1..6298a6bc8cf85 100644
--- a/tests/ui/privacy/privacy3.rs
+++ b/tests/ui/privacy/privacy3.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
-#![feature(start, no_core)]
+#![feature( no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
 // Test to make sure that private items imported through globs remain private
@@ -26,4 +26,4 @@ fn test1() {
     gpriv();
 }
 
-#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
+fn main() {}
diff --git a/tests/ui/privacy/privacy4.rs b/tests/ui/privacy/privacy4.rs
index fa257b800394f..7341c7752bbf7 100644
--- a/tests/ui/privacy/privacy4.rs
+++ b/tests/ui/privacy/privacy4.rs
@@ -1,4 +1,4 @@
-#![feature(lang_items, start, no_core)]
+#![feature(lang_items, no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
 #[lang = "sized"] pub trait Sized {}
@@ -22,4 +22,4 @@ fn test2() {
     gpriv();
 }
 
-#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs
deleted file mode 100644
index f0e111b578f9f..0000000000000
--- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(start)]
-
-#[start]
-#[track_caller] //~ ERROR `#[start]` function is not allowed to be `#[track_caller]`
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    panic!("{}: oh no", std::panic::Location::caller());
-}
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr
deleted file mode 100644
index 2738444f21f64..0000000000000
--- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: `#[start]` function is not allowed to be `#[track_caller]`
-  --> $DIR/error-with-start.rs:4:1
-   |
-LL | #[track_caller]
-   | ^^^^^^^^^^^^^^^
-LL | fn start(_argc: isize, _argv: *const *const u8) -> isize {
-   | -------------------------------------------------------- `#[start]` function is not allowed to be `#[track_caller]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs
deleted file mode 100644
index 6aa8f6fd821ed..0000000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ only-x86_64
-
-#![feature(start)]
-#![feature(target_feature_11)]
-
-#[start]
-#[target_feature(enable = "avx2")]
-//~^ ERROR `#[start]` function is not allowed to have `#[target_feature]`
-fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 }
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr
deleted file mode 100644
index d0a67c4f6a8d0..0000000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: `#[start]` function is not allowed to have `#[target_feature]`
-  --> $DIR/issue-108645-target-feature-on-start.rs:7:1
-   |
-LL | #[target_feature(enable = "avx2")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |
-LL | fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 }
-   | -------------------------------------------------------- `#[start]` function is not allowed to have `#[target_feature]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/runtime/native-print-no-runtime.rs b/tests/ui/runtime/native-print-no-runtime.rs
deleted file mode 100644
index f0ed7d97b2caf..0000000000000
--- a/tests/ui/runtime/native-print-no-runtime.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ run-pass
-
-#![feature(start)]
-
-#[start]
-pub fn main(_: isize, _: *const *const u8) -> isize {
-    println!("hello");
-    0
-}
diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
index 229408fb72474..f3f9ce0bd879e 100644
--- a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
+++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
@@ -4,15 +4,16 @@
 //@ compile-flags: -Cpanic=abort
 //@ no-prefer-dynamic so panic=abort works
 
-#![feature(start, rustc_private)]
+#![feature(rustc_private)]
+#![no_main]
 
 extern crate libc;
 
-// Use #[start] so we don't have a runtime that messes with SIGPIPE.
-#[start]
-fn start(argc: isize, argv: *const *const u8) -> isize {
+// Use no_main so we don't have a runtime that messes with SIGPIPE.
+#[no_mangle]
+extern "C" fn main(argc: core::ffi::c_int, argv: *const *const u8) -> core::ffi::c_int {
     assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg");
-    let arg1 = unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) }
+    let arg1 = unsafe { core::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) }
         .to_str()
         .unwrap();
 
@@ -23,8 +24,8 @@ fn start(argc: isize, argv: *const *const u8) -> isize {
     };
 
     let actual = unsafe {
-        let mut actual: libc::sigaction = std::mem::zeroed();
-        libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
+        let mut actual: libc::sigaction = core::mem::zeroed();
+        libc::sigaction(libc::SIGPIPE, core::ptr::null(), &mut actual);
         #[cfg(not(target_os = "aix"))]
         {
             actual.sa_sigaction
diff --git a/tests/ui/runtime/running-with-no-runtime.rs b/tests/ui/runtime/running-with-no-runtime.rs
index 695025b385906..5c219b6fedac5 100644
--- a/tests/ui/runtime/running-with-no-runtime.rs
+++ b/tests/ui/runtime/running-with-no-runtime.rs
@@ -2,15 +2,15 @@
 //@ ignore-wasm32 spawning processes is not supported
 //@ ignore-sgx no processes
 
-#![feature(start)]
+#![no_main]
 
 use std::ffi::CStr;
 use std::process::{Command, Output};
 use std::panic;
 use std::str;
 
-#[start]
-fn start(argc: isize, argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: core::ffi::c_int, argv: *const *const u8) -> core::ffi::c_int {
     if argc > 1 {
         unsafe {
             match **argv.offset(1) as char {
diff --git a/tests/ui/sanitizer/memory-eager.rs b/tests/ui/sanitizer/memory-eager.rs
index 9e7889fa1bc09..532d7b308f63d 100644
--- a/tests/ui/sanitizer/memory-eager.rs
+++ b/tests/ui/sanitizer/memory-eager.rs
@@ -15,7 +15,7 @@
 // since it will be linked with an uninstrumented version of it.
 
 #![feature(core_intrinsics)]
-#![feature(start)]
+#![no_main]
 
 use std::hint::black_box;
 use std::mem::MaybeUninit;
@@ -29,8 +29,8 @@ fn random() -> char {
     black_box(r)
 }
 
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int {
     random();
     0
 }
diff --git a/tests/ui/sanitizer/memory-passing.rs b/tests/ui/sanitizer/memory-passing.rs
index c8ab64bfaf833..96a4cd909c7c2 100644
--- a/tests/ui/sanitizer/memory-passing.rs
+++ b/tests/ui/sanitizer/memory-passing.rs
@@ -12,8 +12,8 @@
 // since it will be linked with an uninstrumented version of it.
 
 #![feature(core_intrinsics)]
-#![feature(start)]
 #![allow(invalid_value)]
+#![no_main]
 
 use std::hint::black_box;
 
@@ -25,8 +25,8 @@ fn calling_black_box_on_zst_ok() {
     black_box(zst);
 }
 
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int {
     calling_black_box_on_zst_ok();
     0
 }
diff --git a/tests/ui/sanitizer/memory.rs b/tests/ui/sanitizer/memory.rs
index bd2d67717495f..a91fefe4d16da 100644
--- a/tests/ui/sanitizer/memory.rs
+++ b/tests/ui/sanitizer/memory.rs
@@ -15,8 +15,8 @@
 // since it will be linked with an uninstrumented version of it.
 
 #![feature(core_intrinsics)]
-#![feature(start)]
 #![allow(invalid_value)]
+#![no_main]
 
 use std::hint::black_box;
 use std::mem::MaybeUninit;
@@ -39,8 +39,8 @@ fn xor(a: &[isize]) -> isize {
     s
 }
 
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int {
     let r = black_box(random as fn() -> [isize; 32])();
-    xor(&r)
+    xor(&r) as std::ffi::c_int
 }
diff --git a/tests/ui/test-attrs/test-runner-hides-start.rs b/tests/ui/test-attrs/test-runner-hides-start.rs
deleted file mode 100644
index 444ac237cfa3a..0000000000000
--- a/tests/ui/test-attrs/test-runner-hides-start.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ run-pass
-//@ compile-flags: --test
-
-#![feature(start)]
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize { panic!(); }
diff --git a/tests/ui/use/use.rs b/tests/ui/use/use.rs
index db031500a4ac8..25b8e529c432a 100644
--- a/tests/ui/use/use.rs
+++ b/tests/ui/use/use.rs
@@ -3,7 +3,7 @@
 #![allow(stable_features)]
 
 #![allow(unused_imports)]
-#![feature(start, no_core, core)]
+#![feature(no_core, core)]
 #![no_core]
 
 extern crate std;
@@ -18,5 +18,4 @@ mod baz {
     pub use std::str as x;
 }
 
-#[start]
-pub fn start(_: isize, _: *const *const u8) -> isize { 0 }
+fn main() {}