Clarify why a type is rejected for asm! · rust-lang/rust@c7088b2 (original) (raw)
`@@ -3,6 +3,7 @@ use std::assert_matches::debug_assert_matches;
`
3
3
`use rustc_abi::FieldIdx;
`
4
4
`use rustc_ast::InlineAsmTemplatePiece;
`
5
5
`use rustc_data_structures::fx::FxIndexSet;
`
``
6
`+
use rustc_hir::def_id::DefId;
`
6
7
`use rustc_hir::{self as hir, LangItem};
`
7
8
`use rustc_middle::bug;
`
8
9
`use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
`
`@@ -21,6 +22,12 @@ pub struct InlineAsmCtxt<'a, 'tcx> {
`
21
22
`get_operand_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
`
22
23
`}
`
23
24
``
``
25
`+
enum NonAsmTypeReason<'tcx> {
`
``
26
`+
UnevaluatedSIMDArrayLength(DefId, ty::Const<'tcx>),
`
``
27
`+
Invalid(Ty<'tcx>),
`
``
28
`+
InvalidElement(DefId, Ty<'tcx>),
`
``
29
`+
}
`
``
30
+
24
31
`impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
`
25
32
`pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self {
`
26
33
`InlineAsmCtxt {
`
`@@ -56,7 +63,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
`
56
63
`false
`
57
64
`}
`
58
65
``
59
``
`-
fn get_asm_ty(&self, ty: Ty<'tcx>) -> Option {
`
``
66
`+
fn get_asm_ty(&self, ty: Ty<'tcx>) -> Result<InlineAsmType, NonAsmTypeReason<'tcx>> {
`
60
67
`let asm_ty_isize = match self.tcx.sess.target.pointer_width {
`
61
68
`16 => InlineAsmType::I16,
`
62
69
`32 => InlineAsmType::I32,
`
`@@ -65,65 +72,62 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
`
65
72
`};
`
66
73
``
67
74
`match *ty.kind() {
`
68
``
`-
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
`
69
``
`-
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
`
70
``
`-
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
`
71
``
`-
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64),
`
72
``
`-
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128),
`
73
``
`-
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize),
`
74
``
`-
ty::Float(FloatTy::F16) => Some(InlineAsmType::F16),
`
75
``
`-
ty::Float(FloatTy::F32) => Some(InlineAsmType::F32),
`
76
``
`-
ty::Float(FloatTy::F64) => Some(InlineAsmType::F64),
`
77
``
`-
ty::Float(FloatTy::F128) => Some(InlineAsmType::F128),
`
78
``
`-
ty::FnPtr(..) => Some(asm_ty_isize),
`
79
``
`-
ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize),
`
``
75
`+
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Ok(InlineAsmType::I8),
`
``
76
`+
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Ok(InlineAsmType::I16),
`
``
77
`+
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Ok(InlineAsmType::I32),
`
``
78
`+
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Ok(InlineAsmType::I64),
`
``
79
`+
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Ok(InlineAsmType::I128),
`
``
80
`+
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Ok(asm_ty_isize),
`
``
81
`+
ty::Float(FloatTy::F16) => Ok(InlineAsmType::F16),
`
``
82
`+
ty::Float(FloatTy::F32) => Ok(InlineAsmType::F32),
`
``
83
`+
ty::Float(FloatTy::F64) => Ok(InlineAsmType::F64),
`
``
84
`+
ty::Float(FloatTy::F128) => Ok(InlineAsmType::F128),
`
``
85
`+
ty::FnPtr(..) => Ok(asm_ty_isize),
`
``
86
`+
ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Ok(asm_ty_isize),
`
80
87
` ty::Adt(adt, args) if adt.repr().simd() => {
`
81
88
`let fields = &adt.non_enum_variant().fields;
`
82
``
`-
let elem_ty = fields[FieldIdx::ZERO].ty(self.tcx, args);
`
``
89
`+
let field = &fields[FieldIdx::ZERO];
`
``
90
`+
let elem_ty = field.ty(self.tcx, args);
`
83
91
``
84
92
`let (size, ty) = match elem_ty.kind() {
`
85
93
` ty::Array(ty, len) => {
`
86
94
`let len = self.tcx.normalize_erasing_regions(self.typing_env, *len);
`
87
95
`if let Some(len) = len.try_to_target_usize(self.tcx) {
`
88
96
`(len, *ty)
`
89
97
`} else {
`
90
``
`-
return None;
`
``
98
`+
return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength(
`
``
99
`+
field.did, len,
`
``
100
`+
));
`
91
101
`}
`
92
102
`}
`
93
103
` _ => (fields.len() as u64, elem_ty),
`
94
104
`};
`
95
105
``
96
106
`match ty.kind() {
`
97
``
`-
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::VecI8(size)),
`
98
``
`-
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => {
`
99
``
`-
Some(InlineAsmType::VecI16(size))
`
100
``
`-
}
`
101
``
`-
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => {
`
102
``
`-
Some(InlineAsmType::VecI32(size))
`
103
``
`-
}
`
104
``
`-
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => {
`
105
``
`-
Some(InlineAsmType::VecI64(size))
`
106
``
`-
}
`
``
107
`+
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Ok(InlineAsmType::VecI8(size)),
`
``
108
`+
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Ok(InlineAsmType::VecI16(size)),
`
``
109
`+
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Ok(InlineAsmType::VecI32(size)),
`
``
110
`+
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Ok(InlineAsmType::VecI64(size)),
`
107
111
` ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => {
`
108
``
`-
Some(InlineAsmType::VecI128(size))
`
``
112
`+
Ok(InlineAsmType::VecI128(size))
`
109
113
`}
`
110
114
` ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => {
`
111
``
`-
Some(match self.tcx.sess.target.pointer_width {
`
``
115
`+
Ok(match self.tcx.sess.target.pointer_width {
`
112
116
`16 => InlineAsmType::VecI16(size),
`
113
117
`32 => InlineAsmType::VecI32(size),
`
114
118
`64 => InlineAsmType::VecI64(size),
`
115
119
` width => bug!("unsupported pointer width: {width}"),
`
116
120
`})
`
117
121
`}
`
118
``
`-
ty::Float(FloatTy::F16) => Some(InlineAsmType::VecF16(size)),
`
119
``
`-
ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)),
`
120
``
`-
ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)),
`
121
``
`-
ty::Float(FloatTy::F128) => Some(InlineAsmType::VecF128(size)),
`
122
``
`-
_ => None,
`
``
122
`+
ty::Float(FloatTy::F16) => Ok(InlineAsmType::VecF16(size)),
`
``
123
`+
ty::Float(FloatTy::F32) => Ok(InlineAsmType::VecF32(size)),
`
``
124
`+
ty::Float(FloatTy::F64) => Ok(InlineAsmType::VecF64(size)),
`
``
125
`+
ty::Float(FloatTy::F128) => Ok(InlineAsmType::VecF128(size)),
`
``
126
`+
_ => Err(NonAsmTypeReason::InvalidElement(field.did, ty)),
`
123
127
`}
`
124
128
`}
`
125
129
` ty::Infer(_) => bug!("unexpected infer ty in asm operand"),
`
126
``
`-
_ => None,
`
``
130
`+
_ => Err(NonAsmTypeReason::Invalid(ty)),
`
127
131
`}
`
128
132
`}
`
129
133
``
`@@ -164,17 +168,42 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
`
164
168
`}
`
165
169
` _ => self.get_asm_ty(ty),
`
166
170
`};
`
167
``
`-
let Some(asm_ty) = asm_ty else {
`
168
``
`` -
let msg = format!("cannot use value of type {ty}
for inline assembly");
``
169
``
`-
self.tcx
`
170
``
`-
.dcx()
`
171
``
`-
.struct_span_err(expr.span, msg)
`
172
``
`-
.with_note(
`
173
``
`-
"only integers, floats, SIMD vectors, pointers and function pointers \
`
174
``
`-
can be used as arguments for inline assembly",
`
175
``
`-
)
`
176
``
`-
.emit();
`
177
``
`-
return None;
`
``
171
`+
let asm_ty = match asm_ty {
`
``
172
`+
Ok(asm_ty) => asm_ty,
`
``
173
`+
Err(reason) => {
`
``
174
`+
match reason {
`
``
175
`+
NonAsmTypeReason::UnevaluatedSIMDArrayLength(did, len) => {
`
``
176
`` +
let msg = format!("cannot evaluate SIMD vector length {len}
");
``
``
177
`+
self.tcx
`
``
178
`+
.dcx()
`
``
179
`+
.struct_span_err(self.tcx.def_span(did), msg)
`
``
180
`+
.with_span_note(
`
``
181
`+
expr.span,
`
``
182
`` +
"SIMD vector length needs to be known statically for use in asm!
",
``
``
183
`+
)
`
``
184
`+
.emit();
`
``
185
`+
}
`
``
186
`+
NonAsmTypeReason::Invalid(ty) => {
`
``
187
`` +
let msg = format!("cannot use value of type {ty}
for inline assembly");
``
``
188
`+
self.tcx.dcx().struct_span_err(expr.span, msg).with_note(
`
``
189
`+
"only integers, floats, SIMD vectors, pointers and function pointers \
`
``
190
`+
can be used as arguments for inline assembly",
`
``
191
`+
).emit();
`
``
192
`+
}
`
``
193
`+
NonAsmTypeReason::InvalidElement(did, ty) => {
`
``
194
`+
let msg = format!(
`
``
195
`` +
"cannot use SIMD vector with element type {ty}
for inline assembly"
``
``
196
`+
);
`
``
197
`+
self.tcx.dcx()
`
``
198
`+
.struct_span_err(self.tcx.def_span(did), msg).with_span_note(
`
``
199
`+
expr.span,
`
``
200
`+
"only integers, floats, SIMD vectors, pointers and function pointers \
`
``
201
`+
can be used as arguments for inline assembly",
`
``
202
`+
).emit();
`
``
203
`+
}
`
``
204
`+
}
`
``
205
`+
return None;
`
``
206
`+
}
`
178
207
`};
`
179
208
``
180
209
`// Check that the type implements Copy. The only case where this can
`