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::{self, Instance, InstanceKind, Ty, TyCtxt};
7use rustc_span::def_id::DefId;
8use rustc_span::{DUMMY_SP, Span, Symbol, sym};
9use rustc_target::callconv::{FnAbi, PassMode};
10
11use crate::diagnostics;
12
13enum UsesVectorRegisters {
15 FixedVector,
17 ScalableVector,
19 No,
20}
21
22fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters {
25 match mode {
26 PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No,
27 PassMode::Cast { pad_i32_count: _, cast }
28 if cast.prefix.iter().any(|x| #[allow(non_exhaustive_omitted_patterns)] match x.kind {
RegKind::Vector { .. } => true,
_ => false,
}matches!(x.kind, RegKind::Vector { .. }))
29 || #[allow(non_exhaustive_omitted_patterns)] match cast.rest.unit.kind {
RegKind::Vector { .. } => true,
_ => false,
}matches!(cast.rest.unit.kind, RegKind::Vector { .. }) =>
30 {
31 UsesVectorRegisters::FixedVector
32 }
33 PassMode::Direct(..) | PassMode::Pair(..)
34 if #[allow(non_exhaustive_omitted_patterns)] match repr {
BackendRepr::SimdVector { .. } => true,
_ => false,
}matches!(repr, BackendRepr::SimdVector { .. }) =>
35 {
36 UsesVectorRegisters::FixedVector
37 }
38 PassMode::Direct(..) | PassMode::Pair(..)
39 if #[allow(non_exhaustive_omitted_patterns)] match repr {
BackendRepr::SimdScalableVector { .. } => true,
_ => false,
}matches!(repr, BackendRepr::SimdScalableVector { .. }) =>
40 {
41 UsesVectorRegisters::ScalableVector
42 }
43 _ => UsesVectorRegisters::No,
44 }
45}
46
47fn do_check_simd_vector_abi<'tcx>(
52 tcx: TyCtxt<'tcx>,
53 abi: &FnAbi<'tcx, Ty<'tcx>>,
54 def_id: DefId,
55 is_call: bool,
56 loc: impl Fn() -> (Span, HirId),
57) {
58 let codegen_attrs = tcx.codegen_fn_attrs(def_id);
59 let have_feature = |feat: Symbol| {
60 let target_feats = tcx.sess.internal_target_features.contains(&feat);
61 let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat);
62 target_feats || fn_feats
63 };
64 for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
65 let size = arg_abi.layout.size;
66 match passes_vectors_by_value(&arg_abi.mode, &arg_abi.layout.backend_repr) {
67 UsesVectorRegisters::FixedVector => {
68 let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi();
69 let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
71 Some((_, feature)) => feature,
72 None => {
73 let (span, _hir_id) = loc();
74 tcx.dcx().emit_err(diagnostics::AbiErrorUnsupportedVectorType {
75 span,
76 ty: arg_abi.layout.ty,
77 is_call,
78 });
79 continue;
80 }
81 };
82 if !feature.is_empty() && !have_feature(Symbol::intern(feature)) {
83 let (span, _hir_id) = loc();
84 tcx.dcx().emit_err(diagnostics::AbiErrorDisabledVectorType {
85 span,
86 required_feature: feature,
87 abi: abi.conv.to_string(),
88 ty: arg_abi.layout.ty,
89 is_call,
90 is_scalable: false,
91 });
92 }
93 }
94 UsesVectorRegisters::ScalableVector => {
95 let Some(required_feature) =
96 tcx.sess.target.features_for_correct_scalable_vector_abi()
97 else {
98 continue;
99 };
100 if !required_feature.is_empty() && !have_feature(Symbol::intern(required_feature)) {
101 let (span, _) = loc();
102 tcx.dcx().emit_err(diagnostics::AbiErrorDisabledVectorType {
103 span,
104 required_feature,
105 abi: abi.conv.to_string(),
106 ty: arg_abi.layout.ty,
107 is_call,
108 is_scalable: true,
109 });
110 }
111 }
112 UsesVectorRegisters::No => {
113 continue;
114 }
115 }
116 }
117 if abi.conv == CanonAbi::X86(X86Call::Vectorcall) && !have_feature(sym::sse2) {
119 let (span, _hir_id) = loc();
120 tcx.dcx().emit_err(diagnostics::AbiRequiredTargetFeature {
121 span,
122 required_feature: "sse2",
123 abi: "vectorcall",
124 is_call,
125 });
126 }
127}
128
129fn do_check_unsized_params<'tcx>(
134 tcx: TyCtxt<'tcx>,
135 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
136 is_call: bool,
137 loc: impl Fn() -> (Span, HirId),
138) {
139 if fn_abi.conv.is_rustic_abi() {
141 return;
142 }
143
144 for arg_abi in fn_abi.args.iter() {
145 if !arg_abi.layout.layout.is_sized() {
146 let (span, _hir_id) = loc();
147 tcx.dcx().emit_err(diagnostics::AbiErrorUnsupportedUnsizedParameter {
148 span,
149 ty: arg_abi.layout.ty,
150 is_call,
151 });
152 }
153 }
154}
155
156fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
161 let typing_env = ty::TypingEnv::fully_monomorphized();
162 let ty = instance.ty(tcx, typing_env);
163 if ty.is_fn() && ty.fn_sig(tcx).abi() == ExternAbi::LlvmIntrinsic {
164 return;
167 }
168 let Ok(abi) = tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
169 else {
170 tcx.dcx().delayed_bug("ABI computation failure should lead to compilation failure");
173 return;
174 };
175 let loc = || {
178 let def_id = instance.def_id();
179 (
180 tcx.def_span(def_id),
181 def_id.as_local().map(|did| tcx.local_def_id_to_hir_id(did)).unwrap_or(CRATE_HIR_ID),
182 )
183 };
184 do_check_unsized_params(tcx, abi, false, loc);
185 do_check_simd_vector_abi(tcx, abi, instance.def_id(), false, loc);
186}
187
188fn check_call_site_abi<'tcx>(
193 tcx: TyCtxt<'tcx>,
194 callee: Ty<'tcx>,
195 caller: InstanceKind<'tcx>,
196 loc: impl Fn() -> (Span, HirId) + Copy,
197) {
198 let extern_abi = callee.fn_sig(tcx).abi();
199 if extern_abi.is_rustic_abi() || extern_abi == ExternAbi::LlvmIntrinsic {
200 return;
205 }
206 let typing_env = ty::TypingEnv::fully_monomorphized();
207 let callee_abi = match *callee.kind() {
208 ty::FnPtr(..) => {
209 tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((callee.fn_sig(tcx), ty::List::empty())))
210 }
211 ty::FnDef(def_id, args) => {
212 if tcx.intrinsic(def_id).is_some() {
214 return;
215 }
216 let instance = ty::Instance::expect_resolve(
217 tcx,
218 typing_env,
219 def_id,
220 args.no_bound_vars().unwrap(),
221 DUMMY_SP,
222 );
223 if let InstanceKind::LlvmIntrinsic(..) = instance.def {
224 return;
226 }
227 tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
228 }
229 _ => {
230 { ::core::panicking::panic_fmt(format_args!("Invalid function call")); };panic!("Invalid function call");
231 }
232 };
233
234 let Ok(callee_abi) = callee_abi else {
235 return;
237 };
238 do_check_unsized_params(tcx, callee_abi, true, loc);
239 do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), true, loc);
240}
241
242fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
243 for (bb, _data) in traversal::mono_reachable(body, tcx, instance) {
245 let terminator = body.basic_blocks[bb].terminator();
246 match terminator.kind {
247 mir::TerminatorKind::Call { ref func, ref fn_span, .. }
248 | mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
249 let callee_ty = func.ty(body, tcx);
250 let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
251 tcx,
252 ty::TypingEnv::fully_monomorphized(),
253 ty::EarlyBinder::bind(tcx, callee_ty),
254 );
255 check_call_site_abi(tcx, callee_ty, body.source.instance, || {
256 let loc = Location {
257 block: bb,
258 statement_index: body.basic_blocks[bb].statements.len(),
259 };
260 (
261 *fn_span,
262 body.source_info(loc)
263 .scope
264 .lint_root(&body.source_scopes)
265 .unwrap_or(CRATE_HIR_ID),
266 )
267 });
268 }
269 _ => {}
270 }
271 }
272}
273
274pub(crate) fn check_feature_dependent_abi<'tcx>(
275 tcx: TyCtxt<'tcx>,
276 instance: Instance<'tcx>,
277 body: &'tcx mir::Body<'tcx>,
278) {
279 check_instance_abi(tcx, instance);
280 check_callees_abi(tcx, instance, body);
281}