about summary refs log tree commit diff
diff options
context:
space:
mode:
authorasquared31415 <34665709+asquared31415@users.noreply.github.com>2022-12-23 13:54:14 -0500
committerDavid Tolnay <dtolnay@gmail.com>2023-01-11 14:35:08 -0800
commit337a97d3741bb78319cde745119cf96941b78325 (patch)
treee1a564cb922042c09fd3e3e062523cda035f85e2
parentef4046e4f3932991971cdb64915172899532aece (diff)
downloadrust-337a97d3741bb78319cde745119cf96941b78325.tar.gz
rust-337a97d3741bb78319cde745119cf96941b78325.zip
add checks for the signature of the lang item
-rw-r--r--compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl11
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs133
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs33
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs2
-rw-r--r--tests/run-make-fulldeps/target-specs/foo.rs2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argc.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argv.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr13
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_args.stderr13
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_ret.stderr13
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_ty.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr11
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_ret.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr11
-rw-r--r--tests/ui/lang-items/start_lang_item_args.rs101
-rw-r--r--tests/ui/lang-items/start_lang_item_args.sigpipe.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.start_ret.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.too_many_args.stderr17
18 files changed, 405 insertions, 3 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl b/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl
index 0612dbae0b6..ca72b7faa92 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl
@@ -46,3 +46,14 @@ hir_typeck_add_missing_parentheses_in_range = you must surround the range in par
 
 hir_typeck_op_trait_generic_params =
     `{$method_name}` must not have any generic parameters
+
+hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
+hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
+
+hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
+    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
+
+hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
+    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 32f86b8042c..57feefbcab6 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -1,4 +1,7 @@
 use crate::coercion::CoerceMany;
+use crate::errors::{
+    LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy,
+};
 use crate::gather_locals::GatherLocalsVisitor;
 use crate::FnCtxt;
 use crate::GeneratorTypes;
@@ -9,8 +12,9 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::check::fn_maybe_err;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::RegionVariableOrigin;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
+use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use std::cell::RefCell;
 
@@ -168,6 +172,10 @@ pub(super) fn check_fn<'a, 'tcx>(
         check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
     }
 
+    if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == hir.local_def_id(fn_id).to_def_id() {
+        check_lang_start_fn(tcx, fn_sig, decl, fn_def_id);
+    }
+
     gen_ty
 }
 
@@ -223,3 +231,126 @@ fn check_panic_info_fn(
         tcx.sess.span_err(span, "should have no const parameters");
     }
 }
