Skip to content

Avoid loading HIR for check_well_formed on type declarations #143328

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4818,6 +4818,7 @@ impl<'hir> Node<'hir> {
ForeignItemKind::Static(ty, ..) => Some(ty),
_ => None,
},
Node::Field(f) => Some(f.ty),
_ => None,
}
}
Expand Down
57 changes: 39 additions & 18 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ use {rustc_attr_data_structures as attrs, rustc_hir as hir};
use super::compare_impl_item::check_type_bounds;
use super::*;
use crate::check::wfcheck::{
check_associated_item, check_trait_item, check_variances_for_type_defn, check_where_clauses,
enter_wf_checking_ctxt,
check_associated_item, check_trait_item, check_type_defn, check_variances_for_type_defn,
check_where_clauses, enter_wf_checking_ctxt,
};

fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) {
Expand Down Expand Up @@ -89,7 +89,7 @@ pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>,
}
}

fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
Expand All @@ -100,15 +100,17 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {

check_transparent(tcx, def);
check_packed(tcx, span, def);
check_type_defn(tcx, def_id, false)
}

fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
check_transparent(tcx, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
check_type_defn(tcx, def_id, true)
}

fn allowed_union_or_unsafe_field<'tcx>(
Expand Down Expand Up @@ -768,23 +770,25 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
check_static_inhabited(tcx, def_id);
check_static_linkage(tcx, def_id);
res = res.and(wfcheck::check_static_item(tcx, def_id));

// Only `Node::Item` and `Node::ForeignItem` still have HIR based
// checks. Returning early here does not miss any checks and
// avoids this query from having a direct dependency edge on the HIR
return res;
}
DefKind::Const => {}
DefKind::Const => res = res.and(wfcheck::check_const_item(tcx, def_id)),
_ => unreachable!(),
}
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
// checks. Returning early here does not miss any checks and
// avoids this query from having a direct dependency edge on the HIR
return res;
}
DefKind::Enum => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
crate::collect::lower_enum_variant_types(tcx, def_id.to_def_id());
crate::collect::check_enum_variant_types(tcx, def_id.to_def_id());
check_enum(tcx, def_id);
check_variances_for_type_defn(tcx, def_id);
res = res.and(check_type_defn(tcx, def_id, true));
// enums are fully handled by the type based check and have no hir wfcheck logic
return res;
}
DefKind::Fn => {
tcx.ensure_ok().generics_of(def_id);
Expand Down Expand Up @@ -844,12 +848,19 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
_ => {}
}
}
res = res.and(wfcheck::check_trait(tcx, def_id));
wfcheck::check_gat_where_clauses(tcx, def_id);
// Trait aliases do not have hir checks anymore
return res;
}
DefKind::TraitAlias => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().explicit_implied_predicates_of(def_id);
tcx.ensure_ok().explicit_super_predicates_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
res = res.and(wfcheck::check_trait(tcx, def_id));
// Trait aliases do not have hir checks anymore
return res;
}
def_kind @ (DefKind::Struct | DefKind::Union) => {
tcx.ensure_ok().generics_of(def_id);
Expand All @@ -864,14 +875,16 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
}

if let Some((_, ctor_def_id)) = adt.ctor {
crate::collect::lower_variant_ctor(tcx, ctor_def_id.expect_local());
crate::collect::check_ctor(tcx, ctor_def_id.expect_local());
}
match def_kind {
res = res.and(match def_kind {
DefKind::Struct => check_struct(tcx, def_id),
DefKind::Union => check_union(tcx, def_id),
_ => unreachable!(),
}
});
check_variances_for_type_defn(tcx, def_id);
// structs and enums are fully handled by the type based check and have no hir wfcheck logic
return res;
}
DefKind::OpaqueTy => {
check_opaque_precise_captures(tcx, def_id);
Expand Down Expand Up @@ -922,6 +935,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
}));
check_variances_for_type_defn(tcx, def_id);
}
// Doesn't have any hir based checks
return res;
}
DefKind::ForeignMod => {
let it = tcx.hir_expect_item(def_id);
Expand Down Expand Up @@ -984,6 +999,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
_ => (),
}
}
// Doesn't have any hir based checks
return res;
}
DefKind::Closure => {
// This is guaranteed to be called by metadata encoding,
Expand Down Expand Up @@ -1059,10 +1076,14 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
return res;
}

