rustc_hir_analysis/check/
entry.rs1use std::ops::Not;
2
3use rustc_abi::ExternAbi;
4use rustc_attr_data_structures::{AttributeKind, find_attr};
5use rustc_hir as hir;
6use rustc_hir::Node;
7use rustc_infer::infer::TyCtxtInferExt;
8use rustc_middle::span_bug;
9use rustc_middle::ty::{self, TyCtxt, TypingMode};
10use rustc_session::config::EntryFnType;
11use rustc_span::Span;
12use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
13use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
14use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
15
16use super::check_function_signature;
17use crate::errors;
18
19pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
20 match tcx.entry_fn(()) {
21 Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
22 _ => {}
23 }
24}
25
26fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
27 let main_fnsig = tcx.fn_sig(main_def_id).instantiate_identity();
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();
33 if !matches!(hir_type.kind(), ty::FnDef(..)) {
34 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 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 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 span_bug!(tcx.def_span(def_id), "main has a non-function type");
87 }
88 }
89 }
90
91 let mut error = false;
92 let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span);
93
94 let main_asyncness = tcx.asyncness(main_def_id);
95 if main_asyncness.is_async() {
96 let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
97 tcx.dcx()
98 .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
99 error = true;
100 }
101
102 if let Some(attr_span) =
103 find_attr!(tcx.get_all_attrs(main_def_id), AttributeKind::TrackCaller(span) => *span)
104 {
105 tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span });
106 error = true;
107 }
108
109 if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
110 && !tcx.sess.target.is_like_wasm
112 && !tcx.sess.opts.actually_rustdoc
113 {
114 tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span });
115 error = true;
116 }
117
118 if error {
119 return;
120 }
121
122 let param_env = ty::ParamEnv::empty();
124 let expected_return_type;
125 if let Some(term_did) = tcx.lang_items().termination() {
126 let return_ty = main_fnsig.output();
127 let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
128 let Some(return_ty) = return_ty.no_bound_vars() else {
129 tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
130 return;
131 };
132 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
133 let cause = traits::ObligationCause::new(
134 return_ty_span,
135 main_diagnostics_def_id,
136 ObligationCauseCode::MainFunctionType,
137 );
138 let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
139 let norm_return_ty = ocx.normalize(&cause, param_env, return_ty);
140 ocx.register_bound(cause, param_env, norm_return_ty, term_did);
141 let errors = ocx.select_all_or_error();
142 if !errors.is_empty() {
143 infcx.err_ctxt().report_fulfillment_errors(errors);
144 error = true;
145 }
146 expected_return_type = norm_return_ty;
148 } else {
149 expected_return_type = tcx.types.unit;
151 }
152
153 if error {
154 return;
155 }
156
157 let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
158 [],
159 expected_return_type,
160 false,
161 hir::Safety::Safe,
162 ExternAbi::Rust,
163 ));
164
165 if check_function_signature(
166 tcx,
167 ObligationCause::new(
168 main_span,
169 main_diagnostics_def_id,
170 ObligationCauseCode::MainFunctionType,
171 ),
172 main_def_id,
173 expected_sig,
174 )
175 .is_err()
176 {
177 return;
178 }
179
180 let main_fn_generics = tcx.generics_of(main_def_id);
181 let main_fn_predicates = tcx.predicates_of(main_def_id);
182 if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
183 let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
184 tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
185 span: generics_param_span.unwrap_or(main_span),
186 label_span: generics_param_span,
187 });
188 } else if !main_fn_predicates.predicates.is_empty() {
189 let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
191 tcx.dcx().emit_err(errors::WhereClauseOnMain {
192 span: generics_where_clauses_span.unwrap_or(main_span),
193 generics_span: generics_where_clauses_span,
194 });
195 }
196}