+
+fn check_lang_start_fn<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_sig: ty::FnSig<'tcx>,
+    decl: &'tcx hir::FnDecl<'tcx>,
+    def_id: LocalDefId,
+) {
+    let inputs = fn_sig.inputs();
+
+    let arg_count = inputs.len();
+    if arg_count != 4 {
+        tcx.sess.emit_err(LangStartIncorrectNumberArgs {
+            params_span: tcx.def_span(def_id),
+            found_param_count: arg_count,
+        });
+    }
+
+    // only check args if they should exist by checking the count
+    // note: this does not handle args being shifted or their order swapped very nicely
+    // but it's a lang item, users shouldn't frequently encounter this
+
+    // first arg is `main: fn() -> T`
+    if let Some(&main_arg) = inputs.get(0) {
+        // make a Ty for the generic on the fn for diagnostics
+        // FIXME: make the lang item generic checks check for the right generic *kind*
+        // for example `start`'s generic should be a type parameter
+        let generics = tcx.generics_of(def_id);
+        let fn_generic = generics.param_at(0, tcx);
+        let generic_tykind =
+            ty::Param(ty::ParamTy { index: fn_generic.index, name: fn_generic.name });
+        let generic_ty = tcx.mk_ty(generic_tykind);
+        let expected_fn_sig =
+            tcx.mk_fn_sig([].iter(), &generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
+        let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig));
+
+        // we emit the same error to suggest changing the arg no matter what's wrong with the arg
+        let emit_main_fn_arg_err = || {
+            tcx.sess.emit_err(LangStartIncorrectParam {
+                param_span: decl.inputs[0].span,
+                param_num: 1,
+                expected_ty: expected_ty,
+                found_ty: main_arg,
+            });
+        };
+
+        if let ty::FnPtr(main_fn_sig) = main_arg.kind() {
+            let main_fn_inputs = main_fn_sig.inputs();
+            if main_fn_inputs.iter().count() != 0 {
+                emit_main_fn_arg_err();
+            }
+
+            let output = main_fn_sig.output();
+            output.map_bound(|ret_ty| {
+                // if the output ty is a generic, it's probably the right one
+                if !matches!(ret_ty.kind(), ty::Param(_)) {
+                    emit_main_fn_arg_err();
+                }
+            });
+        } else {
+            emit_main_fn_arg_err();
+        }
+    }
+
+    // second arg is isize
+    if let Some(&argc_arg) = inputs.get(1) {
+        if argc_arg != tcx.types.isize {
+            tcx.sess.emit_err(LangStartIncorrectParam {
+                param_span: decl.inputs[1].span,
+                param_num: 2,
+                expected_ty: tcx.types.isize,
+                found_ty: argc_arg,
+            });
+        }
+    }
+
+    // third arg is `*const *const u8`
+    if let Some(&argv_arg) = inputs.get(2) {
+        let mut argv_is_okay = false;
+        if let ty::RawPtr(outer_ptr) = argv_arg.kind() {
+            if outer_ptr.mutbl.is_not() {
+                if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() {
+                    if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 {
+                        argv_is_okay = true;
+                    }
+                }
+            }
+        }
+
+        if !argv_is_okay {
+            let inner_ptr_ty =
+                tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
+            let expected_ty =
+                tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
+            tcx.sess.emit_err(LangStartIncorrectParam {
+                param_span: decl.inputs[2].span,
+                param_num: 3,
+                expected_ty,
+                found_ty: argv_arg,
+            });
+        }
+    }
+
+    // fourth arg is `sigpipe: u8`
+    if let Some(&sigpipe_arg) = inputs.get(3) {
+        if sigpipe_arg != tcx.types.u8 {
+            tcx.sess.emit_err(LangStartIncorrectParam {
+                param_span: decl.inputs[3].span,
+                param_num: 4,
+                expected_ty: tcx.types.u8,
+                found_ty: sigpipe_arg,
+            });
+        }
+    }
+
+    // output type is isize
+    if fn_sig.output() != tcx.types.isize {
+        tcx.sess.emit_err(LangStartIncorrectRetTy {
+            ret_span: decl.output.span(),
+            expected_ty: tcx.types.isize,
+            found_ty: fn_sig.output(),
+        });
+    }
+}
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 507272fdec5..5b4fd5e4a52 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -172,3 +172,36 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
         );
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_lang_start_incorrect_number_params)]
+#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)]
+#[note(hir_typeck_lang_start_expected_sig_note)]
+pub struct LangStartIncorrectNumberArgs {
+    #[primary_span]
+    pub params_span: Span,
+    pub found_param_count: usize,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_lang_start_incorrect_param)]
+pub struct LangStartIncorrectParam<'tcx> {
+    #[primary_span]
+    #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
+    pub param_span: Span,
+
+    pub param_num: usize,
+    pub expected_ty: Ty<'tcx>,
+    pub found_ty: Ty<'tcx>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_lang_start_incorrect_ret_ty)]
+pub struct LangStartIncorrectRetTy<'tcx> {
+    #[primary_span]
+    #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
+    pub ret_span: Span,
+
+    pub expected_ty: Ty<'tcx>,
+    pub found_ty: Ty<'tcx>,
+}
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index a7da8f89aa3..1af77d1a25b 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -15,7 +15,7 @@ pub trait Copy {}
 pub unsafe trait Freeze {}
 
 #[lang = "start"]
-fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
     0
 }
 
diff --git a/tests/run-make-fulldeps/target-specs/foo.rs b/tests/run-make-fulldeps/target-specs/foo.rs
index d576a1dd281..22939e87912 100644
--- a/tests/run-make-fulldeps/target-specs/foo.rs
+++ b/tests/run-make-fulldeps/target-specs/foo.rs
@@ -11,7 +11,7 @@ trait Sized {}
 auto trait Freeze {}
 
 #[lang = "start"]
-fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
     0
 }
 
