rustc_monomorphize/mono_checks/
abi_check.rs
1use rustc_abi::{BackendRepr, RegKind};
4use rustc_hir::CRATE_HIR_ID;
5use rustc_middle::mir::{self, traversal};
6use rustc_middle::ty::inherent::*;
7use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt};
8use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES;
9use rustc_span::def_id::DefId;
10use rustc_span::{DUMMY_SP, Span, Symbol};
11use rustc_target::callconv::{FnAbi, PassMode};
12
13use crate::errors::{
14 AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef,
15 AbiErrorUnsupportedVectorTypeCall, AbiErrorUnsupportedVectorTypeDef,
16};
17
18fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
19 match mode {
20 PassMode::Ignore | PassMode::Indirect { .. } => false,
21 PassMode::Cast { pad_i32: _, cast } => {
22 cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
23 || cast.rest.unit.kind == RegKind::Vector
24 }
25 PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::Vector { .. }),
26 }
27}
28
29fn do_check_abi<'tcx>(
34 tcx: TyCtxt<'tcx>,
35 abi: &FnAbi<'tcx, Ty<'tcx>>,
36 target_feature_def: DefId,
37 mut emit_err: impl FnMut(Option<&'static str>),
38) {
39 let feature_def = tcx.sess.target.features_for_correct_vector_abi();
40 let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def);
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 emit_err(None);
49 continue;
50 }
51 };
52 let feature_sym = Symbol::intern(feature);
53 if !tcx.sess.unstable_target_features.contains(&feature_sym)
54 && !codegen_attrs.target_features.iter().any(|x| x.name == feature_sym)
55 {
56 emit_err(Some(&feature));
57 }
58 }
59 }
60}
61
62fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
65 let typing_env = ty::TypingEnv::fully_monomorphized();
66 let Ok(abi) = tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
67 else {
68 return;
71 };
72 do_check_abi(tcx, abi, instance.def_id(), |required_feature| {
73 let span = tcx.def_span(instance.def_id());
74 if let Some(required_feature) = required_feature {
75 tcx.emit_node_span_lint(
76 ABI_UNSUPPORTED_VECTOR_TYPES,
77 CRATE_HIR_ID,
78 span,
79 AbiErrorDisabledVectorTypeDef { span, required_feature },
80 );
81 } else {
82 tcx.emit_node_span_lint(
83 ABI_UNSUPPORTED_VECTOR_TYPES,
84 CRATE_HIR_ID,
85 span,
86 AbiErrorUnsupportedVectorTypeDef { span },
87 );
88 }
89 })
90}
91
92fn check_call_site_abi<'tcx>(
95 tcx: TyCtxt<'tcx>,
96 callee: Ty<'tcx>,
97 span: Span,
98 caller: InstanceKind<'tcx>,
99) {
100 if callee.fn_sig(tcx).abi().is_rust() {
101 return;
103 }
104 let typing_env = ty::TypingEnv::fully_monomorphized();
105 let callee_abi = match *callee.kind() {
106 ty::FnPtr(..) => {
107 tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((callee.fn_sig(tcx), ty::List::empty())))
108 }
109 ty::FnDef(def_id, args) => {
110 if tcx.intrinsic(def_id).is_some() {
112 return;
113 }
114 let instance = ty::Instance::expect_resolve(tcx, typing_env, def_id, args, DUMMY_SP);
115 tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
116 }
117 _ => {
118 panic!("Invalid function call");
119 }
120 };
121
122 let Ok(callee_abi) = callee_abi else {
123 return;
125 };
126 do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| {
127 if let Some(required_feature) = required_feature {
128 tcx.emit_node_span_lint(
129 ABI_UNSUPPORTED_VECTOR_TYPES,
130 CRATE_HIR_ID,
131 span,
132 AbiErrorDisabledVectorTypeCall { span, required_feature },
133 );
134 } else {
135 tcx.emit_node_span_lint(
136 ABI_UNSUPPORTED_VECTOR_TYPES,
137 CRATE_HIR_ID,
138 span,
139 AbiErrorUnsupportedVectorTypeCall { span },
140 );
141 }
142 });
143}
144
145fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
146 for (bb, _data) in traversal::mono_reachable(body, tcx, instance) {
148 let terminator = body.basic_blocks[bb].terminator();
149 match terminator.kind {
150 mir::TerminatorKind::Call { ref func, ref fn_span, .. }
151 | mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
152 let callee_ty = func.ty(body, tcx);
153 let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
154 tcx,
155 ty::TypingEnv::fully_monomorphized(),
156 ty::EarlyBinder::bind(callee_ty),
157 );
158 check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance);
159 }
160 _ => {}
161 }
162 }
163}
164
165pub(crate) fn check_feature_dependent_abi<'tcx>(
166 tcx: TyCtxt<'tcx>,
167 instance: Instance<'tcx>,
168 body: &'tcx mir::Body<'tcx>,
169) {
170 check_instance_abi(tcx, instance);
171 check_callees_abi(tcx, instance, body);
172}