1use std::cell::RefCell;
2
3use rustc_abi::ExternAbi;
4use rustc_hir as hir;
5use rustc_hir::def::DefKind;
6use rustc_hir::lang_items::LangItem;
7use rustc_hir_analysis::check::check_function_signature;
8use rustc_infer::infer::RegionVariableOrigin;
9use rustc_infer::traits::WellFormedLoc;
10use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
11use rustc_span::def_id::LocalDefId;
12use rustc_span::sym;
13use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
14use tracing::{debug, instrument};
15
16use crate::coercion::CoerceMany;
17use crate::gather_locals::GatherLocalsVisitor;
18use crate::{CoroutineTypes, Diverges, FnCtxt};
19
20#[instrument(skip(fcx, body), level = "debug")]
27pub(super) fn check_fn<'a, 'tcx>(
28 fcx: &mut FnCtxt<'a, 'tcx>,
29 fn_sig: ty::FnSig<'tcx>,
30 coroutine_types: Option<CoroutineTypes<'tcx>>,
31 decl: &'tcx hir::FnDecl<'tcx>,
32 fn_def_id: LocalDefId,
33 body: &'tcx hir::Body<'tcx>,
34 params_can_be_unsized: bool,
35) -> Option<CoroutineTypes<'tcx>> {
36 let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id);
37 let tcx = fcx.tcx;
38 let declared_ret_ty = fn_sig.output();
39 let ret_ty =
40 fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
41 declared_ret_ty,
42 fn_def_id,
43 decl.output.span(),
44 fcx.param_env,
45 ));
46
47 fcx.coroutine_types = coroutine_types;
48 fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
49
50 let span = body.value.span;
51
52 for param in body.params {
53 GatherLocalsVisitor::gather_from_param(fcx, param);
54 }
55
56 let maybe_va_list = fn_sig.c_variadic.then(|| {
59 let span = body.params.last().unwrap().span;
60 let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
61 let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
62
63 tcx.type_of(va_list_did).instantiate(tcx, &[region.into()])
64 });
65
66 let inputs_hir = tcx.hir_fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
68 let inputs_fn = fn_sig.inputs().iter().copied();
69 for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
70 if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
72 fcx.register_wf_obligation(
73 param_ty.into(),
74 param.span,
75 ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param {
76 function: fn_def_id,
77 param_idx: idx,
78 })),
79 );
80 }
81
82 let ty: Option<&hir::Ty<'_>> = inputs_hir.and_then(|h| h.get(idx));
84 let ty_span = ty.map(|ty| ty.span);
85 fcx.check_pat_top(param.pat, param_ty, ty_span, None, None);
86 if param.pat.is_never_pattern() {
87 fcx.function_diverges_because_of_empty_arguments.set(Diverges::Always {
88 span: param.pat.span,
89 custom_note: Some("any code following a never pattern is unreachable"),
90 });
91 }
92
93 if !params_can_be_unsized {
95 fcx.require_type_is_sized(
96 param_ty,
97 param.ty_span,
98 ObligationCauseCode::SizedArgumentType(
101 if ty_span == Some(param.span) && tcx.is_closure_like(fn_def_id.into()) {
102 None
103 } else {
104 ty.map(|ty| ty.hir_id)
105 },
106 ),
107 );
108 }
109
110 fcx.write_ty(param.hir_id, param_ty);
111 }
112
113 fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
114
115 if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
117 let return_or_body_span = match decl.output {
118 hir::FnRetTy::DefaultReturn(_) => body.value.span,
119 hir::FnRetTy::Return(ty) => ty.span,
120 };
121
122 fcx.require_type_is_sized(
123 declared_ret_ty,
124 return_or_body_span,
125 ObligationCauseCode::SizedReturnType,
126 );
127 }
128
129 fcx.is_whole_body.set(true);
130 fcx.check_return_or_body_tail(body.value, false);
131
132 let coercion = fcx.ret_coercion.take().unwrap().into_inner();
137 let mut actual_return_ty = coercion.complete(fcx);
138 debug!("actual_return_ty = {:?}", actual_return_ty);
139 if let ty::Dynamic(..) = declared_ret_ty.kind() {
140 actual_return_ty = fcx.next_ty_var(span);
144 debug!("actual_return_ty replaced with {:?}", actual_return_ty);
145 }
146
147 fcx.demand_suptype(span, ret_ty, actual_return_ty);
152
153 if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::PanicImpl) {
155 check_panic_info_fn(tcx, fn_def_id, fn_sig);
156 }
157
158 if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::Start) {
159 check_lang_start_fn(tcx, fn_sig, fn_def_id);
160 }
161
162 fcx.coroutine_types
163}
164
165fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) {
166 let span = tcx.def_span(fn_id);
167
168 let DefKind::Fn = tcx.def_kind(fn_id) else {
169 tcx.dcx().span_err(span, "should be a function");
170 return;
171 };
172
173 let generic_counts = tcx.generics_of(fn_id).own_counts();
174 if generic_counts.types != 0 {
175 tcx.dcx().span_err(span, "should have no type parameters");
176 }
177 if generic_counts.consts != 0 {
178 tcx.dcx().span_err(span, "should have no const parameters");
179 }
180
181 let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, Some(span));
182
183 let panic_info_ty = tcx.type_of(panic_info_did).instantiate(
185 tcx,
186 &[ty::GenericArg::from(ty::Region::new_bound(
187 tcx,
188 ty::INNERMOST,
189 ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BoundRegionKind::Anon },
190 ))],
191 );
192 let panic_info_ref_ty = Ty::new_imm_ref(
193 tcx,
194 ty::Region::new_bound(
195 tcx,
196 ty::INNERMOST,
197 ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon },
198 ),
199 panic_info_ty,
200 );
201
202 let bounds = tcx.mk_bound_variable_kinds(&[
203 ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon),
204 ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon),
205 ]);
206 let expected_sig = ty::Binder::bind_with_vars(
207 tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.safety, ExternAbi::Rust),
208 bounds,
209 );
210
211 let _ = check_function_signature(
212 tcx,
213 ObligationCause::new(span, fn_id, ObligationCauseCode::LangFunctionType(sym::panic_impl)),
214 fn_id.into(),
215 expected_sig,
216 );
217}
218
219fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id: LocalDefId) {
220 let generics = tcx.generics_of(def_id);
226 let fn_generic = generics.param_at(0, tcx);
227 let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
228 let main_fn_ty = Ty::new_fn_ptr(
229 tcx,
230 Binder::dummy(tcx.mk_fn_sig([], generic_ty, false, hir::Safety::Safe, ExternAbi::Rust)),
231 );
232
233 let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
234 [
235 main_fn_ty,
236 tcx.types.isize,
237 Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8)),
238 tcx.types.u8,
239 ],
240 tcx.types.isize,
241 false,
242 fn_sig.safety,
243 ExternAbi::Rust,
244 ));
245
246 let _ = check_function_signature(
247 tcx,
248 ObligationCause::new(
249 tcx.def_span(def_id),
250 def_id,
251 ObligationCauseCode::LangFunctionType(sym::start),
252 ),
253 def_id.into(),
254 expected_sig,
255 );
256}