Skip to content

Commit 95530d8

Browse files
hir/trait_sel: prohibit scalable vectors in types
Extend well-formedness checking and HIR analysis to prohibit the use of scalable vectors in structs, enums, unions, tuples and arrays. LLVM does not support scalable vectors being members of other types, so these restrictions are necessary. Co-authored-by: Jamie Cunliffe <Jamie.Cunliffe@arm.com>
1 parent 1d3a344 commit 95530d8

File tree

10 files changed

+269
-91
lines changed

10 files changed

+269
-91
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
9595
def.destructor(tcx); // force the destructor to be evaluated
9696

9797
if def.repr().simd() {
98-
check_simd(tcx, span, def_id);
98+
if def.repr().scalable() {
99+
check_scalable_simd(tcx, span, def_id);
100+
} else {
101+
check_simd(tcx, span, def_id);
102+
}
99103
}
100104

101105
check_transparent(tcx, def);
@@ -1392,6 +1396,54 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
13921396
}
13931397
}
13941398

1399+
fn check_scalable_simd(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId) {
1400+
let ty = tcx.type_of(def_id).instantiate_identity();
1401+
let ty::Adt(def, args) = ty.kind() else { return };
1402+
if !def.is_struct() {
1403+
tcx.dcx().delayed_bug("`repr(scalable)` applied to non-struct");
1404+
return;
1405+
}
1406+
1407+
let fields = &def.non_enum_variant().fields;
1408+
match fields.len() {
1409+
0 => {
1410+
let mut err =
1411+
tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
1412+
err.help("scalable vector types' only field must be slice of a primitive scalar type");
1413+
err.emit();
1414+
return;
1415+
}
1416+
1 => {}
1417+
2.. => {
1418+
tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit();
1419+
}
1420+
}
1421+
1422+
let array_field = &fields[FieldIdx::ZERO];
1423+
let array_ty = array_field.ty(tcx, args);
1424+
let ty::Slice(element_ty) = array_ty.kind() else {
1425+
let mut err =
1426+
tcx.dcx().struct_span_err(span, "the field of a scalable vector type must be a slice");
1427+
err.span_label(tcx.def_span(array_field.did), "not a slice");
1428+
err.emit();
1429+
return;
1430+
};
1431+
1432+
// Check that `element_ty` only uses types valid in the lanes of a scalable vector register:
1433+
// scalar types which directly match a "machine" type - e.g. integers, floats, bools, thin ptrs.
1434+
match element_ty.kind() {
1435+
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) | ty::Bool => (),
1436+
_ => {
1437+
let mut err = tcx.dcx().struct_span_err(
1438+
span,
1439+
"element type of a scalable vector must be a primitive scalar",
1440+
);
1441+
err.help("only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted");
1442+
err.emit();
1443+
}
1444+
}
1445+
}
1446+
13951447
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
13961448
let repr = def.repr();
13971449
if repr.packed() {

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,10 +1051,9 @@ fn check_type_defn<'tcx>(
10511051
};
10521052
// All fields (except for possibly the last) should be sized.
10531053
let all_sized = all_sized || variant.fields.is_empty() || needs_drop_copy();
1054-
let unsized_len = if all_sized { 0 } else { 1 };
1055-
for (idx, field) in
1056-
variant.fields.raw[..variant.fields.len() - unsized_len].iter().enumerate()
1057-
{
1054+
let unsized_len =
1055+
if all_sized { variant.fields.len() } else { variant.fields.len() - 1 };
1056+
for (idx, field) in variant.fields.raw.iter().enumerate() {
10581057
let last = idx == variant.fields.len() - 1;
10591058
let field_id = field.did.expect_local();
10601059
let hir::FieldDef { ty: hir_ty, .. } =
@@ -1064,28 +1063,41 @@ fn check_type_defn<'tcx>(
10641063
None,
10651064
tcx.type_of(field.did).instantiate_identity(),
10661065
);
1067-
wfcx.register_bound(
1068-
traits::ObligationCause::new(
1066+
1067+
if matches!(ty.kind(), ty::Adt(def, _) if def.repr().scalable()) {
1068+
tcx.dcx().span_err(
10691069
hir_ty.span,
1070-
wfcx.body_def_id,
1071-
ObligationCauseCode::FieldSized {
1072-
adt_kind: match &item.kind {
1073-
ItemKind::Struct(..) => AdtKind::Struct,
1074-
ItemKind::Union(..) => AdtKind::Union,
1075-
ItemKind::Enum(..) => AdtKind::Enum,
1076-
kind => span_bug!(
1077-
item.span,
1078-
"should be wfchecking an ADT, got {kind:?}"
1079-
),
1070+
format!(
1071+
"scalable vectors cannot be fields of a {}",
1072+
adt_def.variant_descr()
1073+
),
1074+
);
1075+
}
1076+
1077+
if idx < unsized_len {
1078+
wfcx.register_bound(
1079+
traits::ObligationCause::new(
1080+
hir_ty.span,
1081+
wfcx.body_def_id,
1082+
ObligationCauseCode::FieldSized {
1083+
adt_kind: match &item.kind {
1084+
ItemKind::Struct(..) => AdtKind::Struct,
1085+
ItemKind::Union(..) => AdtKind::Union,
1086+
ItemKind::Enum(..) => AdtKind::Enum,
1087+
kind => span_bug!(
1088+
item.span,
1089+
"should be wfchecking an ADT, got {kind:?}"
1090+
),
1091+
},
1092+
span: hir_ty.span,
1093+
last,
10801094
},
1081-
span: hir_ty.span,
1082-
last,
1083-
},
1084-
),
1085-
wfcx.param_env,
1086-
ty,
1087-
tcx.require_lang_item(LangItem::Sized, hir_ty.span),
1088-
);
1095+
),
1096+
wfcx.param_env,
1097+
ty,
1098+
tcx.require_lang_item(LangItem::Sized, hir_ty.span),
1099+
);
1100+
}
10891101
}
10901102

10911103
// Explicit `enum` discriminant values must const-evaluate successfully.

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,13 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
748748

749749
ty::Array(subty, len) => {
750750
self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
751+
if subty.is_scalable_simd() && !self.span.is_dummy() {
752+
self.tcx()
753+
.dcx()
754+
.struct_span_err(self.span, "scalable vectors cannot be array elements")
755+
.emit();
756+
}
757+
751758
// Note that the len being WF is implicitly checked while visiting.
752759
// Here we just check that it's of type usize.
753760
let cause = self.cause(ObligationCauseCode::ArrayLen(t));
@@ -769,9 +776,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
769776
}
770777

771778
ty::Tuple(tys) => {
772-
if let Some((_last, rest)) = tys.split_last() {
779+
if let Some((last, rest)) = tys.split_last() {
773780
for &elem in rest {
774781
self.require_sized(elem, ObligationCauseCode::TupleElem);
782+
if elem.is_scalable_simd() && !self.span.is_dummy() {
783+
self.tcx()
784+
.dcx()
785+
.struct_span_err(
786+
self.span,
787+
"scalable vectors cannot be tuple fields",
788+
)
789+
.emit();
790+
}
791+
}
792+
793+
if last.is_scalable_simd() && !self.span.is_dummy() {
794+
self.tcx()
795+
.dcx()
796+
.struct_span_err(self.span, "scalable vectors cannot be tuple fields")
797+
.emit();
775798
}
776799
}
777800
}

tests/ui/feature-gates/feature-gate-repr-scalable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![feature(repr_simd)]
22

33
#[repr(simd, scalable(16))] //~ ERROR: scalable vector types are experimental
4-
struct Foo { //~ ERROR: SIMD vector's only field must be an array
4+
struct Foo {
55
_ty: [i8],
66
}
77

tests/ui/feature-gates/feature-gate-repr-scalable.stderr

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,6 @@ LL | #[repr(simd, scalable(16))]
77
= help: add `#![feature(repr_scalable)]` to the crate attributes to enable
88
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
99

10-
error[E0076]: SIMD vector's only field must be an array
11-
--> $DIR/feature-gate-repr-scalable.rs:4:1
12-
|
13-
LL | struct Foo {
14-
| ^^^^^^^^^^
15-
LL | _ty: [i8],
16-
| --------- not an array
17-
18-
error: aborting due to 2 previous errors
10+
error: aborting due to 1 previous error
1911

20-
Some errors have detailed explanations: E0076, E0658.
21-
For more information about an error, try `rustc --explain E0076`.
12+
For more information about this error, try `rustc --explain E0658`.

tests/ui/simd/scalable/illformed.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ compile-flags: --crate-type=lib
2+
#![feature(repr_scalable, repr_simd)]
3+
4+
#[repr(simd, scalable(4))]
5+
struct NoFields {} //~ ERROR: scalable vectors must have a single field
6+
7+
#[repr(simd, scalable(4))]
8+
struct MultipleFields { //~ ERROR: scalable vectors cannot have multiple fields
9+
_ty: [f32], //~ ERROR: the size for values of type `[f32]` cannot be known at compilation time
10+
other: u32,
11+
}
12+
13+
#[repr(simd, scalable(4))]
14+
struct WrongFieldType { //~ ERROR: the field of a scalable vector type must be a slice
15+
_ty: String,
16+
}
17+
18+
#[repr(simd, scalable(4))]
19+
struct WrongElementTy { //~ ERROR: element type of a scalable vector must be a primitive scalar
20+
_ty: [String],
21+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error: scalable vectors must have a single field
2+
--> $DIR/illformed.rs:5:1
3+
|
4+
LL | struct NoFields {}
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= help: scalable vector types' only field must be slice of a primitive scalar type
8+
9+
error: scalable vectors cannot have multiple fields
10+
--> $DIR/illformed.rs:8:1
11+
|
12+
LL | struct MultipleFields {
13+
| ^^^^^^^^^^^^^^^^^^^^^
14+
15+
error[E0277]: the size for values of type `[f32]` cannot be known at compilation time
16+
--> $DIR/illformed.rs:9:10
17+
|
18+
LL | _ty: [f32],
19+
| ^^^^^ doesn't have a size known at compile-time
20+
|
21+
= help: the trait `Sized` is not implemented for `[f32]`
22+
= note: only the last field of a struct may have a dynamically sized type
23+
= help: change the field's type to have a statically known size
24+
help: borrowed types always have a statically known size
25+
|
26+
LL | _ty: &[f32],
27+
| +
28+
help: the `Box` type always has a statically known size and allocates its contents in the heap
29+
|
30+
LL | _ty: Box<[f32]>,
31+
| ++++ +
32+
33+
error: the field of a scalable vector type must be a slice
34+
--> $DIR/illformed.rs:14:1
35+
|
36+
LL | struct WrongFieldType {
37+
| ^^^^^^^^^^^^^^^^^^^^^
38+
LL | _ty: String,
39+
| ----------- not a slice
40+
41+
error: element type of a scalable vector must be a primitive scalar
42+
--> $DIR/illformed.rs:19:1
43+
|
44+
LL | struct WrongElementTy {
45+
| ^^^^^^^^^^^^^^^^^^^^^
46+
|
47+
= help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted
48+
49+
error: aborting due to 5 previous errors
50+
51+
For more information about this error, try `rustc --explain E0277`.

tests/ui/simd/scalable/invalid.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,21 +175,18 @@ fn main() {
175175

176176
#[repr(transparent, simd, scalable(4))] //~ ERROR: transparent struct cannot have other repr hints
177177
struct CombinedWithReprTransparent {
178-
//~^ ERROR: SIMD vector's only field must be an array
179178
_ty: [f64],
180179
}
181180

182181
#[repr(Rust, simd, scalable(4))] //~ ERROR: conflicting representation hints
183182
struct CombinedWithReprRust {
184-
//~^ ERROR: SIMD vector's only field must be an array
185183
_ty: [f64],
186184
}
187185

188186
#[repr(C, simd, scalable(4))]
189187
//~^ ERROR: conflicting representation hints
190188
//~^^ WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
191189
struct CombinedWithReprC {
192-
//~^ ERROR: SIMD vector's only field must be an array
193190
_ty: [f64],
194191
}
195192

@@ -224,6 +221,5 @@ struct ArgKind {
224221

225222
#[repr(simd, scalable(4))]
226223
struct Okay {
227-
//~^ ERROR: SIMD vector's only field must be an array
228224
_ty: [f64],
229225
}

0 commit comments

Comments
 (0)