rustc_monomorphize/mono_checks/
abi_check.rs1use rustc_abi::{BackendRepr, CanonAbi, ExternAbi, RegKind, X86Call};
4use rustc_hir::{CRATE_HIR_ID, HirId};
5use rustc_middle::mir::{self, Location, traversal};
6use rustc_middle::ty::layout::{FnAbiRequest, codegen_handle_fn_abi_err};
7use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt};
8use rustc_span::def_id::DefId;
9use rustc_span::{DUMMY_SP, Span, Symbol, sym};
10use rustc_target::callconv::{FnAbi, PassMode};
11
12use crate::diagnostics;
13
14enum UsesVectorRegisters {
16 FixedVector,
18 ScalableVector,
20 No,
21}
22
23fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters {
26 match mode {
27 PassMode::Ignore | PassMode::Indirect { .. } | PassMode::IndirectUnsized { .. } => {
28 UsesVectorRegisters::No
29 }
30 PassMode::Cast { pad_i32_count: _, cast }
31 if cast.prefix.iter().any(|x| #[allow(non_exhaustive_omitted_patterns)] match x.kind {
RegKind::Vector { .. } => true,
_ => false,
}matches!(x.kind, RegKind::Vector { .. }))
32 || #[allow(non_exhaustive_omitted_patterns)] match cast.rest.unit.kind {
RegKind::Vector { .. } => true,
_ => false,
}matches!(cast.rest.unit.kind, RegKind::Vector { .. }) =>
33 {
34 UsesVectorRegisters::FixedVector
35 }
36 PassMode::Direct(..) | PassMode::Pair(..)
37 if #[allow(non_exhaustive_omitted_patterns)] match repr {
BackendRepr::SimdVector { .. } => true,
_ => false,
}matches!(repr, BackendRepr::SimdVector { .. }) =>
38 {
39 UsesVectorRegisters::FixedVector
40 }
41 PassMode::Direct(..) | PassMode::Pair(..)
42 if #[allow(non_exhaustive_omitted_patterns)] match repr {
BackendRepr::SimdScalableVector { .. } => true,
_ => false,
}matches!(repr, BackendRepr::SimdScalableVector { .. }) =>
43 {
44 UsesVectorRegisters::ScalableVector
45 }
46 _ => UsesVectorRegisters::No,
47 }
48}
49
50fn do_check_simd_vector_abi<'tcx>(
55 tcx: TyCtxt<'tcx>,
56 abi: &FnAbi<'tcx, Ty<'tcx>>,
57 def_id: DefId,
58 is_call: bool,
59 loc: impl Fn() -> (Span, HirId),
60) {
61 let codegen_attrs = tcx.codegen_fn_attrs(def_id);
62 let have_feature = |feat: Symbol| {
63 let target_feats = tcx.sess.internal_target_features.contains(&feat);
64 let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat);
65 target_feats || fn_feats
66 };
67 for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
68 let size = arg_abi.layout.size;
69 match passes_vectors_by_value(&arg_abi.mode, &arg_abi.layout.backend_repr) {
70 UsesVectorRegisters::FixedVector => {
71 let unit_size = match &arg_abi.mode {
73 PassMode::Cast { pad_i32_count: _, cast } if cast.prefix.is_empty() => {
74 cast.rest.unit.size
75 }
76 _ => size,
77 };
78
79 let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi();
80 let feature = match feature_def.iter().find(|(bits, _)| unit_size.bits() <= *bits) {
82 Some((_, feature)) => feature,
83 None => {
84 let (span, _hir_id) = loc();
85 tcx.dcx().emit_err(diagnostics::AbiErrorUnsupportedVectorType {
86 span,
87 ty: arg_abi.layout.ty,
88 is_call,
89 });
90 continue;
91 }
92 };
93 if !feature.is_empty() && !have_feature(Symbol::intern(feature)) {
94 let (span, _hir_id) = loc();
95 tcx.dcx().emit_err(diagnostics::AbiErrorDisabledVectorType {
96 span,
97 required_feature: feature,
98 abi: abi.conv.to_string(),
99 ty: arg_abi.layout.ty,
100 is_call,
101 is_scalable: false,
102 });
103 }
104 }
105 UsesVectorRegisters::ScalableVector => {
106 let Some(required_feature) =
107 tcx.sess.target.features_for_correct_scalable_vector_abi()
108 else {
109 continue;
110 };
111 if !required_feature.is_empty() && !have_feature(Symbol::intern(required_feature)) {
112 let (span, _) = loc();
113 tcx.dcx().emit_err(diagnostics::AbiErrorDisabledVectorType {
114 span,
115 required_feature,
116 abi: abi.conv.to_string(),
117 ty: arg_abi.layout.ty,
118 is_call,
119 is_scalable: true,
120 });
121 }
122 }
123 UsesVectorRegisters::No => {
124 continue;
125 }
126 }
127 }
128 if abi.conv == CanonAbi::X86(X86Call::Vectorcall) && !have_feature(sym::sse2) {
130 let (span, _hir_id) = loc();
131 tcx.dcx().emit_err(diagnostics::AbiRequiredTargetFeature {
132 span,
133 required_feature: "sse2",
134 abi: "vectorcall",
135 is_call,
136 });
137 }
138}
139
140fn do_check_unsized_params<'tcx>(
145 tcx: TyCtxt<'tcx>,
146 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
147 is_call: bool,
148 loc: impl Fn() -> (Span, HirId),
149) {
150 if fn_abi.conv.is_rustic_abi() {
152 return;
153 }
154
155 for arg_abi in fn_abi.args.iter() {
156 if !arg_abi.layout.layout.is_sized() {
157 let (span, _hir_id) = loc();
158 tcx.dcx().emit_err(diagnostics::AbiErrorUnsupportedUnsizedParameter {
159 span,
160 ty: arg_abi.layout.ty,
161 is_call,
162 });
163 }
164 }
165}
166
167fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
172 let typing_env = ty::TypingEnv::fully_monomorphized();
173 let ty = instance.ty(tcx, typing_env);
174 if ty.is_fn() && ty.fn_sig(tcx).abi() == ExternAbi::LlvmIntrinsic {
175 return;
178 }
179 let abi = match tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
180 {
181 Ok(abi) => abi,
182 Err(err) => {
183 codegen_handle_fn_abi_err(
184 tcx,
185 *err,
186 tcx.def_span(instance.def_id()),
187 FnAbiRequest::OfInstance { instance, extra_args: ty::List::empty() },
188 );
189 return;
191 }
192 };
193 let loc = || {
196 let def_id = instance.def_id();
197 (
198 tcx.def_span(def_id),
199 def_id.as_local().map(|did| tcx.local_def_id_to_hir_id(did)).unwrap_or(CRATE_HIR_ID),
200 )
201 };
202 do_check_unsized_params(tcx, abi, false, loc);
203 do_check_simd_vector_abi(tcx, abi, instance.def_id(), false, loc);
204}
205
206fn check_call_site_abi<'tcx>(
211 tcx: TyCtxt<'tcx>,
212 callee: Ty<'tcx>,
213 caller: InstanceKind<'tcx>,
214 loc: impl Fn() -> (Span, HirId) + Copy,
215) {
216 let extern_abi = callee.fn_sig(tcx).abi();
217 if extern_abi.is_rustic_abi() || extern_abi == ExternAbi::LlvmIntrinsic {
218 return;
226 }
227 let typing_env = ty::TypingEnv::fully_monomorphized();
228 let callee_abi = match *callee.kind() {
229 ty::FnPtr(..) => {
230 let sig = callee.fn_sig(tcx);
231 match tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((sig, ty::List::empty()))) {
232 Ok(callee_abi) => callee_abi,
233 Err(err) => {
234 codegen_handle_fn_abi_err(
235 tcx,
236 *err,
237 loc().0,
238 FnAbiRequest::OfFnPtr { sig, extra_args: ty::List::empty() },
239 );
240 return;
242 }
243 }
244 }
245 ty::FnDef(def_id, args) => {
246 if tcx.intrinsic(def_id).is_some() {
248 return;
249 }
250 let instance = ty::Instance::expect_resolve(
251 tcx,
252 typing_env,
253 def_id,
254 args.no_bound_vars().unwrap(),
255 DUMMY_SP,
256 );
257 if let InstanceKind::LlvmIntrinsic(..) = instance.def {
258 return;
260 }
261 match tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty()))) {
262 Ok(callee_abi) => callee_abi,
263 Err(err) => {
264 codegen_handle_fn_abi_err(
265 tcx,
266 *err,
267 loc().0,
268 FnAbiRequest::OfInstance { instance, extra_args: ty::List::empty() },
269 );
270 return;
272 }
273 }
274 }
275 _ => {
276 { ::core::panicking::panic_fmt(format_args!("Invalid function call")); };panic!("Invalid function call");
277 }
278 };
279
280 do_check_unsized_params(tcx, callee_abi, true, loc);
281 do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), true, loc);
282}
283
284fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
285 for (bb, _data) in traversal::mono_reachable(body, tcx, instance) {
287 let terminator = body.basic_blocks[bb].terminator();
288 match terminator.kind {
289 mir::TerminatorKind::Call { ref func, ref fn_span, .. }
290 | mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
291 let callee_ty = func.ty(body, tcx);
292 let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
293 tcx,
294 ty::TypingEnv::fully_monomorphized(),
295 ty::EarlyBinder::bind(tcx, callee_ty),
296 );
297 check_call_site_abi(tcx, callee_ty, body.source.instance, || {
298 let loc = Location {
299 block: bb,
300 statement_index: body.basic_blocks[bb].statements.len(),
301 };
302 (
303 *fn_span,
304 body.source_info(loc)
305 .scope
306 .lint_root(&body.source_scopes)
307 .unwrap_or(CRATE_HIR_ID),
308 )
309 });
310 }
311 _ => {}
312 }
313 }
314}
315
316pub(crate) fn check_feature_dependent_abi<'tcx>(
317 tcx: TyCtxt<'tcx>,
318 instance: Instance<'tcx>,
319 body: &'tcx mir::Body<'tcx>,
320) {
321 check_instance_abi(tcx, instance);
322 check_callees_abi(tcx, instance, body);
323}