diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 169ad0df3a5..67592fa7840 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -108,7 +108,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{HirIdMap, Node}; +use rustc_hir::{HirIdMap, ImplicitSelfKind, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -137,6 +137,7 @@ use crate::util::common::indenter; use self::coercion::DynamicCoerceMany; pub use self::Expectation::*; +use rustc_target::spec::abi; #[macro_export] macro_rules! type_error_struct { @@ -520,6 +521,35 @@ fn typeck_with_fallback<'tcx>( let fn_sig = fixup_opaque_types(tcx, &fn_sig); + if fn_sig.abi == abi::Abi::RustCall { + let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 }; + + let err = || { + if let Node::Item(item) = tcx.hir().get(id) { + if let hir::ItemKind::Fn(header, ..) = &item.kind { + tcx.sess.span_err(header.span, "A function with the \"rust-call\" ABI must take a single non-self argument that is a tuple") + } + } else { + bug!("Couldn't get span of FnHeader being checked") + } + }; + + if fn_sig.inputs().len() != expected_args { + err() + } else { + match fn_sig.inputs()[expected_args - 1].kind() { + ty::Tuple(_) => (), + // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on + // This will probably require wide-scale changes to support a TupleKind obligation + // We can't resolve this without knowing the type of the param + ty::Param(_) => (), + _ => { + err() + } + } + } + } + let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; fcx } else { diff --git a/src/test/ui/abi/issues/issue-22565-rust-call.rs b/src/test/ui/abi/issues/issue-22565-rust-call.rs new file mode 100644 index 00000000000..055d959b46e --- /dev/null +++ b/src/test/ui/abi/issues/issue-22565-rust-call.rs @@ -0,0 +1,8 @@ +#![feature(unboxed_closures)] + +extern "rust-call" fn b(_i: i32) {} +//~^ ERROR A function with the "rust-call" ABI must take a single non-self argument that is a tuple + +fn main () { + b(10); +} diff --git a/src/test/ui/abi/issues/issue-22565-rust-call.stderr b/src/test/ui/abi/issues/issue-22565-rust-call.stderr new file mode 100644 index 00000000000..31fb035eb99 --- /dev/null +++ b/src/test/ui/abi/issues/issue-22565-rust-call.stderr @@ -0,0 +1,8 @@ +error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple + --> $DIR/issue-22565-rust-call.rs:3:1 + | +LL | extern "rust-call" fn b(_i: i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/abi/rustcall-generic.rs b/src/test/ui/abi/rustcall-generic.rs new file mode 100644 index 00000000000..2fa41a7e35a --- /dev/null +++ b/src/test/ui/abi/rustcall-generic.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(unboxed_closures)] + +extern "rust-call" fn foo(_: T) {} + +fn main() { + foo(()); + foo((1, 2)); +} diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr index 50cd8bc68a2..25f0c259d11 100644 --- a/src/test/ui/feature-gates/feature-gate-abi.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi.stderr @@ -26,7 +26,7 @@ LL | extern "vectorcall" fn f3() {} error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:18:8 | -LL | extern "rust-call" fn f4() {} +LL | extern "rust-call" fn f4(_: ()) {} | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -113,7 +113,7 @@ LL | extern "vectorcall" fn m3(); error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:33:12 | -LL | extern "rust-call" fn m4(); +LL | extern "rust-call" fn m4(_: ()); | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -183,7 +183,7 @@ LL | extern "vectorcall" fn dm3() {} error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:42:12 | -LL | extern "rust-call" fn dm4() {} +LL | extern "rust-call" fn dm4(_: ()) {} | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -270,7 +270,7 @@ LL | extern "vectorcall" fn m3() {} error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:60:12 | -LL | extern "rust-call" fn m4() {} +LL | extern "rust-call" fn m4(_: ()) {} | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -357,7 +357,7 @@ LL | extern "vectorcall" fn im3() {} error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:76:12 | -LL | extern "rust-call" fn im4() {} +LL | extern "rust-call" fn im4(_: ()) {} | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -444,7 +444,7 @@ LL | type A3 = extern "vectorcall" fn(); error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:89:18 | -LL | type A4 = extern "rust-call" fn(); +LL | type A4 = extern "rust-call" fn(_: ()); | ^^^^^^^^^^^ | = note: see issue #29625 for more information