rustc_hir_analysis/check/
entry.rs1use std::ops::Not;
2
3use rustc_hir as hir;
4use rustc_hir::{Node, find_attr};
5use rustc_infer::infer::TyCtxtInferExt;
6use rustc_infer::traits::TraitErrors;
7use rustc_middle::span_bug;
8use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized};
9use rustc_session::config::EntryFnType;
10use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
11use rustc_span::{ErrorGuaranteed, Span};
12use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
13use rustc_trait_selection::regions::InferCtxtRegionExt;
14use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
15
16use super::check_function_signature;
17use crate::diagnostics;
18
19pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
20 match tcx.entry_fn(()) {
21 Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
22 _ => Ok(()),
23 }
24}
25
26fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuaranteed> {
27 let main_fnsig = tcx.fn_sig(main_def_id).instantiate_identity().skip_norm_wip();
28 let main_span = tcx.def_span(main_def_id);
29
30 fn main_fn_diagnostics_def_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> LocalDefId {
31 if let Some(local_def_id) = def_id.as_local() {
32 let hir_type = tcx.type_of(local_def_id).instantiate_identity().skip_norm_wip();
33 if !#[allow(non_exhaustive_omitted_patterns)] match hir_type.kind() {
ty::FnDef(..) => true,
_ => false,
}matches!(hir_type.kind(), ty::FnDef(..)) {
34 ::rustc_middle::util::bug::span_bug_fmt(sp,
format_args!("main has a non-function type: found `{0}`", hir_type));span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
35 }
36 local_def_id
37 } else {
38 CRATE_DEF_ID
39 }
40 }
41
42 fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
43 if !def_id.is_local() {
44 return None;
45 }
46 match tcx.hir_node_by_def_id(def_id.expect_local()) {
47 Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) => {
48 generics.params.is_empty().not().then_some(generics.span)
49 }
50 _ => {
51 ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(def_id),
format_args!("main has a non-function type"));span_bug!(tcx.def_span(def_id), "main has a non-function type");
52 }
53 }
54 }
55
56 fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
57 if !def_id.is_local() {
58 return None;
59 }
60 match tcx.hir_node_by_def_id(def_id.expect_local()) {
61 Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) => {
62 Some(generics.where_clause_span)
63 }
64 _ => {
65 ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(def_id),
format_args!("main has a non-function type"));span_bug!(tcx.def_span(def_id), "main has a non-function type");
66 }
67 }
68 }
69
70 fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
71 if !def_id.is_local() {
72 return None;
73 }
74 Some(tcx.def_span(def_id))
75 }
76
77 fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
78 if !def_id.is_local() {
79 return None;
80 }
81 match tcx.hir_node_by_def_id(def_id.expect_local()) {
82 Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) => {
83 Some(fn_sig.decl.output.span())
84 }
85 _ => {
86 ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(def_id),
format_args!("main has a non-function type"));span_bug!(tcx.def_span(def_id), "main has a non-function type");
87 }
88 }
89 }
90
91 let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span);
92
93 let main_asyncness = tcx.asyncness(main_def_id);
94 if main_asyncness.is_async() {
95 let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
96 return Err(tcx.dcx().emit_err(diagnostics::MainFunctionAsync {
97 span: main_span,
98 asyncness: asyncness_span,
99 }));
100 }
101
102 if let Some(attr_span) = {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(main_def_id, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(TrackCaller(span)) => {
break 'done Some(*span);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, main_def_id, TrackCaller(span) => *span) {
103 return Err(tcx
104 .dcx()
105 .emit_err(diagnostics::TrackCallerOnMain { span: attr_span, annotated: main_span }));
106 }
107
108 if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
109 && !tcx.sess.target.is_like_wasm
111 && !tcx.sess.opts.actually_rustdoc
112 {
113 return Err(tcx.dcx().emit_err(diagnostics::TargetFeatureOnMain { main: main_span }));
114 }
115
116 let param_env = ty::ParamEnv::empty();
118 let expected_return_type;
119 if let Some(term_did) = tcx.lang_items().termination() {
120 let return_ty = main_fnsig.output();
121 let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
122 let Some(return_ty) = return_ty.no_bound_vars() else {
123 return Err(tcx
124 .dcx()
125 .emit_err(diagnostics::MainFunctionReturnTypeGeneric { span: return_ty_span }));
126 };
127 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
128 let cause = traits::ObligationCause::new(
129 return_ty_span,
130 main_diagnostics_def_id,
131 ObligationCauseCode::MainFunctionType,
132 );
133 let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
134 let norm_return_ty = ocx.normalize(&cause, param_env, Unnormalized::new_wip(return_ty));
135 ocx.register_bound(cause, param_env, norm_return_ty, term_did);
136 let errors = ocx.evaluate_obligations_error_on_ambiguity();
137 if let TraitErrors::HasErrors(errors) = errors {
138 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
139 }
140
141 let region_errors =
142 infcx.resolve_regions(main_diagnostics_def_id, param_env, ty::List::empty());
143
144 if !region_errors.is_empty() {
145 return Err(infcx
146 .err_ctxt()
147 .report_region_errors(main_diagnostics_def_id, ®ion_errors));
148 }
149 expected_return_type = norm_return_ty;
151 } else {
152 expected_return_type = tcx.types.unit;
154 }
155
156 let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig_safe_rust_abi([], expected_return_type));
157
158 check_function_signature(
159 tcx,
160 ObligationCause::new(
161 main_span,
162 main_diagnostics_def_id,
163 ObligationCauseCode::MainFunctionType,
164 ),
165 main_def_id,
166 expected_sig,
167 )?;
168
169 let main_fn_generics = tcx.generics_of(main_def_id);
170 let main_fn_clauses = tcx.clauses_of(main_def_id);
171 if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
172 let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
173 return Err(tcx.dcx().emit_err(diagnostics::MainFunctionGenericParameters {
174 span: generics_param_span.unwrap_or(main_span),
175 label_span: generics_param_span,
176 }));
177 } else if !main_fn_clauses.clauses.is_empty() {
178 let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
180 return Err(tcx.dcx().emit_err(diagnostics::WhereClauseOnMain {
181 span: generics_where_clauses_span.unwrap_or(main_span),
182 generics_span: generics_where_clauses_span,
183 }));
184 }
185
186 Ok(())
187}