rustc_monomorphize/mono_checks/
abi_check.rs1use rustc_abi::{BackendRepr, CanonAbi, 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::errors;
12
13fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
14 match mode {
15 PassMode::Ignore | PassMode::Indirect { .. } => false,
16 PassMode::Cast { pad_i32: _, cast } => {
17 cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
18 || cast.rest.unit.kind == RegKind::Vector
19 }
20 PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }),
21 }
22}
23
24fn do_check_simd_vector_abi<'tcx>(
29 tcx: TyCtxt<'tcx>,
30 abi: &FnAbi<'tcx, Ty<'tcx>>,
31 def_id: DefId,
32 is_call: bool,
33 loc: impl Fn() -> (Span, HirId),
34) {
35 let feature_def = tcx.sess.target.features_for_correct_vector_abi();
36 let codegen_attrs = tcx.codegen_fn_attrs(def_id);
37 let have_feature = |feat: Symbol| {
38 tcx.sess.unstable_target_features.contains(&feat)
39 || codegen_attrs.target_features.iter().any(|x| x.name == feat)
40 };
41 for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
42 let size = arg_abi.layout.size;
43 if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) {
44 let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
46 Some((_, feature)) => feature,
47 None => {
48 let (span, _hir_id) = loc();
49 tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
50 span,
51 ty: arg_abi.layout.ty,
52 is_call,
53 });
54 continue;
55 }
56 };
57 if !have_feature(Symbol::intern(feature)) {
58 let (span, _hir_id) = loc();
60 tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
61 span,
62 required_feature: feature,
63 ty: arg_abi.layout.ty,
64 is_call,
65 });
66 }
67 }
68 }
69 if abi.conv == CanonAbi::X86(X86Call::Vectorcall) && !have_feature(sym::sse2) {
71 let (span, _hir_id) = loc();
72 tcx.dcx().emit_err(errors::AbiRequiredTargetFeature {
73 span,
74 required_feature: "sse2",
75 abi: "vectorcall",
76 is_call,
77 });
78 }
79}
80
81fn do_check_unsized_params<'tcx>(
86 tcx: TyCtxt<'tcx>,
87 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
88 is_call: bool,
89 loc: impl Fn() -> (Span, HirId),
90) {
91 if fn_abi.conv.is_rustic_abi() {
93 return;
94 }
95
96 for arg_abi in fn_abi.args.iter() {
97 if !arg_abi.layout.layout.is_sized() {
98 let (span, _hir_id) = loc();
99 tcx.dcx().emit_err(errors::AbiErrorUnsupportedUnsizedParameter {
100 span,
101 ty: arg_abi.layout.ty,
102 is_call,
103 });
104 }
105 }
106}
107
108fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
113 let typing_env = ty::TypingEnv::fully_monomorphized();
114 let Ok(abi) = tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
115 else {
116 tcx.dcx().delayed_bug("ABI computation failure should lead to compilation failure");
119 return;
120 };
121 let loc = || {
128 let def_id = instance.def_id();
129 (
130 tcx.def_span(def_id),
131 def_id.as_local().map(|did| tcx.local_def_id_to_hir_id(did)).unwrap_or(CRATE_HIR_ID),
132 )
133 };
134 do_check_unsized_params(tcx, abi, false, loc);
135 do_check_simd_vector_abi(tcx, abi, instance.def_id(), false, loc);
136}
137
138fn check_call_site_abi<'tcx>(
143 tcx: TyCtxt<'tcx>,
144 callee: Ty<'tcx>,
145 caller: InstanceKind<'tcx>,
146 loc: impl Fn() -> (Span, HirId) + Copy,
147) {
148 if callee.fn_sig(tcx).abi().is_rustic_abi() {
149 return;
152 }
153 let typing_env = ty::TypingEnv::fully_monomorphized();
154 let callee_abi = match *callee.kind() {
155 ty::FnPtr(..) => {
156 tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((callee.fn_sig(tcx), ty::List::empty())))
157 }
158 ty::FnDef(def_id, args) => {
159 if tcx.intrinsic(def_id).is_some() {
161 return;
162 }
163 let instance = ty::Instance::expect_resolve(tcx, typing_env, def_id, args, DUMMY_SP);
164 tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
165 }
166 _ => {
167 panic!("Invalid function call");
168 }
169 };
170
171 let Ok(callee_abi) = callee_abi else {
172 return;
174 };
175 do_check_unsized_params(tcx, callee_abi, true, loc);
176 do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), true, loc);
177}
178
179fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
180 for (bb, _data) in traversal::mono_reachable(body, tcx, instance) {
182 let terminator = body.basic_blocks[bb].terminator();
183 match terminator.kind {
184 mir::TerminatorKind::Call { ref func, ref fn_span, .. }
185 | mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
186 let callee_ty = func.ty(body, tcx);
187 let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
188 tcx,
189 ty::TypingEnv::fully_monomorphized(),
190 ty::EarlyBinder::bind(callee_ty),
191 );
192 check_call_site_abi(tcx, callee_ty, body.source.instance, || {
193 let loc = Location {
194 block: bb,
195 statement_index: body.basic_blocks[bb].statements.len(),
196 };
197 (
198 *fn_span,
199 body.source_info(loc)
200 .scope
201 .lint_root(&body.source_scopes)
202 .unwrap_or(CRATE_HIR_ID),
203 )
204 });
205 }
206 _ => {}
207 }
208 }
209}
210
211pub(crate) fn check_feature_dependent_abi<'tcx>(
212 tcx: TyCtxt<'tcx>,
213 instance: Instance<'tcx>,
214 body: &'tcx mir::Body<'tcx>,
215) {
216 check_instance_abi(tcx, instance);
217 check_callees_abi(tcx, instance, body);
218}