// Only `Node::Item` and `Node::ForeignItem` still have HIR based
// checks. Returning early here does not miss any checks and
// avoids this query from having a direct dependency edge on the HIR
DefKind::AnonConst | DefKind::InlineConst => return res,
// These have no wf checks
DefKind::AnonConst
| DefKind::InlineConst
| DefKind::ExternCrate
| DefKind::Macro(..)
| DefKind::Use
| DefKind::GlobalAsm
| DefKind::Mod => return res,
_ => {}
}
let node = tcx.hir_node_by_def_id(def_id);
Expand Down
91 changes: 28 additions & 63 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::traits::solve::NoSolution;
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFlags,
TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
Upcast,
self, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFlags, TypeFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
};
use rustc_middle::{bug, span_bug};
use rustc_session::parse::feature_err;
Expand Down Expand Up @@ -290,13 +289,8 @@ pub(super) fn check_item<'tcx>(
res
}
hir::ItemKind::Fn { sig, .. } => check_item_fn(tcx, def_id, sig.decl),
hir::ItemKind::Const(_, _, ty, _) => check_const_item(tcx, def_id, ty.span),
hir::ItemKind::Struct(..) => check_type_defn(tcx, item, false),
hir::ItemKind::Union(..) => check_type_defn(tcx, item, true),
hir::ItemKind::Enum(..) => check_type_defn(tcx, item, true),
hir::ItemKind::Trait(..) => check_trait(tcx, item),
hir::ItemKind::TraitAlias(..) => check_trait(tcx, item),
_ => Ok(()),
// Note: do not add new entries to this match. Instead add all new logic in `check_item_type`
_ => span_bug!(item.span, "should have been handled by the type based wf check: {item:?}"),
}
}

Expand Down Expand Up @@ -346,7 +340,7 @@ pub(crate) fn check_trait_item<'tcx>(
/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
/// }
/// ```
fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
pub(crate) fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
// Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
let mut required_bounds_by_item = FxIndexMap::default();
let associated_items = tcx.associated_items(trait_def_id);
Expand Down Expand Up @@ -992,15 +986,15 @@ pub(crate) fn check_associated_item(
}

/// In a type definition, we check that to ensure that the types of the fields are well-formed.
fn check_type_defn<'tcx>(
pub(crate) fn check_type_defn<'tcx>(
tcx: TyCtxt<'tcx>,
item: &hir::Item<'tcx>,
item: LocalDefId,
all_sized: bool,
) -> Result<(), ErrorGuaranteed> {
let _ = tcx.representability(item.owner_id.def_id);
let adt_def = tcx.adt_def(item.owner_id);
let _ = tcx.representability(item);
let adt_def = tcx.adt_def(item);

enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| {
enter_wf_checking_ctxt(tcx, item, |wfcx| {
let variants = adt_def.variants();
let packed = adt_def.repr().packed();

Expand All @@ -1027,18 +1021,13 @@ fn check_type_defn<'tcx>(
}
}
let field_id = field.did.expect_local();
let hir::FieldDef { ty: hir_ty, .. } =
tcx.hir_node_by_def_id(field_id).expect_field();
let span = tcx.ty_span(field_id);
let ty = wfcx.deeply_normalize(
hir_ty.span,
span,
None,
tcx.type_of(field.did).instantiate_identity(),
);
wfcx.register_wf_obligation(
hir_ty.span,
Some(WellFormedLoc::Ty(field_id)),
ty.into(),
)
wfcx.register_wf_obligation(span, Some(WellFormedLoc::Ty(field_id)), ty.into())
}

// For DST, or when drop needs to copy things around, all
Expand All @@ -1058,35 +1047,21 @@ fn check_type_defn<'tcx>(
variant.fields.raw[..variant.fields.len() - unsized_len].iter().enumerate()
{
let last = idx == variant.fields.len() - 1;
let field_id = field.did.expect_local();
let hir::FieldDef { ty: hir_ty, .. } =
tcx.hir_node_by_def_id(field_id).expect_field();
let ty = wfcx.normalize(
hir_ty.span,
None,
tcx.type_of(field.did).instantiate_identity(),
);
let span = tcx.ty_span(field.did.expect_local());
let ty = wfcx.normalize(span, None, tcx.type_of(field.did).instantiate_identity());
wfcx.register_bound(
traits::ObligationCause::new(
hir_ty.span,
span,
wfcx.body_def_id,
ObligationCauseCode::FieldSized {
adt_kind: match &item.kind {
ItemKind::Struct(..) => AdtKind::Struct,
ItemKind::Union(..) => AdtKind::Union,
ItemKind::Enum(..) => AdtKind::Enum,
kind => span_bug!(
item.span,
"should be wfchecking an ADT, got {kind:?}"
),
},
span: hir_ty.span,
adt_kind: adt_def.adt_kind(),
span,
last,
},
),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::Sized, hir_ty.span),
tcx.require_lang_item(LangItem::Sized, span),
);
}

