Rollup merge of #86148 - FabianWolff:issue-85855, r=varkor
Check the number of generic lifetime and const parameters of intrinsics This pull request fixes #85855. The current code for type checking intrinsics only checks the number of generic _type_ parameters, but does not check for an incorrect number of lifetime or const parameters, which can cause problems later on, such as the ICE in #85855, where the code thought that it was looking at a type parameter but found a lifetime parameter: ``` error: internal compiler error: compiler/rustc_middle/src/ty/generics.rs:188:18: expected type parameter, but found another generic parameter ``` The changes in this PR add checks for the number of lifetime and const parameters, expand the scope of `E0094` to also apply to these cases, and improve the error message by properly pluralizing the number of expected generic parameters.
This commit is contained in:
commit
ab4d16fe7a
5 changed files with 83 additions and 32 deletions
|
@ -1,4 +1,4 @@
|
||||||
An invalid number of type parameters was given to an intrinsic function.
|
An invalid number of generic parameters was passed to an intrinsic function.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
|
SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
|
||||||
WrongNumberOfTypeArgumentsToInstrinsic,
|
WrongNumberOfGenericArgumentsToIntrinsic,
|
||||||
};
|
};
|
||||||
use crate::require_same_types;
|
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_hir as hir;
|
||||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||||
use rustc_middle::ty::subst::Subst;
|
use rustc_middle::ty::subst::Subst;
|
||||||
|
@ -21,36 +21,45 @@ fn equate_intrinsic_type<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
it: &hir::ForeignItem<'_>,
|
it: &hir::ForeignItem<'_>,
|
||||||
n_tps: usize,
|
n_tps: usize,
|
||||||
|
n_lts: usize,
|
||||||
sig: ty::PolyFnSig<'tcx>,
|
sig: ty::PolyFnSig<'tcx>,
|
||||||
) {
|
) {
|
||||||
match it.kind {
|
let (own_counts, span) = match &it.kind {
|
||||||
hir::ForeignItemKind::Fn(..) => {}
|
hir::ForeignItemKind::Fn(.., generics) => {
|
||||||
|
let own_counts = tcx.generics_of(it.def_id.to_def_id()).own_counts();
|
||||||
|
(own_counts, generics.span)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(tcx.sess, it.span, E0622, "intrinsic must be a function")
|
struct_span_err!(tcx.sess, it.span, E0622, "intrinsic must be a function")
|
||||||
.span_label(it.span, "expected a function")
|
.span_label(it.span, "expected a function")
|
||||||
.emit();
|
.emit();
|
||||||
return;
|
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 {
|
let gen_count_ok = |found: usize, expected: usize, descr: &str| -> bool {
|
||||||
|
if found != expected {
|
||||||
|
tcx.sess.emit_err(WrongNumberOfGenericArgumentsToIntrinsic {
|
||||||
span,
|
span,
|
||||||
found: i_n_tps,
|
found,
|
||||||
expected: n_tps,
|
expected,
|
||||||
|
expected_pluralize: pluralize!(expected),
|
||||||
|
descr,
|
||||||
});
|
});
|
||||||
return;
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime")
|
||||||
|
&& gen_count_ok(own_counts.types, n_tps, "type")
|
||||||
|
&& gen_count_ok(own_counts.consts, 0, "const")
|
||||||
|
{
|
||||||
let fty = tcx.mk_fn_ptr(sig);
|
let fty = tcx.mk_fn_ptr(sig);
|
||||||
let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
|
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);
|
require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the unsafety of the given intrinsic.
|
/// Returns the unsafety of the given intrinsic.
|
||||||
|
@ -121,7 +130,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();
|
let split: Vec<&str> = name_str.split('_').collect();
|
||||||
assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
|
assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
|
||||||
|
|
||||||
|
@ -143,7 +152,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(n_tps, inputs, output, hir::Unsafety::Unsafe)
|
(n_tps, 0, inputs, output, hir::Unsafety::Unsafe)
|
||||||
} else {
|
} else {
|
||||||
let unsafety = intrinsic_operation_unsafety(intrinsic_name);
|
let unsafety = intrinsic_operation_unsafety(intrinsic_name);
|
||||||
let (n_tps, inputs, output) = match intrinsic_name {
|
let (n_tps, inputs, output) = match intrinsic_name {
|
||||||
|
@ -372,11 +381,11 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(n_tps, inputs, output, unsafety)
|
(n_tps, 0, inputs, output, unsafety)
|
||||||
};
|
};
|
||||||
let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic);
|
let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic);
|
||||||
let sig = ty::Binder::bind_with_vars(sig, bound_vars);
|
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.
|
/// Type-check `extern "platform-intrinsic" { ... }` functions.
|
||||||
|
@ -472,5 +481,5 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
|
||||||
Abi::PlatformIntrinsic,
|
Abi::PlatformIntrinsic,
|
||||||
);
|
);
|
||||||
let sig = ty::Binder::dummy(sig);
|
let sig = ty::Binder::dummy(sig);
|
||||||
equate_intrinsic_type(tcx, it, n_tps, sig)
|
equate_intrinsic_type(tcx, it, n_tps, 0, sig)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,15 @@ pub struct UnrecognizedAtomicOperation<'a> {
|
||||||
|
|
||||||
#[derive(SessionDiagnostic)]
|
#[derive(SessionDiagnostic)]
|
||||||
#[error = "E0094"]
|
#[error = "E0094"]
|
||||||
pub struct WrongNumberOfTypeArgumentsToInstrinsic {
|
pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
|
||||||
#[message = "intrinsic has wrong number of type \
|
#[message = "intrinsic has wrong number of {descr} \
|
||||||
parameters: found {found}, expected {expected}"]
|
parameters: found {found}, expected {expected}"]
|
||||||
#[label = "expected {expected} type parameter"]
|
#[label = "expected {expected} {descr} parameter{expected_pluralize}"]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub found: usize,
|
pub found: usize,
|
||||||
pub expected: usize,
|
pub expected: usize,
|
||||||
|
pub expected_pluralize: &'a str,
|
||||||
|
pub descr: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(SessionDiagnostic)]
|
#[derive(SessionDiagnostic)]
|
||||||
|
|
19
src/test/ui/simd-intrinsic/issue-85855.rs
Normal file
19
src/test/ui/simd-intrinsic/issue-85855.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// 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) -> T;
|
||||||
|
|
||||||
|
fn simd_sub<T, U>(x: T, y: U);
|
||||||
|
//~^ ERROR: intrinsic has wrong number of type parameters
|
||||||
|
|
||||||
|
fn simd_mul<T, const N: usize>(x: T, y: T);
|
||||||
|
//~^ ERROR: intrinsic has wrong number of const parameters
|
||||||
|
}
|
21
src/test/ui/simd-intrinsic/issue-85855.stderr
Normal file
21
src/test/ui/simd-intrinsic/issue-85855.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
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 type parameters: found 2, expected 1
|
||||||
|
--> $DIR/issue-85855.rs:14:16
|
||||||
|
|
|
||||||
|
LL | fn simd_sub<T, U>(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:17:16
|
||||||
|
|
|
||||||
|
LL | fn simd_mul<T, const N: usize>(x: T, y: T);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ expected 0 const parameters
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0094`.
|
Loading…
Add table
Add a link
Reference in a new issue