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
8 changes: 8 additions & 0 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
} }

with_fn! { with_replace_span,
/// Replace all occurrences of the first span with the second one
#[rustc_lint_diagnostics]
pub fn replace_span(&mut self, before: Span, after: Span) -> &mut Self {
self.span.replace(before, after);
self
} }

#[rustc_lint_diagnostics]
pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
self.is_lint = Some(IsLint { name, has_future_breakage });
Expand Down
46 changes: 34 additions & 12 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 @@ -782,9 +784,12 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
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 +849,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 +876,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 +936,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 +1000,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 +1077,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
64 changes: 19 additions & 45 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ use rustc_middle::query::Providers;
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 @@ -289,12 +288,8 @@ pub(super) fn check_item<'tcx>(
}
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 @@ -344,7 +339,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 @@ -990,15 +985,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 Down Expand Up @@ -1056,35 +1051,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.def_span(field.did);
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(),
field: field.did,
last,
},
),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::Sized, hir_ty.span),
tcx.require_lang_item(LangItem::Sized, span),
);
}

Expand All @@ -1100,16 +1081,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 @@ -1135,10 +1113,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
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 @@ -605,13 +605,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 @@ -646,7 +646,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
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3910,7 +3910,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr.span,
ObligationCauseCode::FieldSized {
adt_kind: AdtKind::Enum,
span: self.tcx.def_span(field.did),
field: field.did,
last: false,
},
);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ pub enum ObligationCauseCode<'tcx> {
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
FieldSized {
adt_kind: AdtKind,
span: Span,
field: DefId,
last: bool,
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3121,7 +3121,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
ObligationCauseCode::StructInitializerSized => {
err.note("structs must have a statically known size to be initialized");
}
ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => {
ObligationCauseCode::FieldSized { adt_kind: ref item, last, field } => {
let def_span = tcx.def_span(field);
let span = field
.as_local()
.map(|field| tcx.hir_node_by_def_id(field).expect_field().ty.span)
.unwrap_or(def_span);
err.replace_span(def_span, span);
match *item {
AdtKind::Struct => {
if last {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,6 @@ help: consider adding an explicit lifetime bound
LL | struct Far<T: 'static
| +++++++++

error[E0392]: lifetime parameter `'a` is never used
--> $DIR/static-lifetime-tip-with-default-type.rs:22:10
|
LL | struct S<'a, K: 'a = i32>(&'static K);
| ^^ unused lifetime parameter
|
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`

error[E0310]: the parameter type `K` may not live long enough
--> $DIR/static-lifetime-tip-with-default-type.rs:22:27
|
Expand All @@ -104,6 +96,14 @@ help: consider adding an explicit lifetime bound
LL | struct S<'a, K: 'a + 'static = i32>(&'static K);
| +++++++++

error[E0392]: lifetime parameter `'a` is never used
--> $DIR/static-lifetime-tip-with-default-type.rs:22:10
|
LL | struct S<'a, K: 'a = i32>(&'static K);
| ^^ unused lifetime parameter
|
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`

error: aborting due to 8 previous errors

Some errors have detailed explanations: E0310, E0392.
Expand Down
12 changes: 6 additions & 6 deletions tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ LL | beta: [(); foo::<&'a ()>()],
= note: lifetime parameters may not be used in const expressions
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions

error: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/issue-64173-unused-lifetimes.rs:4:28
|
LL | array: [(); size_of::<&Self>()],
| ^^^^

error[E0392]: lifetime parameter `'s` is never used
--> $DIR/issue-64173-unused-lifetimes.rs:3:12
|
Expand All @@ -15,12 +21,6 @@ LL | struct Foo<'s> {
|
= help: consider removing `'s`, referring to it in a field, or using a marker such as `PhantomData`

error: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/issue-64173-unused-lifetimes.rs:4:28
|
LL | array: [(); size_of::<&Self>()],
| ^^^^

error[E0392]: lifetime parameter `'a` is never used
--> $DIR/issue-64173-unused-lifetimes.rs:15:12
|
Expand Down
Loading
Loading