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

`