Skip to content

Commit f95a354

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 <[email protected]>
1 parent c3ce478 commit f95a354

16 files changed

+695
-5
lines changed

compiler/rustc_ast_passes/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing
228228
229229
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
230230
231+
ast_passes_scalable_vector_not_tuple_struct = scalable vectors must be tuple structs
232+
231233
ast_passes_static_without_body =
232234
free static item without body
233235
.suggestion = provide a definition for the static

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11821182
}
11831183
ItemKind::Struct(ident, generics, vdata) => {
11841184
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
1185+
// Scalable vectors can only be tuple structs
1186+
let is_scalable_vector =
1187+
item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector));
1188+
if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) {
1189+
this.dcx()
1190+
.emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
1191+
}
1192+
11851193
match vdata {
11861194
VariantData::Struct { fields, .. } => {
11871195
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,3 +907,10 @@ pub(crate) struct AbiMustNotHaveReturnType {
907907
pub span: Span,
908908
pub abi: ExternAbi,
909909
}
910+
911+
#[derive(Diagnostic)]
912+
#[diag(ast_passes_scalable_vector_not_tuple_struct)]
913+
pub(crate) struct ScalableVectorNotTupleStruct {
914+
#[primary_span]
915+
pub span: Span,
916+
}

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::cell::LazyCell;
22
use std::ops::ControlFlow;
33

4-
use rustc_abi::{ExternAbi, FieldIdx};
4+
use rustc_abi::{ExternAbi, FieldIdx, ScalableElt};
55
use rustc_data_structures::unord::{UnordMap, UnordSet};
66
use rustc_errors::codes::*;
77
use rustc_errors::{EmissionGuarantee, MultiSpan};
@@ -94,7 +94,9 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
9494
let span = tcx.def_span(def_id);
9595
def.destructor(tcx); // force the destructor to be evaluated
9696

97-
if def.repr().simd() {
97+
if let Some(scalable) = def.repr().scalable {
98+
check_scalable_vector(tcx, span, def_id, scalable);
99+
} else if def.repr().simd() {
98100
check_simd(tcx, span, def_id);
99101
}
100102

@@ -1398,6 +1400,83 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
13981400
}
13991401
}
14001402

1403+
#[tracing::instrument(skip(tcx), level = "debug")]
1404+
fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalable: ScalableElt) {
1405+
let ty = tcx.type_of(def_id).instantiate_identity();
1406+
let ty::Adt(def, args) = ty.kind() else { return };
1407+
if !def.is_struct() {
1408+
tcx.dcx().delayed_bug("`rustc_scalable_vector` applied to non-struct");
1409+
return;
1410+
}
1411+
1412+
let fields = &def.non_enum_variant().fields;
1413+
match scalable {
1414+
ScalableElt::ElementCount(..) if fields.is_empty() => {
1415+
let mut err =
1416+
tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
1417+
err.help("scalable vector types' only field must be a primitive scalar type");
1418+
err.emit();
1419+
return;
1420+
}
1421+
ScalableElt::ElementCount(..) if fields.len() >= 2 => {
1422+
tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit();
1423+
return;
1424+
}
1425+
ScalableElt::Container if fields.is_empty() => {
1426+
let mut err =
1427+
tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
1428+
err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type");
1429+
err.emit();
1430+
return;
1431+
}
1432+
_ => {}
1433+
}
1434+
1435+
match scalable {
1436+
ScalableElt::ElementCount(..) => {
1437+
let element_ty = &fields[FieldIdx::ZERO].ty(tcx, args);
1438+
1439+
// Check that `element_ty` only uses types valid in the lanes of a scalable vector
1440+
// register: scalar types which directly match a "machine" type - integers, floats and
1441+
// bools
1442+
match element_ty.kind() {
1443+
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool => (),
1444+
_ => {
1445+
let mut err = tcx.dcx().struct_span_err(
1446+
span,
1447+
"element type of a scalable vector must be a primitive scalar",
1448+
);
1449+
err.help(
1450+
"only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted",
1451+
);
1452+
err.emit();
1453+
}
1454+
}
1455+
}
1456+
ScalableElt::Container => {
1457+
let mut prev_field_ty = None;
1458+
for field in fields.iter() {
1459+
let element_ty = field.ty(tcx, args);
1460+
if let ty::Adt(def, _) = element_ty.kind()
1461+
&& !def.repr().scalable()
1462+
{
1463+
tcx.dcx().span_err(
1464+
tcx.def_span(field.did),
1465+
"scalable vector structs can only have scalable vector fields",
1466+
);
1467+
} else if let Some(prev_ty) = prev_field_ty.replace(element_ty)
1468+
&& prev_ty != element_ty
1469+
{
1470+
tcx.dcx().span_err(
1471+
tcx.def_span(field.did),
1472+
"all fields in a scalable vector struct must be the same type",
1473+
);
1474+
}
1475+
}
1476+
}
1477+
}
1478+
}
1479+
14011480
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
14021481
let repr = def.repr();
14031482
if repr.packed() {

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::cell::LazyCell;
22
use std::ops::{ControlFlow, Deref};
33

44
use hir::intravisit::{self, Visitor};
5-
use rustc_abi::ExternAbi;
5+
use rustc_abi::{ExternAbi, ScalableElt};
66
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
77
use rustc_errors::codes::*;
88
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
@@ -1039,7 +1039,21 @@ fn check_type_defn<'tcx>(
10391039
hir_ty.span,
10401040
Some(WellFormedLoc::Ty(field_id)),
10411041
ty.into(),
1042-
)
1042+
);
1043+
1044+
if matches!(ty.kind(), ty::Adt(def, _) if def.repr().scalable())
1045+
&& !matches!(adt_def.repr().scalable, Some(ScalableElt::Container))
1046+
{
1047+
// Scalable vectors can only be fields of structs if the type has an
1048+
// `rustc_scalable_vector` attribute w/out specifying an element count
1049+
tcx.dcx().span_err(
1050+
hir_ty.span,
1051+
format!(
1052+
"scalable vectors cannot be fields of a {}",
1053+
adt_def.variant_descr()
1054+
),
1055+
);
1056+
}
10431057
}
10441058

