diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md index 42baa65bf9faf..42cd2aa185315 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0094.md +++ b/compiler/rustc_error_codes/src/error_codes/E0094.md @@ -1,4 +1,5 @@ -An invalid number of type parameters was given to an intrinsic function. +An invalid number of generic type, lifetime, or const parameters was +given to an intrinsic function. Erroneous code example: diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 5741b6824b5d7..7a7ecb06132b9 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -3,11 +3,11 @@ use crate::errors::{ SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, - WrongNumberOfTypeArgumentsToInstrinsic, + WrongNumberOfGenericArgumentsToInstrinsic, }; use crate::require_same_types; -use rustc_errors::struct_span_err; +use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::subst::Subst; @@ -21,36 +21,68 @@ fn equate_intrinsic_type<'tcx>( tcx: TyCtxt<'tcx>, it: &hir::ForeignItem<'_>, n_tps: usize, + n_lts: usize, sig: ty::PolyFnSig<'tcx>, ) { - match it.kind { - hir::ForeignItemKind::Fn(..) => {} + let (gen_lts, gen_tys, gen_cns, span) = match &it.kind { + hir::ForeignItemKind::Fn(.., generics) => { + let mut gen_lts = 0; + let mut gen_tys = 0; + let mut gen_cns = 0; + + for param in generics.params { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => { + gen_lts += 1; + } + hir::GenericParamKind::Type { .. } => { + gen_tys += 1; + } + hir::GenericParamKind::Const { .. } => { + gen_cns += 1; + } + } + } + + (gen_lts, gen_tys, gen_cns, generics.span) + } _ => { struct_span_err!(tcx.sess, it.span, E0622, "intrinsic must be a function") .span_label(it.span, "expected a function") .emit(); return; } - } - - let i_n_tps = tcx.generics_of(it.def_id).own_counts().types; - if i_n_tps != n_tps { - let span = match it.kind { - hir::ForeignItemKind::Fn(_, _, ref generics) => generics.span, - _ => bug!(), - }; + }; - tcx.sess.emit_err(WrongNumberOfTypeArgumentsToInstrinsic { + if gen_lts != n_lts { + tcx.sess.emit_err(WrongNumberOfGenericArgumentsToInstrinsic { + span, + found: gen_lts, + expected: n_lts, + expected_pluralize: pluralize!(n_lts), + descr: "lifetime", + }); + } else if gen_tys != n_tps { + tcx.sess.emit_err(WrongNumberOfGenericArgumentsToInstrinsic { span, - found: i_n_tps, + found: gen_tys, expected: n_tps, + expected_pluralize: pluralize!(n_tps), + descr: "type", }); - return; + } else if gen_cns != 0 { + tcx.sess.emit_err(WrongNumberOfGenericArgumentsToInstrinsic { + span, + found: gen_cns, + expected: 0, + expected_pluralize: pluralize!(0), + descr: "const", + }); + } else { + let fty = tcx.mk_fn_ptr(sig); + let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType); + require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty); } - - let fty = tcx.mk_fn_ptr(sig); - let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType); - require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty); } /// Returns `true` if the given intrinsic is unsafe to call or not. @@ -121,7 +153,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { }) }; - let (n_tps, inputs, output, unsafety) = if name_str.starts_with("atomic_") { + let (n_tps, n_lts, inputs, output, unsafety) = if name_str.starts_with("atomic_") { let split: Vec<&str> = name_str.split('_').collect(); assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format"); @@ -143,7 +175,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { return; } }; - (n_tps, inputs, output, hir::Unsafety::Unsafe) + (n_tps, 0, inputs, output, hir::Unsafety::Unsafe) } else { let unsafety = intrinsic_operation_unsafety(intrinsic_name); let (n_tps, inputs, output) = match intrinsic_name { @@ -372,11 +404,17 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { return; } }; - (n_tps, inputs, output, unsafety) + ( + n_tps, + if matches!(intrinsic_name, sym::va_copy) { 1 } else { 0 }, + inputs, + output, + unsafety, + ) }; let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic); let sig = ty::Binder::bind_with_vars(sig, bound_vars); - equate_intrinsic_type(tcx, it, n_tps, sig) + equate_intrinsic_type(tcx, it, n_tps, n_lts, sig) } /// Type-check `extern "platform-intrinsic" { ... }` functions. @@ -472,5 +510,5 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) Abi::PlatformIntrinsic, ); let sig = ty::Binder::dummy(sig); - equate_intrinsic_type(tcx, it, n_tps, sig) + equate_intrinsic_type(tcx, it, n_tps, 0, sig) } diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 5068242692ae8..bc686a025a650 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -24,13 +24,15 @@ pub struct UnrecognizedAtomicOperation<'a> { #[derive(SessionDiagnostic)] #[error = "E0094"] -pub struct WrongNumberOfTypeArgumentsToInstrinsic { - #[message = "intrinsic has wrong number of type \ +pub struct WrongNumberOfGenericArgumentsToInstrinsic<'a> { + #[message = "intrinsic has wrong number of {descr} \ parameters: found {found}, expected {expected}"] - #[label = "expected {expected} type parameter"] + #[label = "expected {expected} {descr} parameter{expected_pluralize}"] pub span: Span, pub found: usize, pub expected: usize, + pub expected_pluralize: &'a str, + pub descr: &'a str, } #[derive(SessionDiagnostic)] diff --git a/src/test/ui/simd-intrinsic/issue-85855.rs b/src/test/ui/simd-intrinsic/issue-85855.rs new file mode 100644 index 0000000000000..61aa15be47f63 --- /dev/null +++ b/src/test/ui/simd-intrinsic/issue-85855.rs @@ -0,0 +1,20 @@ +// Check that appropriate errors are reported if an intrinsic is defined +// with the wrong number of generic lifetime/type/const parameters, and +// that no ICE occurs in these cases. + +#![feature(platform_intrinsics)] +#![crate_type="lib"] + +extern "platform-intrinsic" { + fn simd_saturating_add<'a, T: 'a>(x: T, y: T); + //~^ ERROR: intrinsic has wrong number of lifetime parameters + + fn simd_add<'a, T>(x: T, y: T); + //~^ ERROR: intrinsic has wrong number of lifetime parameters + + fn simd_sub(x: T, y: U); + //~^ ERROR: intrinsic has wrong number of type parameters + + fn simd_mul(x: T, y: T); + //~^ ERROR: intrinsic has wrong number of const parameters +} diff --git a/src/test/ui/simd-intrinsic/issue-85855.stderr b/src/test/ui/simd-intrinsic/issue-85855.stderr new file mode 100644 index 0000000000000..7dfdecb9520a7 --- /dev/null +++ b/src/test/ui/simd-intrinsic/issue-85855.stderr @@ -0,0 +1,27 @@ +error[E0094]: intrinsic has wrong number of lifetime parameters: found 1, expected 0 + --> $DIR/issue-85855.rs:9:27 + | +LL | fn simd_saturating_add<'a, T: 'a>(x: T, y: T); + | ^^^^^^^^^^^ expected 0 lifetime parameters + +error[E0094]: intrinsic has wrong number of lifetime parameters: found 1, expected 0 + --> $DIR/issue-85855.rs:12:16 + | +LL | fn simd_add<'a, T>(x: T, y: T); + | ^^^^^^^ expected 0 lifetime parameters + +error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1 + --> $DIR/issue-85855.rs:15:16 + | +LL | fn simd_sub(x: T, y: U); + | ^^^^^^ expected 1 type parameter + +error[E0094]: intrinsic has wrong number of const parameters: found 1, expected 0 + --> $DIR/issue-85855.rs:18:16 + | +LL | fn simd_mul(x: T, y: T); + | ^^^^^^^^^^^^^^^^^^^ expected 0 const parameters + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0094`.