diff --git a/tests/ui/lang-items/start_lang_item_args.argc.stderr b/tests/ui/lang-items/start_lang_item_args.argc.stderr
new file mode 100644
index 00000000000..65c99a93c75
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.argc.stderr
@@ -0,0 +1,8 @@
+error: parameter 2 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:75:38
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                                      ^^ help: change the type from `i8` to `isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.argv.stderr b/tests/ui/lang-items/start_lang_item_args.argv.stderr
new file mode 100644
index 00000000000..f0947a9b3e9
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.argv.stderr
@@ -0,0 +1,8 @@
+error: parameter 3 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:89:52
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize {
+   |                                                    ^^ help: change the type from `u8` to `*const *const u8`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
new file mode 100644
index 00000000000..08efd5088f9
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
@@ -0,0 +1,13 @@
+error: parameter 3 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:82:52
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize {
+   |                                                    ^^^^^^^^^^^^^^^^^^^
+   |
+help: change the type from `*const *const usize` to `*const *const u8`
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                                                    ~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.main_args.stderr b/tests/ui/lang-items/start_lang_item_args.main_args.stderr
new file mode 100644
index 00000000000..c20a744661d
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.main_args.stderr
@@ -0,0 +1,13 @@
+error: parameter 1 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:61:20
+   |
+LL | fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ^^^^^^^^^^^^
+   |
+help: change the type from `fn(i32) -> T` to `fn() -> T`
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
new file mode 100644
index 00000000000..8f967252f49
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
@@ -0,0 +1,13 @@
+error: parameter 1 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:68:20
+   |
+LL | fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ^^^^^^^^^^^
+   |
+help: change the type from `fn() -> u16` to `fn() -> T`
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
new file mode 100644
index 00000000000..deb37b868ea
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
@@ -0,0 +1,8 @@
+error: parameter 1 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:54:20
+   |
+LL | fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ^^^ help: change the type from `u64` to `fn() -> T`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
new file mode 100644
index 00000000000..004c2a67f62
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
@@ -0,0 +1,11 @@
+error: incorrect number of parameters for the `start` lang item
+  --> $DIR/start_lang_item_args.rs:15:1
+   |
+LL | fn start<T>() -> isize {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `start` lang item should have four parameters, but found 0
+   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
new file mode 100644
index 00000000000..1d8285b5900
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
@@ -0,0 +1,8 @@
+error: the return type of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:29:84
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
+   |                                                                                    ^ help: change the type from `()` to `isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
new file mode 100644
index 00000000000..e545a750f24
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
@@ -0,0 +1,11 @@
+error: incorrect number of parameters for the `start` lang item
+  --> $DIR/start_lang_item_args.rs:22:1
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `start` lang item should have four parameters, but found 3
+   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.rs b/tests/ui/lang-items/start_lang_item_args.rs
new file mode 100644
index 00000000000..0dbfba39cb6
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.rs
@@ -0,0 +1,101 @@
+// check-fail
+// revisions: missing_all_args missing_sigpipe_arg missing_ret start_ret too_many_args
+// revisions: main_ty main_args main_ret argc argv_inner_ptr argv sigpipe
+
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "sized"]
+pub trait Sized {}
+
+#[cfg(missing_all_args)]
+#[lang = "start"]
+fn start<T>() -> isize {
+    //[missing_all_args]~^ ERROR incorrect number of parameters
+    100
+}
+
+#[cfg(missing_sigpipe_arg)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+    //[missing_sigpipe_arg]~^ ERROR incorrect number of parameters
+    100
+}
+
+#[cfg(missing_ret)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
+//[missing_ret]~^ ERROR the return type of the `start` lang item is incorrect
+
+#[cfg(start_ret)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 {
+    //[start_ret]~^ ERROR the return type of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(too_many_args)]
+#[lang = "start"]
+fn start<T>(
+    //[too_many_args]~^ ERROR incorrect number of parameters
+    _main: fn() -> T,
+    _argc: isize,
+    _argv: *const *const u8,
+    _sigpipe: u8,
+    _extra_arg: (),
+) -> isize {
+    100
+}
+
+#[cfg(main_ty)]
+#[lang = "start"]
+fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    //[main_ty]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(main_args)]
+#[lang = "start"]
+fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    //[main_args]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(main_ret)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    //[main_ret]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(argc)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    //[argc]~^ ERROR parameter 2 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(argv_inner_ptr)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize {
+    //[argv_inner_ptr]~^ ERROR parameter 3 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(argv)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize {
+    //[argv]~^ ERROR parameter 3 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(sigpipe)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize {
+    //[sigpipe]~^ ERROR parameter 4 of the `start` lang item is incorrect
+    100
+}
+
+fn main() {}
diff --git a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
new file mode 100644
index 00000000000..b20ae312801
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
@@ -0,0 +1,8 @@
+error: parameter 4 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:96:80
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize {
+   |                                                                                ^^^ help: change the type from `i64` to `u8`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
new file mode 100644
index 00000000000..935d5f3c8b4
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
@@ -0,0 +1,8 @@
+error: the return type of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:34:87
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 {
+   |                                                                                       ^^ help: change the type from `u8` to `isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
new file mode 100644
index 00000000000..30a7ed18a3d
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
@@ -0,0 +1,17 @@
+error: incorrect number of parameters for the `start` lang item
+  --> $DIR/start_lang_item_args.rs:41:1
+   |
+LL | / fn start<T>(
+LL | |
+LL | |     _main: fn() -> T,
+LL | |     _argc: isize,
+...  |
+LL | |     _extra_arg: (),
+LL | | ) -> isize {
+   | |__________^
+   |
+   = note: the `start` lang item should have four parameters, but found 5
+   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+