1use std::cell::RefCell;
2
3use rustc_hir as hir;
4use rustc_hir::def::DefKind;
5use rustc_hir::lang_items::LangItem;
6use rustc_hir_analysis::check::check_function_signature;
7use rustc_infer::infer::RegionVariableOrigin;
8use rustc_infer::traits::WellFormedLoc;
9use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
10use rustc_span::def_id::LocalDefId;
11use rustc_span::sym;
12use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
13use tracing::{debug, instrument};
14
15use crate::coercion::CoerceMany;
16use crate::gather_locals::GatherLocalsVisitor;
17use crate::{CoroutineTypes, Diverges, FnCtxt};
18
19#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("check_fn",
"rustc_hir_typeck::check", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/check.rs"),
::tracing_core::__macro_support::Option::Some(25u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::check"),
::tracing_core::field::FieldSet::new(&["fn_sig",
"coroutine_types", "decl", "fn_def_id",
"params_can_be_unsized"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&fn_sig)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&coroutine_types)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&decl)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&fn_def_id)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(¶ms_can_be_unsized
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Option<CoroutineTypes<'tcx>> =
loop {};
return __tracing_attr_fake_return;
}
{
let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id);
let tcx = fcx.tcx;
let declared_ret_ty = fn_sig.output();
let ret_ty =
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(declared_ret_ty,
fn_def_id, decl.output.span(), fcx.param_env));
fcx.coroutine_types = coroutine_types;
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
let span = body.value.span;
for param in body.params {
GatherLocalsVisitor::gather_from_param(fcx, param);
}
let maybe_va_list =
fn_sig.c_variadic().then(||
{
let span = body.params.last().unwrap().span;
let va_list_did =
tcx.require_lang_item(LangItem::VaList, span);
let region =
fcx.next_region_var(RegionVariableOrigin::Misc(span));
tcx.type_of(va_list_did).instantiate(tcx,
&[region.into()]).skip_norm_wip()
});
let inputs_hir =
tcx.hir_fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
let inputs_fn = fn_sig.inputs().iter().copied();
for (idx, (param_ty, param)) in
inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
fcx.register_wf_obligation(param_ty.into(), param.span,
ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param {
function: fn_def_id,
param_idx: idx,
})));
}
let ty: Option<&hir::Ty<'_>> =
inputs_hir.and_then(|h| h.get(idx));
let ty_span = ty.map(|ty| ty.span);
fcx.check_pat_top(param.pat, param_ty, ty_span, None, None);
if param.pat.is_never_pattern() {
fcx.function_diverges_because_of_empty_arguments.set(Diverges::Always {
span: param.pat.span,
custom_note: Some("any code following a never pattern is unreachable"),
});
}
if !params_can_be_unsized {
fcx.require_type_is_sized(param_ty, param.ty_span,
ObligationCauseCode::SizedArgumentType(if ty_span ==
Some(param.span) && tcx.is_closure_like(fn_def_id.into()) {
None
} else { ty.map(|ty| ty.hir_id) }));
}
fcx.write_ty(param.hir_id, param_ty);
}
fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id,
fn_sig);
if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
let return_or_body_span =
match decl.output {
hir::FnRetTy::DefaultReturn(_) => body.value.span,
hir::FnRetTy::Return(ty) => ty.span,
};
fcx.require_type_is_sized(declared_ret_ty,
return_or_body_span, ObligationCauseCode::SizedReturnType);
}
fcx.is_whole_body.set(true);
fcx.check_return_or_body_tail(body.value, false);
let coercion = fcx.ret_coercion.take().unwrap().into_inner();
let mut actual_return_ty = coercion.complete(fcx);
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/check.rs:137",
"rustc_hir_typeck::check", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/check.rs"),
::tracing_core::__macro_support::Option::Some(137u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::check"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("actual_return_ty = {0:?}",
actual_return_ty) as &dyn Value))])
});
} else { ; }
};
if let ty::Dynamic(..) = declared_ret_ty.kind() {
actual_return_ty = fcx.next_ty_var(span);
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/check.rs:143",
"rustc_hir_typeck::check", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/check.rs"),
::tracing_core::__macro_support::Option::Some(143u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::check"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("actual_return_ty replaced with {0:?}",
actual_return_ty) as &dyn Value))])
});
} else { ; }
};
}
fcx.demand_suptype(span, ret_ty, actual_return_ty);
if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::PanicImpl) {
check_panic_info_fn(tcx, fn_def_id, fn_sig);
}
if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::Start) {
check_lang_start_fn(tcx, fn_sig, fn_def_id);
}
fcx.coroutine_types
}
}
}#[instrument(skip(fcx, body), level = "debug")]
26pub(super) fn check_fn<'a, 'tcx>(
27 fcx: &mut FnCtxt<'a, 'tcx>,
28 fn_sig: ty::FnSig<'tcx>,
29 coroutine_types: Option<CoroutineTypes<'tcx>>,
30 decl: &'tcx hir::FnDecl<'tcx>,
31 fn_def_id: LocalDefId,
32 body: &'tcx hir::Body<'tcx>,
33 params_can_be_unsized: bool,
34) -> Option<CoroutineTypes<'tcx>> {
35 let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id);
36 let tcx = fcx.tcx;
37 let declared_ret_ty = fn_sig.output();
38 let ret_ty =
39 fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
40 declared_ret_ty,
41 fn_def_id,
42 decl.output.span(),
43 fcx.param_env,
44 ));
45
46 fcx.coroutine_types = coroutine_types;
47 fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
48
49 let span = body.value.span;
50
51 for param in body.params {
52 GatherLocalsVisitor::gather_from_param(fcx, param);
53 }
54
55 let maybe_va_list = fn_sig.c_variadic().then(|| {
58 let span = body.params.last().unwrap().span;
59 let va_list_did = tcx.require_lang_item(LangItem::VaList, span);
60 let region = fcx.next_region_var(RegionVariableOrigin::Misc(span));
61
62 tcx.type_of(va_list_did).instantiate(tcx, &[region.into()]).skip_norm_wip()
63 });
64
65 let inputs_hir = tcx.hir_fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
67 let inputs_fn = fn_sig.inputs().iter().copied();
68 for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
69 if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
71 fcx.register_wf_obligation(
72 param_ty.into(),
73 param.span,
74 ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param {
75 function: fn_def_id,
76 param_idx: idx,
77 })),
78 );
79 }
80
81 let ty: Option<&hir::Ty<'_>> = inputs_hir.and_then(|h| h.get(idx));
83 let ty_span = ty.map(|ty| ty.span);
84 fcx.check_pat_top(param.pat, param_ty, ty_span, None, None);
85 if param.pat.is_never_pattern() {
86 fcx.function_diverges_because_of_empty_arguments.set(Diverges::Always {
87 span: param.pat.span,
88 custom_note: Some("any code following a never pattern is unreachable"),
89 });
90 }
91
92 if !params_can_be_unsized {
94 fcx.require_type_is_sized(
95 param_ty,
96 param.ty_span,
97 ObligationCauseCode::SizedArgumentType(
100 if ty_span == Some(param.span) && tcx.is_closure_like(fn_def_id.into()) {
101 None
102 } else {
103 ty.map(|ty| ty.hir_id)
104 },
105 ),
106 );
107 }
108
109 fcx.write_ty(param.hir_id, param_ty);
110 }
111
112 fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
113
114 if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
116 let return_or_body_span = match decl.output {
117 hir::FnRetTy::DefaultReturn(_) => body.value.span,
118 hir::FnRetTy::Return(ty) => ty.span,
119 };
120
121 fcx.require_type_is_sized(
122 declared_ret_ty,
123 return_or_body_span,
124 ObligationCauseCode::SizedReturnType,
125 );
126 }
127
128 fcx.is_whole_body.set(true);
129 fcx.check_return_or_body_tail(body.value, false);
130
131 let coercion = fcx.ret_coercion.take().unwrap().into_inner();
136 let mut actual_return_ty = coercion.complete(fcx);
137 debug!("actual_return_ty = {:?}", actual_return_ty);
138 if let ty::Dynamic(..) = declared_ret_ty.kind() {
139 actual_return_ty = fcx.next_ty_var(span);
143 debug!("actual_return_ty replaced with {:?}", actual_return_ty);
144 }
145
146 fcx.demand_suptype(span, ret_ty, actual_return_ty);
151
152 if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::PanicImpl) {
154 check_panic_info_fn(tcx, fn_def_id, fn_sig);
155 }
156
157 if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::Start) {
158 check_lang_start_fn(tcx, fn_sig, fn_def_id);
159 }
160
161 fcx.coroutine_types
162}
163
164fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) {
165 let span = tcx.def_span(fn_id);
166
167 let DefKind::Fn = tcx.def_kind(fn_id) else {
168 tcx.dcx().span_err(span, "should be a function");
169 return;
170 };
171
172 let generic_counts = tcx.generics_of(fn_id).own_counts();
173 if generic_counts.types != 0 {
174 tcx.dcx().span_err(span, "should have no type parameters");
175 }
176 if generic_counts.consts != 0 {
177 tcx.dcx().span_err(span, "should have no const parameters");
178 }
179
180 let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, span);
181
182 let panic_info_ty = tcx
184 .type_of(panic_info_did)
185 .instantiate(
186 tcx,
187 &[ty::GenericArg::from(ty::Region::new_bound(
188 tcx,
189 ty::INNERMOST,
190 ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BoundRegionKind::Anon },
191 ))],
192 )
193 .skip_norm_wip();
194 let panic_info_ref_ty = Ty::new_imm_ref(
195 tcx,
196 ty::Region::new_bound(
197 tcx,
198 ty::INNERMOST,
199 ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon },
200 ),
201 panic_info_ty,
202 );
203
204 let bounds = tcx.mk_bound_variable_kinds(&[
205 ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon),
206 ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon),
207 ]);
208 let expected_sig = ty::Binder::bind_with_vars(
209 tcx.mk_fn_sig_rust_abi([panic_info_ref_ty], tcx.types.never, fn_sig.safety()),
210 bounds,
211 );
212
213 let _ = check_function_signature(
214 tcx,
215 ObligationCause::new(span, fn_id, ObligationCauseCode::LangFunctionType(sym::panic_impl)),
216 fn_id.into(),
217 expected_sig,
218 );
219}
220
221fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id: LocalDefId) {
222 let generics = tcx.generics_of(def_id);
228 let fn_generic = generics.param_at(0, tcx);
229 let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
230 let main_fn_ty =
231 Ty::new_fn_ptr(tcx, Binder::dummy(tcx.mk_fn_sig_safe_rust_abi([], generic_ty)));
232
233 let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig_rust_abi(
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 fn_sig.safety(),
242 ));
243
244 let _ = check_function_signature(
245 tcx,
246 ObligationCause::new(
247 tcx.def_span(def_id),
248 def_id,
249 ObligationCauseCode::LangFunctionType(sym::start),
250 ),
251 def_id.into(),
252 expected_sig,
253 );
254}