Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c4083fa

Browse files
committedJul 16, 2023
Auto merge of #113545 - cjgillot:query-entry, r=compiler-errors
Check entry type as part of item type checking. This code is currently executed inside the root `analysis` query. Instead, check it during `check_for_entry_fn(CRATE_DEF_ID)` to hopefully avoid some re-executions. `CRATE_DEF_ID` is chosen by considering that entry fn are typically at crate root, so the corresponding HIR should already be in the dependencies.
2 parents cc7d9d5 + 87233da commit c4083fa

File tree

8 files changed

+310
-295
lines changed

8 files changed

+310
-295
lines changed
 

‎compiler/rustc_hir_analysis/src/check/check.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_attr as attr;
88
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
99
use rustc_hir as hir;
1010
use rustc_hir::def::{CtorKind, DefKind, Res};
11-
use rustc_hir::def_id::{DefId, LocalDefId};
11+
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
1212
use rustc_hir::intravisit::Visitor;
1313
use rustc_hir::{ItemKind, Node, PathSegment};
1414
use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
@@ -1378,6 +1378,9 @@ pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
13781378
for id in module.items() {
13791379
check_item_type(tcx, id);
13801380
}
1381+
if module_def_id == CRATE_DEF_ID {
1382+
super::entry::check_for_entry_fn(tcx);
1383+
}
13811384
}
13821385

