summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/lib.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs285
1 files changed, 16 insertions, 269 deletions
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index a68832d96..4f95174f8 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -99,23 +99,20 @@ use rustc_errors::ErrorGuaranteed;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
-use rustc_hir::Node;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::middle;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::util;
-use rustc_session::{config::EntryFnType, parse::feature_err};
-use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_session::parse::feature_err;
use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt};
-
-use std::ops::Not;
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
use astconv::{AstConv, OnlySelfBounds};
use bounds::Bounds;
+use rustc_hir::def::DefKind;
fluent_messages! { "../messages.ftl" }
@@ -176,271 +173,11 @@ fn require_same_types<'tcx>(
}
}
-fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
- let main_fnsig = tcx.fn_sig(main_def_id).subst_identity();
- let main_span = tcx.def_span(main_def_id);
-
- fn main_fn_diagnostics_def_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> LocalDefId {
- if let Some(local_def_id) = def_id.as_local() {
- let hir_type = tcx.type_of(local_def_id).subst_identity();
- if !matches!(hir_type.kind(), ty::FnDef(..)) {
- span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
- }
- local_def_id
- } else {
- CRATE_DEF_ID
- }
- }
-
- fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
- if !def_id.is_local() {
- return None;
- }
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
- generics.params.is_empty().not().then_some(generics.span)
- }
- _ => {
- span_bug!(tcx.def_span(def_id), "main has a non-function type");
- }
- }
- }
-
- fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
- if !def_id.is_local() {
- return None;
- }
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
- Some(generics.where_clause_span)
- }
- _ => {
- span_bug!(tcx.def_span(def_id), "main has a non-function type");
- }
- }
- }
-
- fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
- if !def_id.is_local() {
- return None;
- }
- Some(tcx.def_span(def_id))
- }
-
- fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
- if !def_id.is_local() {
- return None;
- }
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => {
- Some(fn_sig.decl.output.span())
- }
- _ => {
- span_bug!(tcx.def_span(def_id), "main has a non-function type");
- }
- }
- }
-
- let mut error = false;
- let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span);
- let main_fn_generics = tcx.generics_of(main_def_id);
- let main_fn_predicates = tcx.predicates_of(main_def_id);
- if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
- let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
- tcx.sess.emit_err(errors::MainFunctionGenericParameters {
- span: generics_param_span.unwrap_or(main_span),
- label_span: generics_param_span,
- });
- error = true;
- } else if !main_fn_predicates.predicates.is_empty() {
- // generics may bring in implicit predicates, so we skip this check if generics is present.
- let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
- tcx.sess.emit_err(errors::WhereClauseOnMain {
- span: generics_where_clauses_span.unwrap_or(main_span),
- generics_span: generics_where_clauses_span,
- });
- error = true;
- }
-
- let main_asyncness = tcx.asyncness(main_def_id);
- if let hir::IsAsync::Async = main_asyncness {
- let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
- tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
- error = true;
- }
-
- for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
- tcx.sess.emit_err(errors::TrackCallerOnMain { span: attr.span, annotated: main_span });
- error = true;
- }
-
- if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
- // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
- && !tcx.sess.target.is_like_wasm
- && !tcx.sess.opts.actually_rustdoc
- {
- tcx.sess.emit_err(errors::TargetFeatureOnMain { main: main_span });
- error = true;
- }
-
- if error {
- return;
- }
-
- // Main should have no WC, so empty param env is OK here.
- let param_env = ty::ParamEnv::empty();
- let expected_return_type;
- if let Some(term_did) = tcx.lang_items().termination() {
- let return_ty = main_fnsig.output();
- let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
- if !return_ty.bound_vars().is_empty() {
- tcx.sess.emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
- error = true;
- }
- let return_ty = return_ty.skip_binder();
- let infcx = tcx.infer_ctxt().build();
- let cause = traits::ObligationCause::new(
- return_ty_span,
- main_diagnostics_def_id,
- ObligationCauseCode::MainFunctionType,
- );
- let ocx = traits::ObligationCtxt::new(&infcx);
- let norm_return_ty = ocx.normalize(&cause, param_env, return_ty);
- ocx.register_bound(cause, param_env, norm_return_ty, term_did);
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
- error = true;
- }
- // now we can take the return type of the given main function
- expected_return_type = main_fnsig.output();
- } else {
- // standard () main return type
- expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx));
- }
-
- if error {
- return;
- }
-
- let se_ty = Ty::new_fn_ptr(
- tcx,
- expected_return_type.map_bound(|expected_return_type| {
- tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
- }),
- );
-
- require_same_types(
- tcx,
- &ObligationCause::new(
- main_span,
- main_diagnostics_def_id,
- ObligationCauseCode::MainFunctionType,
- ),
- param_env,
- se_ty,
- Ty::new_fn_ptr(tcx, main_fnsig),
- );
-}
-fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
- let start_def_id = start_def_id.expect_local();
- let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id);
- let start_span = tcx.def_span(start_def_id);
- let start_t = tcx.type_of(start_def_id).subst_identity();
- match start_t.kind() {
- ty::FnDef(..) => {
- if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
- if let hir::ItemKind::Fn(sig, generics, _) = &it.kind {
- let mut error = false;
- if !generics.params.is_empty() {
- tcx.sess.emit_err(errors::StartFunctionParameters { span: generics.span });
- error = true;
- }
- if generics.has_where_clause_predicates {
- tcx.sess.emit_err(errors::StartFunctionWhere {
- span: generics.where_clause_span,
- });
- error = true;
- }
- if let hir::IsAsync::Async = sig.header.asyncness {
- let span = tcx.def_span(it.owner_id);
- tcx.sess.emit_err(errors::StartAsync { span: span });
- error = true;
- }
-
- let attrs = tcx.hir().attrs(start_id);
- for attr in attrs {
- if attr.has_name(sym::track_caller) {
- tcx.sess.emit_err(errors::StartTrackCaller {
- span: attr.span,
- start: start_span,
- });
- error = true;
- }
- if attr.has_name(sym::target_feature)
- // Calling functions with `#[target_feature]` is
- // not unsafe on WASM, see #84988
- && !tcx.sess.target.is_like_wasm
- && !tcx.sess.opts.actually_rustdoc
- {
- tcx.sess.emit_err(errors::StartTargetFeature {
- span: attr.span,
- start: start_span,
- });
- error = true;
- }
- }
-
- if error {
- return;
- }
- }
- }
-
- let se_ty = Ty::new_fn_ptr(
- tcx,
- ty::Binder::dummy(tcx.mk_fn_sig(
- [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
- tcx.types.isize,
- false,
- hir::Unsafety::Normal,
- Abi::Rust,
- )),
- );
-
- require_same_types(
- tcx,
- &ObligationCause::new(
- start_span,
- start_def_id,
- ObligationCauseCode::StartFunctionType,
- ),
- ty::ParamEnv::empty(), // start should not have any where bounds.
- se_ty,
- Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).subst_identity()),
- );
- }
- _ => {
- span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
- }
- }
-}
-
-fn check_for_entry_fn(tcx: TyCtxt<'_>) {
- match tcx.entry_fn(()) {
- Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
- Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
- _ => {}
- }
-}
-
pub fn provide(providers: &mut Providers) {
collect::provide(providers);
coherence::provide(providers);
check::provide(providers);
+ check_unused::provide(providers);
variance::provide(providers);
outlives::provide(providers);
impl_wf_check::provide(providers);
@@ -500,8 +237,18 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
});
- check_unused::check_crate(tcx);
- check_for_entry_fn(tcx);
+ // FIXME: Remove this when we implement creating `DefId`s
+ // for anon constants during their parents' typeck.
+ // Typeck all body owners in parallel will produce queries
+ // cycle errors because it may typeck on anon constants directly.
+ tcx.hir().par_body_owners(|item_def_id| {
+ let def_kind = tcx.def_kind(item_def_id);
+ if !matches!(def_kind, DefKind::AnonConst) {
+ tcx.ensure().typeck(item_def_id);
+ }
+ });
+
+ tcx.ensure().check_unused_traits(());
if let Some(reported) = tcx.sess.has_errors() { Err(reported) } else { Ok(()) }
}