rustc_hir_analysis/check/
entry.rs
1use std::ops::Not;
2
3use rustc_abi::ExternAbi;
4use rustc_hir as hir;
5use rustc_hir::Node;
6use rustc_infer::infer::TyCtxtInferExt;
7use rustc_middle::span_bug;
8use rustc_middle::ty::{self, TyCtxt, TypingMode};
9use rustc_session::config::EntryFnType;
10use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
11use rustc_span::{Span, sym};
12use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
13use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
14
15use super::check_function_signature;
16use crate::errors;
17
18pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
19 match tcx.entry_fn(()) {
20 Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
21 _ => {}
22 }
23}
24
25fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
26 let main_fnsig = tcx.fn_sig(main_def_id).instantiate_identity();
27 let main_span = tcx.def_span(main_def_id);
28
29 fn main_fn_diagnostics_def_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> LocalDefId {
30 if let Some(local_def_id) = def_id.as_local() {
31 let hir_type = tcx.type_of(local_def_id).instantiate_identity();
32 if !matches!(hir_type.kind(), ty::FnDef(..)) {
33 span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
34 }
35 local_def_id
36 } else {
37 CRATE_DEF_ID
38 }
39 }
40
41 fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
42 if !def_id.is_local() {
43 return None;
44 }
45 match tcx.hir_node_by_def_id(def_id.expect_local()) {
46 Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) => {
47 generics.params.is_empty().not().then_some(generics.span)
48 }
49 _ => {
50 span_bug!(tcx.def_span(def_id), "main has a non-function type");
51 }
52 }
53 }
54
55 fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
56 if !def_id.is_local() {
57 return None;
58 }
59 match tcx.hir_node_by_def_id(def_id.expect_local()) {
60 Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) => {
61 Some(generics.where_clause_span)
62 }
63 _ => {
64 span_bug!(tcx.def_span(def_id), "main has a non-function type");
65 }
66 }
67 }
68
69 fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
70 if !def_id.is_local() {
71 return None;
72 }
73 Some(tcx.def_span(def_id))
74 }
75
76 fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
77 if !def_id.is_local() {
78 return None;
79 }
80 match tcx.hir_node_by_def_id(def_id.expect_local()) {
81 Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) => {
82 Some(fn_sig.decl.output.span())
83 }
84 _ => {
85 span_bug!(tcx.def_span(def_id), "main has a non-function type");
86 }
87 }
88 }
89
90 let mut error = false;
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 tcx.dcx()
97 .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
98 error = true;
99 }
100
101 for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
102 tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span, annotated: main_span });
103 error = true;
104 }
105
106 if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
107 && !tcx.sess.target.is_like_wasm
109 && !tcx.sess.opts.actually_rustdoc
110 {
111 tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span });
112 error = true;
113 }
114
115 if error {
116 return;
117 }
118
119 let param_env = ty::ParamEnv::empty();
121 let expected_return_type;
122 if let Some(term_did) = tcx.lang_items().termination() {
123 let return_ty = main_fnsig.output();
124 let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
125 let Some(return_ty) = return_ty.no_bound_vars() else {
126 tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
127 return;
128 };
129 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
130 let cause = traits::ObligationCause::new(
131 return_ty_span,
132 main_diagnostics_def_id,
133 ObligationCauseCode::MainFunctionType,
134 );
135 let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
136 let norm_return_ty = ocx.normalize(&cause, param_env, return_ty);
137 ocx.register_bound(cause, param_env, norm_return_ty, term_did);
138 let errors = ocx.select_all_or_error();
139 if !errors.is_empty() {
140 infcx.err_ctxt().report_fulfillment_errors(errors);
141 error = true;
142 }
143 expected_return_type = norm_return_ty;
145 } else {
146 expected_return_type = tcx.types.unit;
148 }
149
150 if error {
151 return;
152 }
153
154 let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
155 [],
156 expected_return_type,
157 false,
158 hir::Safety::Safe,
159 ExternAbi::Rust,
160 ));
161
162 if check_function_signature(
163 tcx,
164 ObligationCause::new(
165 main_span,
166 main_diagnostics_def_id,
167 ObligationCauseCode::MainFunctionType,
168 ),
169 main_def_id,
170 expected_sig,
171 )
172 .is_err()
173 {
174 return;
175 }
176
177 let main_fn_generics = tcx.generics_of(main_def_id);
178 let main_fn_predicates = tcx.predicates_of(main_def_id);
179 if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
180 let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
181 tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
182 span: generics_param_span.unwrap_or(main_span),
183 label_span: generics_param_span,
184 });
185 } else if !main_fn_predicates.predicates.is_empty() {
186 let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
188 tcx.dcx().emit_err(errors::WhereClauseOnMain {
189 span: generics_where_clauses_span.unwrap_or(main_span),
190 generics_span: generics_where_clauses_span,
191 });
192 }
193}