Expand All @@ -1102,16 +1077,13 @@ fn check_type_defn<'tcx>(
}
}

check_where_clauses(wfcx, item.owner_id.def_id);
check_where_clauses(wfcx, item);
Ok(())
})
}

#[instrument(skip(tcx, item))]
fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuaranteed> {
debug!(?item.owner_id);

let def_id = item.owner_id.def_id;
#[instrument(skip(tcx))]
pub(crate) fn check_trait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
if tcx.is_lang_item(def_id.into(), LangItem::PointeeSized) {
// `PointeeSized` is removed during lowering.
return Ok(());
Expand All @@ -1137,10 +1109,6 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant
Ok(())
});

// Only check traits, don't check trait aliases
if let hir::ItemKind::Trait(..) = item.kind {
check_gat_where_clauses(tcx, item.owner_id.def_id);
}
res
}

Expand Down Expand Up @@ -1185,7 +1153,8 @@ pub(super) fn check_static_item(
) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, item_id, |wfcx| {
let ty = tcx.type_of(item_id).instantiate_identity();
let item_ty = wfcx.deeply_normalize(DUMMY_SP, Some(WellFormedLoc::Ty(item_id)), ty);
let span = tcx.ty_span(item_id);
let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);

let is_foreign_item = tcx.is_foreign_item(item_id);

Expand All @@ -1194,7 +1163,7 @@ pub(super) fn check_static_item(
!matches!(tail.kind(), ty::Foreign(_))
};

wfcx.register_wf_obligation(DUMMY_SP, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
wfcx.register_wf_obligation(span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
if forbid_unsized {
let span = tcx.def_span(item_id);
wfcx.register_bound(
Expand All @@ -1216,7 +1185,6 @@ pub(super) fn check_static_item(
&& !tcx.is_thread_local_static(item_id.to_def_id());

if should_check_for_sync {
let span = tcx.def_span(item_id);
wfcx.register_bound(
traits::ObligationCause::new(
span,
Expand All @@ -1232,13 +1200,10 @@ pub(super) fn check_static_item(
})
}

fn check_const_item(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
ty_span: Span,
) -> Result<(), ErrorGuaranteed> {
pub(crate) fn check_const_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let ty_span = tcx.ty_span(def_id);
let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty);

wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(def_id)), ty.into());
Expand Down Expand Up @@ -1505,7 +1470,7 @@ pub(super) fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, def_id:
let cause = traits::ObligationCause::new(
sp,
wfcx.body_def_id,
ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP),
ObligationCauseCode::WhereClause(def_id.to_def_id(), sp),
);
Obligation::new(tcx, cause, wfcx.param_env, pred)
});
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,13 +600,13 @@ fn get_new_lifetime_name<'tcx>(
(1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap()
}

pub(super) fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
pub(super) fn check_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
}

pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
pub(super) fn check_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
let def = tcx.adt_def(def_id);
let repr_type = def.repr().discr_type();
let initial = repr_type.initial_discriminant(tcx);
Expand Down Expand Up @@ -641,7 +641,7 @@ pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {

// Lower the ctor, if any. This also registers the variant as an item.
if let Some(ctor_def_id) = variant.ctor_def_id() {
lower_variant_ctor(tcx, ctor_def_id.expect_local());
check_ctor(tcx, ctor_def_id.expect_local());
}
}
}
Expand Down
Loading
Loading