Skip to content

Commit 7de89bc

Browse files
committed
Ban non-array SIMD
1 parent a32d4a0 commit 7de89bc

File tree

96 files changed

+736
-1031
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+736
-1031
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+22-20
Original file line numberDiff line numberDiff line change
@@ -1063,20 +1063,29 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
10631063
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
10641064
return;
10651065
}
1066-
let e = fields[FieldIdx::ZERO].ty(tcx, args);
1067-
if !fields.iter().all(|f| f.ty(tcx, args) == e) {
1068-
struct_span_code_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous")
1069-
.with_span_label(sp, "SIMD elements must have the same type")
1066+
1067+
let array_field = &fields[FieldIdx::ZERO];
1068+
let array_ty = array_field.ty(tcx, args);
1069+
let ty::Array(element_ty, len_const) = array_ty.kind() else {
1070+
struct_span_code_err!(
1071+
tcx.dcx(),
1072+
sp,
1073+
E0076,
1074+
"SIMD vector's only field must be an array"
1075+
)
1076+
.with_span_label(tcx.def_span(array_field.did), "not an array")
1077+
.emit();
1078+
return;
1079+
};
1080+
1081+
if let Some(second_field) = fields.get(FieldIdx::from_u32(1)) {
1082+
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields")
1083+
.with_span_label(tcx.def_span(second_field.did), "excess field")
10701084
.emit();
10711085
return;
10721086
}
10731087

1074-
let len = if let ty::Array(_ty, c) = e.kind() {
1075-
c.try_eval_target_usize(tcx, tcx.param_env(def.did()))
1076-
} else {
1077-
Some(fields.len() as u64)
1078-
};
1079-
if let Some(len) = len {
1088+
if let Some(len) = len_const.try_eval_target_usize(tcx, tcx.param_env(def.did())) {
10801089
if len == 0 {
10811090
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
10821091
return;
@@ -1096,16 +1105,9 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
10961105
// These are scalar types which directly match a "machine" type
10971106
// Yes: Integers, floats, "thin" pointers
10981107
// No: char, "fat" pointers, compound types
1099-
match e.kind() {
1100-
ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
1101-
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct(u8, u8, u8, u8) is ok
1102-
ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
1103-
ty::Array(t, _clen)
1104-
if matches!(
1105-
t.kind(),
1106-
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _)
1107-
) =>
1108-
{ /* struct([f32; 4]) is ok */ }
1108+
match element_ty.kind() {
1109+
ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors
1110+
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok
11091111
_ => {
11101112
struct_span_code_err!(
11111113
tcx.dcx(),

compiler/rustc_middle/src/ty/sty.rs

+15-23
Original file line numberDiff line numberDiff line change
@@ -1091,29 +1091,21 @@ impl<'tcx> Ty<'tcx> {
10911091
}
10921092

10931093
pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
1094-
match self.kind() {
1095-
Adt(def, args) => {
1096-
assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type");
1097-
let variant = def.non_enum_variant();
1098-
let f0_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
1099-
1100-
match f0_ty.kind() {
1101-
// If the first field is an array, we assume it is the only field and its
1102-
// elements are the SIMD components.
1103-
Array(f0_elem_ty, f0_len) => {
1104-
// FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112
1105-
// The way we evaluate the `N` in `[T; N]` here only works since we use
1106-
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
1107-
// if we use it in generic code. See the `simd-array-trait` ui test.
1108-
(f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty)
1109-
}
1110-
// Otherwise, the fields of this Adt are the SIMD components (and we assume they
1111-
// all have the same type).
1112-
_ => (variant.fields.len() as u64, f0_ty),
1113-
}
1114-
}
1115-
_ => bug!("`simd_size_and_type` called on invalid type"),
1116-
}
1094+
let Adt(def, args) = self.kind() else {
1095+
bug!("`simd_size_and_type` called on invalid type")
1096+
};
1097+
assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type");
1098+
let variant = def.non_enum_variant();
1099+
assert_eq!(variant.fields.len(), 1);
1100+
let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
1101+
let Array(f0_elem_ty, f0_len) = field_ty.kind() else {
1102+
bug!("Simd type has non-array field type {field_ty:?}")
1103+
};
1104+
// FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112
1105+
// The way we evaluate the `N` in `[T; N]` here only works since we use
1106+
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
1107+
// if we use it in generic code. See the `simd-array-trait` ui test.
1108+
(f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty)
11171109
}
11181110

11191111
#[inline]

tests/assembly/asm/aarch64-types.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,35 @@ trait Sized {}
2828
#[lang = "copy"]
2929
trait Copy {}
3030

31+
// Do we really need to use no_core for this?!?
32+
impl<T: Copy, const N: usize> Copy for [T; N] {}
33+
3134
type ptr = *mut u8;
3235

3336
#[repr(simd)]
34-
pub struct i8x8(i8, i8, i8, i8, i8, i8, i8, i8);
37+
pub struct i8x8([i8; 8]);
3538
#[repr(simd)]
36-
pub struct i16x4(i16, i16, i16, i16);
39+
pub struct i16x4([i16; 4]);
3740
#[repr(simd)]
38-
pub struct i32x2(i32, i32);
41+
pub struct i32x2([i32; 2]);
3942
#[repr(simd)]
40-
pub struct i64x1(i64);
43+
pub struct i64x1([i64; 1]);
4144
#[repr(simd)]
42-
pub struct f32x2(f32, f32);
45+
pub struct f32x2([f32; 2]);
4346
#[repr(simd)]
44-
pub struct f64x1(f64);
47+
pub struct f64x1([f64; 1]);
4548
#[repr(simd)]
46-
pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
49+
pub struct i8x16([i8; 16]);
4750
#[repr(simd)]
48-
pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
51+
pub struct i16x8([i16; 8]);
4952
#[repr(simd)]
50-
pub struct i32x4(i32, i32, i32, i32);
53+
pub struct i32x4([i32; 4]);
5154
#[repr(simd)]
52-
pub struct i64x2(i64, i64);
55+
pub struct i64x2([i64; 2]);
5356
#[repr(simd)]
54-
pub struct f32x4(f32, f32, f32, f32);
57+
pub struct f32x4([f32; 4]);
5558
#[repr(simd)]
56-
pub struct f64x2(f64, f64);
59+
pub struct f64x2([f64; 2]);
5760

5861
impl Copy for i8 {}
5962
impl Copy for i16 {}

tests/assembly/asm/arm-modifiers.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ trait Sized {}
2727
#[lang = "copy"]
2828
trait Copy {}
2929

30+
// Do we really need to use no_core for this?!?
31+
impl<T: Copy, const N: usize> Copy for [T; N] {}
32+
3033
#[repr(simd)]
31-
pub struct f32x4(f32, f32, f32, f32);
34+
pub struct f32x4([f32; 4]);
3235

3336
impl Copy for i32 {}
3437
impl Copy for f32 {}

tests/assembly/asm/arm-types.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,35 @@ trait Sized {}
3030
#[lang = "copy"]
3131
trait Copy {}
3232

33+
// Do we really need to use no_core for this?!?
34+
impl<T: Copy, const N: usize> Copy for [T; N] {}
35+
3336
type ptr = *mut u8;
3437

3538
#[repr(simd)]
36-
pub struct i8x8(i8, i8, i8, i8, i8, i8, i8, i8);
39+
pub struct i8x8([i8; 8]);
3740
#[repr(simd)]
38-
pub struct i16x4(i16, i16, i16, i16);
41+
pub struct i16x4([i16; 4]);
3942
#[repr(simd)]
40-
pub struct i32x2(i32, i32);
43+
pub struct i32x2([i32; 2]);
4144
#[repr(simd)]
42-
pub struct i64x1(i64);
45+
pub struct i64x1([i64; 1]);
4346
#[repr(simd)]
44-
pub struct f16x4(f16, f16, f16, f16);
47+
pub struct f16x4([f16; 4]);
4548
#[repr(simd)]
46-
pub struct f32x2(f32, f32);
49+
pub struct f32x2([f32; 2]);
4750
#[repr(simd)]
48-
pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
51+
pub struct i8x16([i8; 16]);
4952
#[repr(simd)]
50-
pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
53+
pub struct i16x8([i16; 8]);
5154
#[repr(simd)]
52-
pub struct i32x4(i32, i32, i32, i32);
55+
pub struct i32x4([i32; 4]);
5356
#[repr(simd)]
54-
pub struct i64x2(i64, i64);
57+
pub struct i64x2([i64; 2]);
5558
#[repr(simd)]
56-
pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16);
59+
pub struct f16x8([f16; 8]);
5760
#[repr(simd)]
58-
pub struct f32x4(f32, f32, f32, f32);
61+
pub struct f32x4([f32; 4]);
5962

6063
impl Copy for i8 {}
6164
impl Copy for i16 {}

0 commit comments

Comments
 (0)