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