Skip to content

Commit fb5d918

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 c265ceb commit fb5d918

File tree

16 files changed

+695
-5
lines changed

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
@@ -265,6 +265,8 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing
265265
266266
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
267267
268+
ast_passes_scalable_vector_not_tuple_struct = scalable vectors must be tuple structs
269+
268270
ast_passes_static_without_body =
269271
free static item without body
270272
.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
@@ -1298,6 +1298,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12981298
}
12991299
ItemKind::Struct(ident, generics, vdata) => {
13001300
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
1301+
// Scalable vectors can only be tuple structs
1302+
let is_scalable_vector =
1303+
item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector));
1304+
if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) {
1305+
this.dcx()
1306+
.emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
1307+
}
1308+
13011309
match vdata {
13021310
VariantData::Struct { fields, .. } => {
13031311
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
@@ -974,3 +974,10 @@ pub(crate) struct AbiX86Interrupt {
974974
pub spans: Vec<Span>,
975975
pub param_count: usize,
976976
}
977+
978+
#[derive(Diagnostic)]
979+
#[diag(ast_passes_scalable_vector_not_tuple_struct)]
980+
pub(crate) struct ScalableVectorNotTupleStruct {
981+
#[primary_span]
982+
pub span: Span,
983+
}

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};
@@ -92,7 +92,9 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
9292
let span = tcx.def_span(def_id);
9393
def.destructor(tcx); // force the destructor to be evaluated
9494

95-
if def.repr().simd() {
95+
if let Some(scalable) = def.repr().scalable {
96+
check_scalable_vector(tcx, span, def_id, scalable);
97+
} else if def.repr().simd() {
9698
check_simd(tcx, span, def_id);
9799
}
98100

@@ -1425,6 +1427,83 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
14251427
}
14261428
}
14271429

1430+
#[tracing::instrument(skip(tcx), level = "debug")]
1431+
fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalable: ScalableElt) {
1432+
let ty = tcx.type_of(def_id).instantiate_identity();
1433+
let ty::Adt(def, args) = ty.kind() else { return };
1434+
if !def.is_struct() {
1435+
tcx.dcx().delayed_bug("`rustc_scalable_vector` applied to non-struct");
1436+
return;
1437+
}
1438+
1439+
let fields = &def.non_enum_variant().fields;
1440+
match scalable {
1441+
ScalableElt::ElementCount(..) if fields.is_empty() => {
1442+
let mut err =
1443+
tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
1444+
err.help("scalable vector types' only field must be a primitive scalar type");
1445+
err.emit();
1446+
return;
1447+
}
1448+
ScalableElt::ElementCount(..) if fields.len() >= 2 => {
1449+
tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit();
1450+
return;
1451+
}
1452+
ScalableElt::Container if fields.is_empty() => {
1453+
let mut err =
1454+
tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
1455+
err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type");
1456+
err.emit();
1457+
return;
1458+
}
1459+
_ => {}
1460+
}
1461+
1462+
match scalable {
1463+
ScalableElt::ElementCount(..) => {
1464+
let element_ty = &fields[FieldIdx::ZERO].ty(tcx, args);
1465+
1466+
// Check that `element_ty` only uses types valid in the lanes of a scalable vector
1467+
// register: scalar types which directly match a "machine" type - integers, floats and
1468+
// bools
1469+
match element_ty.kind() {
1470+
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool => (),
1471+
_ => {
1472+
let mut err = tcx.dcx().struct_span_err(
1473+
span,
1474+
"element type of a scalable vector must be a primitive scalar",
1475+
);
1476+
err.help(
1477+
"only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted",
1478+
);
1479+
err.emit();
1480+
}
1481+
}
1482+
}
1483+
ScalableElt::Container => {
1484+
let mut prev_field_ty = None;
1485+
for field in fields.iter() {
1486+
let element_ty = field.ty(tcx, args);
1487+
if let ty::Adt(def, _) = element_ty.kind()
1488+
&& !def.repr().scalable()
1489+
{
1490+
tcx.dcx().span_err(
1491+
tcx.def_span(field.did),
1492+
"scalable vector structs can only have scalable vector fields",
1493+
);
1494+
} else if let Some(prev_ty) = prev_field_ty.replace(element_ty)
1495+
&& prev_ty != element_ty
1496+
{
1497+
tcx.dcx().span_err(
1498+
tcx.def_span(field.did),
1499+
"all fields in a scalable vector struct must be the same type",
1500+
);
1501+
}
1502+
}
1503+
}
1504+
}
1505+
}
1506+
14281507
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
14291508
let repr = def.repr();
14301509
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};
@@ -1037,7 +1037,21 @@ fn check_type_defn<'tcx>(
10371037
hir_ty.span,
10381038
Some(WellFormedLoc::Ty(field_id)),
10391039
ty.into(),
1040-
)
1040+
);
1041+
1042+
if matches!(ty.kind(), ty::Adt(def, _) if def.repr().scalable())
1043+
&& !matches!(adt_def.repr().scalable, Some(ScalableElt::Container))
1044+
{
1045+
// Scalable vectors can only be fields of structs if the type has an
1046+
// `rustc_scalable_vector` attribute w/out specifying an element count
1047+
tcx.dcx().span_err(
1048+
hir_ty.span,
1049+
format!(
1050+
"scalable vectors cannot be fields of a {}",
1051+
adt_def.variant_descr()
1052+
),
1053+
);
1054+
}
10411055
}
10421056

10431057
// 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
@@ -771,9 +771,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
771771
}
772772

773773
ty::Tuple(tys) => {
774-
if let Some((_last, rest)) = tys.split_last() {
774+
if let Some((last, rest)) = tys.split_last() {
775775
for &elem in rest {
776776
self.require_sized(elem, ObligationCauseCode::TupleElem);
777+
if elem.is_scalable_vector() && !self.span.is_dummy() {
778+
self.tcx()
779+
.dcx()
780+
.struct_span_err(
781+
self.span,
782+
"scalable vectors cannot be tuple fields",
783+
)
784+
.emit();
785+
}
786+
}
787+
788+
if last.is_scalable_vector() && !self.span.is_dummy() {
789+
self.tcx()
790+
.dcx()
791+
.struct_span_err(self.span, "scalable vectors cannot be tuple fields")
792+
.emit();
777793
}
778794
}
779795
}
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)