13831386
fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
use rustc_hir as hir;
2+
use rustc_hir::Node;
3+
use rustc_infer::infer::TyCtxtInferExt;
4+
use rustc_middle::ty::{self, Ty, TyCtxt};
5+
use rustc_session::config::EntryFnType;
6+
use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
7+
use rustc_span::{symbol::sym, Span};
8+
use rustc_target::spec::abi::Abi;
9+
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
10+
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
11+
12+
use std::ops::Not;
13+
14+
use crate::errors;
15+
use crate::require_same_types;
16+
17+
pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
18+
match tcx.entry_fn(()) {
19+
Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
20+
Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
21+
_ => {}
22+
}
23+
}
24+
25+
fn 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+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
46+
match tcx.hir().find(hir_id) {
47+
Some(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+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
61+
match tcx.hir().find(hir_id) {
62+
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
63+
Some(generics.where_clause_span)
64+
}
65+
_ => {
66+
span_bug!(tcx.def_span(def_id), "main has a non-function type");
67+
}
68+
}
69+
}
70+
71+
fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
72+
if !def_id.is_local() {
73+
return None;
74+
}
75+
Some(tcx.def_span(def_id))
76+
}
77+
78+
fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
79+
if !def_id.is_local() {
80+
return None;
81+
}
82+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
83+
match tcx.hir().find(hir_id) {
84+
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => {
85+
Some(fn_sig.decl.output.span())
86+
}
87+
_ => {
88+
span_bug!(tcx.def_span(def_id), "main has a non-function type");
89+
}
90+
}
91+
}
92+
93+
let mut error = false;
94+
let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span);
95+
let main_fn_generics = tcx.generics_of(main_def_id);
96+
let main_fn_predicates = tcx.predicates_of(main_def_id);
97+
if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
98+
let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
99+
tcx.sess.emit_err(errors::MainFunctionGenericParameters {
100+
span: generics_param_span.unwrap_or(main_span),
101+
label_span: generics_param_span,
102+
});
103+
error = true;
104+
} else if !main_fn_predicates.predicates.is_empty() {
105+
// generics may bring in implicit predicates, so we skip this check if generics is present.
106+
let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
107+
tcx.sess.emit_err(errors::WhereClauseOnMain {
108+
span: generics_where_clauses_span.unwrap_or(main_span),
109+
generics_span: generics_where_clauses_span,
110+
});
111+
error = true;
112+
}
113+
114+
let main_asyncness = tcx.asyncness(main_def_id);
115+
if let hir::IsAsync::Async = main_asyncness {
116+
let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
117+
tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
118+
error = true;
119+
}
120+
121+
for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
122+
tcx.sess.emit_err(errors::TrackCallerOnMain { span: attr.span, annotated: main_span });
123+
error = true;
124+
}
125+
126+
if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
127+
// Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
128+
&& !tcx.sess.target.is_like_wasm
129+
&& !tcx.sess.opts.actually_rustdoc
130+
{
131+
tcx.sess.emit_err(errors::TargetFeatureOnMain { main: main_span });
132+
error = true;
133+
}
134+
135+
if error {
136+
return;
137+
}
138+
139+
// Main should have no WC, so empty param env is OK here.
140+
let param_env = ty::ParamEnv::empty();
141+
let expected_return_type;
142+
if let Some(term_did) = tcx.lang_items().termination() {
143+
let return_ty = main_fnsig.output();
144+
let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
145+
if !return_ty.bound_vars().is_empty() {
146+
tcx.sess.emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
147+
error = true;
148+
}
149+
let return_ty = return_ty.skip_binder();
150+
let infcx = tcx.infer_ctxt().build();
151+
let cause = traits::ObligationCause::new(
152+
return_ty_span,
153+
main_diagnostics_def_id,
154+
ObligationCauseCode::MainFunctionType,
155+
);
156+
let ocx = traits::ObligationCtxt::new(&infcx);
157+
let norm_return_ty = ocx.normalize(&cause, param_env, return_ty);
158+
ocx.register_bound(cause, param_env, norm_return_ty, term_did);
159+
let errors = ocx.select_all_or_error();
160+
if !errors.is_empty() {
161+
infcx.err_ctxt().report_fulfillment_errors(&errors);
162+
error = true;
163+
}
164+
// now we can take the return type of the given main function
165+
expected_return_type = main_fnsig.output();
166+
} else {
167+
// standard () main return type
168+
expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx));
169+
}
170+
171+
if error {
172+
return;
173+
}
174+
175+
let se_ty = Ty::new_fn_ptr(
176+
tcx,
177+
expected_return_type.map_bound(|expected_return_type| {
178+
tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
179+
}),
180+
);
181+
182+
require_same_types(
183+
tcx,
184+
&ObligationCause::new(
185+
main_span,
186+
main_diagnostics_def_id,
187+
ObligationCauseCode::MainFunctionType,
188+
),
189+
param_env,
190+
se_ty,
191+
Ty::new_fn_ptr(tcx, main_fnsig),
192+
);
193+
}
194+
195+
fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
196+
let start_def_id = start_def_id.expect_local();
197+
let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id);
198+
let start_span = tcx.def_span(start_def_id);
199+
let start_t = tcx.type_of(start_def_id).instantiate_identity();
200+
match start_t.kind() {
201+
ty::FnDef(..) => {
202+
if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
203+
if let hir::ItemKind::Fn(sig, generics, _) = &it.kind {
204+
let mut error = false;
205+
if !generics.params.is_empty() {
206+
tcx.sess.emit_err(errors::StartFunctionParameters { span: generics.span });
207+
error = true;
208+
}
209+
if generics.has_where_clause_predicates {
210+
tcx.sess.emit_err(errors::StartFunctionWhere {
211+
span: generics.where_clause_span,
212+
});
213+
error = true;
214+
}
215+
if let hir::IsAsync::Async = sig.header.asyncness {
216+
let span = tcx.def_span(it.owner_id);
217+
tcx.sess.emit_err(errors::StartAsync { span: span });
218+
error = true;
219+
}
220+
221+
let attrs = tcx.hir().attrs(start_id);
222+
for attr in attrs {
223+
if attr.has_name(sym::track_caller) {
224+
tcx.sess.emit_err(errors::StartTrackCaller {
225+
span: attr.span,
226+
start: start_span,
227+
});
228+
error = true;
229+
}
230+
if attr.has_name(sym::target_feature)
231+
// Calling functions with `#[target_feature]` is
232+
// not unsafe on WASM, see #84988
233+
&& !tcx.sess.target.is_like_wasm
234+
&& !tcx.sess.opts.actually_rustdoc
235+
{
236+
tcx.sess.emit_err(errors::StartTargetFeature {
237+
span: attr.span,
238+
start: start_span,
239+
});
240+
error = true;
241+
}
242+
}
243+
244+
if error {
245+
return;
246+
}
247+
}
248+
}
249+
250+
let se_ty = Ty::new_fn_ptr(
251+
tcx,
252+
ty::Binder::dummy(tcx.mk_fn_sig(
253+
[tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
254+
tcx.types.isize,
255+
false,
256+
hir::Unsafety::Normal,
257+
Abi::Rust,
258+
)),
259+
);
260+
261+
require_same_types(
262+
tcx,
263+
&ObligationCause::new(
264+
start_span,
265+
start_def_id,
266+
ObligationCauseCode::StartFunctionType,
267+
),
268+
ty::ParamEnv::empty(), // start should not have any where bounds.
269+
se_ty,
270+
Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).instantiate_identity()),
271+
);
272+
}
273+
_ => {
274+
span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
275+
}
276+
}
277+
}

‎compiler/rustc_hir_analysis/src/check/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ a type parameter).
6565
mod check;
6666
mod compare_impl_item;
6767
pub mod dropck;
68+
mod entry;
6869
pub mod intrinsic;
6970
pub mod intrinsicck;
7071
mod region;
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.