10451059
// For DST, or when drop needs to copy things around, all

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,9 +770,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
770770
}
771771

772772
ty::Tuple(tys) => {
773-
if let Some((_last, rest)) = tys.split_last() {
773+
if let Some((last, rest)) = tys.split_last() {
774774
for &elem in rest {
775775
self.require_sized(elem, ObligationCauseCode::TupleElem);
776+
if elem.is_scalable_vector() && !self.span.is_dummy() {
777+
self.tcx()
778+
.dcx()
779+
.struct_span_err(
780+
self.span,
781+
"scalable vectors cannot be tuple fields",
782+
)
783+
.emit();
784+
}
785+
}
786+
787+
if last.is_scalable_vector() && !self.span.is_dummy() {
788+
self.tcx()
789+
.dcx()
790+
.struct_span_err(self.span, "scalable vectors cannot be tuple fields")
791+
.emit();
776792
}
777793
}
778794
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//@ compile-flags: --crate-type=lib
2+
#![allow(internal_features)]
3+
#![feature(extern_types)]
4+
#![feature(never_type)]
5+
#![feature(rustc_attrs)]
6+
7+
struct Foo;
8+
enum Bar {}
9+
union Baz { x: u16 }
10+
extern "C" {
11+
type Qux;
12+
}
13+
14+
#[rustc_scalable_vector(4)]
15+
struct TyChar(char);
16+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
17+
18+
#[rustc_scalable_vector(2)]
19+
struct TyConstPtr(*const u8);
20+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
21+
22+
#[rustc_scalable_vector(2)]
23+
struct TyMutPtr(*mut u8);
24+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
25+
26+
#[rustc_scalable_vector(4)]
27+
struct TyStruct(Foo);
28+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
29+
30+
#[rustc_scalable_vector(4)]
31+
struct TyEnum(Bar);
32+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
33+
34+
#[rustc_scalable_vector(4)]
35+
struct TyUnion(Baz);
36+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
37+
38+
#[rustc_scalable_vector(4)]
39+
struct TyForeign(Qux);
40+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
41+
42+
#[rustc_scalable_vector(4)]
43+
struct TyArray([u32; 4]);
44+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
45+
46+
#[rustc_scalable_vector(4)]
47+
struct TySlice([u32]);
48+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
49+
50+
#[rustc_scalable_vector(4)]
51+
struct TyRef<'a>(&'a u32);
52+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
53+
54+
#[rustc_scalable_vector(4)]
55+
struct TyFnPtr(fn(u32) -> u32);
56+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
57+
58+
#[rustc_scalable_vector(4)]
59+
struct TyDyn(dyn std::io::Write);
60+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
61+
62+
#[rustc_scalable_vector(4)]
63+
struct TyNever(!);
64+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
65+
66+
#[rustc_scalable_vector(4)]
67+
struct TyTuple((u32, u32));
68+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
69+
70+
type ValidAlias = u32;
71+
type InvalidAlias = String;
72+
73+
#[rustc_scalable_vector(4)]
74+
struct TyValidAlias(ValidAlias);
75+
76+
#[rustc_scalable_vector(4)]
77+
struct TyInvalidAlias(InvalidAlias);
78+
//~^ ERROR: element type of a scalable vector must be a primitive scalar
79+
80+
trait Tr {
81+
type Valid;
82+
type Invalid;
83+
}
84+
85+
impl Tr for () {
86+
type Valid = u32;
87+
type Invalid = String;
88+
}
89+
90+
struct TyValidProjection(<() as Tr>::Valid);
91+
92+
struct TyInvalidProjection(<() as Tr>::Invalid);
93+
// FIXME: element type of a scalable vector must be a primitive scalar

0 commit comments

Comments
 (0)