summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/check/check.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check/check.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs215
1 files changed, 140 insertions, 75 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 120545c8e..2c7788498 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -8,7 +8,7 @@ use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
@@ -19,11 +19,13 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::traits::DefiningAnchor;
+use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
-use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
+use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{
- self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+ self, AdtDef, ParamEnv, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+ TypeVisitableExt,
};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym;
@@ -34,6 +36,7 @@ use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplem
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
+use rustc_type_ir::fold::TypeFoldable;
use std::ops::ControlFlow;
@@ -96,8 +99,8 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
/// Check that the fields of the `union` do not need dropping.
fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
- let item_type = tcx.type_of(item_def_id).subst_identity();
- if let ty::Adt(def, substs) = item_type.kind() {
+ let item_type = tcx.type_of(item_def_id).instantiate_identity();
+ if let ty::Adt(def, args) = item_type.kind() {
assert!(def.is_union());
fn allowed_union_field<'tcx>(
@@ -128,7 +131,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
let param_env = tcx.param_env(item_def_id);
for field in &def.non_enum_variant().fields {
- let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, substs));
+ let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, args));
if !allowed_union_field(field_ty, tcx, param_env) {
let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
@@ -163,7 +166,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
// would be enough to check this for `extern` statics, as statics with an initializer will
// have UB during initialization if they are uninhabited, but there also seems to be no good
// reason to allow any statics to be uninhabited.
- let ty = tcx.type_of(def_id).subst_identity();
+ let ty = tcx.type_of(def_id).instantiate_identity();
let span = tcx.def_span(def_id);
let layout = match tcx.layout_of(ParamEnv::reveal_all().and(ty)) {
Ok(l) => l,
@@ -212,16 +215,16 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
return;
}
- let substs = InternalSubsts::identity_for_item(tcx, item.owner_id);
+ let args = GenericArgs::identity_for_item(tcx, item.owner_id);
let span = tcx.def_span(item.owner_id.def_id);
if !tcx.features().impl_trait_projections {
check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
}
- if tcx.type_of(item.owner_id.def_id).subst_identity().references_error() {
+ if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() {
return;
}
- if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
+ if check_opaque_for_cycles(tcx, item.owner_id.def_id, args, span, &origin).is_err() {
return;
}
@@ -302,16 +305,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
if let ItemKind::OpaqueTy(&hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
- in_trait,
..
}) = item.kind
{
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() {
- Ty::new_projection(tcx, def_id.to_def_id(), substs)
- } else {
- Ty::new_opaque(tcx, def_id.to_def_id(), substs)
- };
+ let args = GenericArgs::identity_for_item(tcx, def_id);
+ let opaque_identity_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
let mut visitor = ProhibitOpaqueVisitor {
opaque_identity_ty,
parent_count: tcx.generics_of(def_id).parent_count as u32,
@@ -321,7 +319,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
};
let prohibit_opaque = tcx
.explicit_item_bounds(def_id)
- .subst_identity_iter_copied()
+ .instantiate_identity_iter_copied()
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
if let Some(ty) = prohibit_opaque.break_value() {
@@ -347,7 +345,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
err.span_suggestion(
span,
"consider spelling out the type instead",
- name.unwrap_or_else(|| format!("{:?}", ty)),
+ name.unwrap_or_else(|| format!("{ty:?}")),
Applicability::MaybeIncorrect,
);
}
@@ -360,11 +358,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
pub(super) fn check_opaque_for_cycles<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
span: Span,
origin: &hir::OpaqueTyOrigin,
) -> Result<(), ErrorGuaranteed> {
- if tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs).is_err() {
+ if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {
let reported = match origin {
hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span),
_ => opaque_type_cycle_error(tcx, def_id, span),
@@ -409,16 +407,26 @@ fn check_opaque_meets_bounds<'tcx>(
.build();
let ocx = ObligationCtxt::new(&infcx);
- let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
- let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), substs);
+ let args = match *origin {
+ hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
+ GenericArgs::identity_for_item(tcx, parent).extend_to(
+ tcx,
+ def_id.to_def_id(),
+ |param, _| tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into(),
+ )
+ }
+ hir::OpaqueTyOrigin::TyAlias { .. } => GenericArgs::identity_for_item(tcx, def_id),
+ };
+
+ let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
- // `ReErased` regions appear in the "parent_substs" of closures/generators.
+ // `ReErased` regions appear in the "parent_args" of closures/generators.
// We're ignoring them here and replacing them with fresh region variables.
- // See tests in ui/type-alias-impl-trait/closure_{parent_substs,wf_outlives}.rs.
+ // See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs.
//
// FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
// here rather than using ReErased.
- let hidden_ty = tcx.type_of(def_id.to_def_id()).subst(tcx, substs);
+ let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args);
let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() {
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
_ => re,
@@ -442,7 +450,7 @@ fn check_opaque_meets_bounds<'tcx>(
// hidden type is well formed even without those bounds.
let predicate =
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into())));
- ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate));
+ ocx.register_obligation(Obligation::new(tcx, misc_cause.clone(), param_env, predicate));
// Check that all obligations are satisfied by the implementation's
// version.
@@ -453,7 +461,15 @@ fn check_opaque_meets_bounds<'tcx>(
}
match origin {
// Checked when type checking the function containing them.
- hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
+ // HACK: this should also fall through to the hidden type check below, but the original
+ // implementation had a bug where equivalent lifetimes are not identical. This caused us
+ // to reject existing stable code that is otherwise completely fine. The real fix is to
+ // compare the hidden types via our type equivalence/relation infra instead of doing an
+ // identity check.
+ let _ = infcx.take_opaque_types();
+ return Ok(());
+ }
// Nested opaque types occur only in associated types:
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
@@ -469,15 +485,63 @@ fn check_opaque_meets_bounds<'tcx>(
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
}
}
- // Clean up after ourselves
- let _ = infcx.take_opaque_types();
+ // Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
+ for (mut key, mut ty) in infcx.take_opaque_types() {
+ ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
+ key = infcx.resolve_vars_if_possible(key);
+ sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
+ }
Ok(())
}
+fn sanity_check_found_hidden_type<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: ty::OpaqueTypeKey<'tcx>,
+ mut ty: ty::OpaqueHiddenType<'tcx>,
+) -> Result<(), ErrorGuaranteed> {
+ if ty.ty.is_ty_var() {
+ // Nothing was actually constrained.
+ return Ok(());
+ }
+ if let ty::Alias(ty::Opaque, alias) = ty.ty.kind() {
+ if alias.def_id == key.def_id.to_def_id() && alias.args == key.args {
+ // Nothing was actually constrained, this is an opaque usage that was
+ // only discovered to be opaque after inference vars resolved.
+ return Ok(());
+ }
+ }
+ let strip_vars = |ty: Ty<'tcx>| {
+ ty.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |t| t,
+ ct_op: |c| c,
+ lt_op: |l| match l.kind() {
+ RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
+ _ => l,
+ },
+ })
+ };
+ // Closures frequently end up containing erased lifetimes in their final representation.
+ // These correspond to lifetime variables that never got resolved, so we patch this up here.
+ ty.ty = strip_vars(ty.ty);
+ // Get the hidden type.
+ let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
+ let hidden_ty = strip_vars(hidden_ty);
+
+ // If the hidden types differ, emit a type mismatch diagnostic.
+ if hidden_ty == ty.ty {
+ Ok(())
+ } else {
+ let span = tcx.def_span(key.def_id);
+ let other = ty::OpaqueHiddenType { ty: hidden_ty, span };
+ Err(ty.report_mismatch(&other, key.def_id, tcx).emit())
+ }
+}
+
fn is_enum_of_nonnullable_ptr<'tcx>(
tcx: TyCtxt<'tcx>,
adt_def: AdtDef<'tcx>,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
) -> bool {
if adt_def.repr().inhibit_enum_layout_opt() {
return false;
@@ -489,14 +553,14 @@ fn is_enum_of_nonnullable_ptr<'tcx>(
let (([], [field]) | ([field], [])) = (&var_one.fields.raw[..], &var_two.fields.raw[..]) else {
return false;
};
- matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..))
+ matches!(field.ty(tcx, args).kind(), ty::FnPtr(..) | ty::Ref(..))
}
fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
- if match tcx.type_of(def_id).subst_identity().kind() {
+ if match tcx.type_of(def_id).instantiate_identity().kind() {
ty::RawPtr(_) => false,
- ty::Adt(adt_def, substs) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *substs),
+ ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),
_ => true,
} {
tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });
@@ -530,7 +594,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
check_impl_items_against_trait(
tcx,
id.owner_id.def_id,
- impl_trait_ref.subst_identity(),
+ impl_trait_ref.instantiate_identity(),
);
check_on_unimplemented(tcx, id);
}
@@ -546,13 +610,13 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi);
}
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
- let trait_substs =
- InternalSubsts::identity_for_item(tcx, id.owner_id);
+ let trait_args =
+ GenericArgs::identity_for_item(tcx, id.owner_id);
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx,
assoc_item,
assoc_item,
- ty::TraitRef::new(tcx, id.owner_id.to_def_id(), trait_substs),
+ ty::TraitRef::new(tcx, id.owner_id.to_def_id(), trait_args),
);
}
_ => {}
@@ -576,19 +640,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
check_opaque(tcx, id);
}
}
- DefKind::ImplTraitPlaceholder => {
- let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id());
- // Only check the validity of this opaque type if the function has a default body
- if let hir::Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
- ..
- }) = tcx.hir().get_by_def_id(parent.expect_local())
- {
- check_opaque(tcx, id);
- }
- }
- DefKind::TyAlias => {
- let pty_ty = tcx.type_of(id.owner_id).subst_identity();
+ DefKind::TyAlias { .. } => {
+ let pty_ty = tcx.type_of(id.owner_id).instantiate_identity();
let generics = tcx.generics_of(id.owner_id);
check_type_params_are_used(tcx, &generics, pty_ty);
}
@@ -642,7 +695,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
"replace the {} parameters with concrete {}{}",
kinds,
kinds_pl,
- egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
+ egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(),
),
)
.emit();
@@ -727,7 +780,7 @@ pub(super) fn check_specialization_validity<'tcx>(
} else {
tcx.sess.delay_span_bug(
DUMMY_SP,
- format!("parent item: {:?} not marked as default", parent_impl),
+ format!("parent item: {parent_impl:?} not marked as default"),
);
}
}
@@ -902,8 +955,8 @@ fn check_impl_items_against_trait<'tcx>(
}
pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
- let t = tcx.type_of(def_id).subst_identity();
- if let ty::Adt(def, substs) = t.kind()
+ let t = tcx.type_of(def_id).instantiate_identity();
+ if let ty::Adt(def, args) = t.kind()
&& def.is_struct()
{
let fields = &def.non_enum_variant().fields;
@@ -911,8 +964,8 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
return;
}
- let e = fields[FieldIdx::from_u32(0)].ty(tcx, substs);
- if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
+ let e = fields[FieldIdx::from_u32(0)].ty(tcx, args);
+ if !fields.iter().all(|f| f.ty(tcx, args) == e) {
struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
.span_label(sp, "SIMD elements must have the same type")
.emit();
@@ -1019,7 +1072,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
if first {
format!(
"`{}` contains a field of type `{}`",
- tcx.type_of(def.did()).subst_identity(),
+ tcx.type_of(def.did()).instantiate_identity(),
ident
)
} else {
@@ -1041,7 +1094,7 @@ pub(super) fn check_packed_inner(
def_id: DefId,
stack: &mut Vec<DefId>,
) -> Option<Vec<(DefId, Span)>> {
- if let ty::Adt(def, substs) = tcx.type_of(def_id).subst_identity().kind() {
+ if let ty::Adt(def, args) = tcx.type_of(def_id).instantiate_identity().kind() {
if def.is_struct() || def.is_union() {
if def.repr().align.is_some() {
return Some(vec![(def.did(), DUMMY_SP)]);
@@ -1049,7 +1102,7 @@ pub(super) fn check_packed_inner(
stack.push(def_id);
for field in &def.non_enum_variant().fields {
- if let ty::Adt(def, _) = field.ty(tcx, substs).kind()
+ if let ty::Adt(def, _) = field.ty(tcx, args).kind()
&& !stack.contains(&def.did())
&& let Some(mut defs) = check_packed_inner(tcx, def.did(), stack)
{
@@ -1088,21 +1141,21 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
// For each field, figure out if it's known to be a ZST and align(1), with "known"
// respecting #[non_exhaustive] attributes.
let field_infos = adt.all_fields().map(|field| {
- let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
+ let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
let param_env = tcx.param_env(field.did);
let layout = tcx.layout_of(param_env.and(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir().span_if_local(field.did).unwrap();
let zst = layout.is_ok_and(|layout| layout.is_zst());
- let align1 = layout.is_ok_and(|layout| layout.align.abi.bytes() == 1);
+ let align = layout.ok().map(|layout| layout.align.abi.bytes());
if !zst {
- return (span, zst, align1, None);
+ return (span, zst, align, None);
}
fn check_non_exhaustive<'tcx>(
tcx: TyCtxt<'tcx>,
t: Ty<'tcx>,
- ) -> ControlFlow<(&'static str, DefId, SubstsRef<'tcx>, bool)> {
+ ) -> ControlFlow<(&'static str, DefId, GenericArgsRef<'tcx>, bool)> {
match t.kind() {
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
@@ -1131,12 +1184,12 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
}
}
- (span, zst, align1, check_non_exhaustive(tcx, ty).break_value())
+ (span, zst, align, check_non_exhaustive(tcx, ty).break_value())
});
let non_zst_fields = field_infos
.clone()
- .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
+ .filter_map(|(span, zst, _align, _non_exhaustive)| if !zst { Some(span) } else { None });
let non_zst_count = non_zst_fields.clone().count();
if non_zst_count >= 2 {
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
@@ -1144,19 +1197,28 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
let incompatible_zst_fields =
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
- for (span, zst, align1, non_exhaustive) in field_infos {
- if zst && !align1 {
- struct_span_err!(
+ for (span, zst, align, non_exhaustive) in field_infos {
+ if zst && align != Some(1) {
+ let mut err = struct_span_err!(
tcx.sess,
span,
E0691,
"zero-sized field in transparent {} has alignment larger than 1",
adt.descr(),
- )
- .span_label(span, "has alignment larger than 1")
- .emit();
+ );
+
+ if let Some(align_bytes) = align {
+ err.span_label(
+ span,
+ format!("has alignment of {align_bytes}, which is larger than 1"),
+ );
+ } else {
+ err.span_label(span, "may have alignment larger than 1");
+ }
+
+ err.emit();
}
- if incompat && let Some((descr, def_id, substs, non_exhaustive)) = non_exhaustive {
+ if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive {
tcx.struct_span_lint_hir(
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
@@ -1168,7 +1230,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
} else {
"contains private fields"
};
- let field_ty = tcx.def_path_str_with_substs(def_id, substs);
+ let field_ty = tcx.def_path_str_with_args(def_id, args);
lint
.note(format!("this {descr} contains `{field_ty}`, which {note}, \
and makes it not a breaking change to become non-zero-sized in the future."))
@@ -1389,11 +1451,14 @@ pub(super) fn check_type_params_are_used<'tcx>(
}
}
-pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
let module = tcx.hir_module_items(module_def_id);
for id in module.items() {
check_item_type(tcx, id);
}
+ if module_def_id == LocalModDefId::CRATE_DEF_ID {
+ super::entry::check_for_entry_fn(tcx);
+ }
}
fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed {