Skip to content

Commit c23182e

Browse files
committed
repr(transparent) check: do not compute check_unsuited more than once
1 parent 42ebbd2 commit c23182e

File tree

1 file changed

+56
-68
lines changed
  • compiler/rustc_hir_analysis/src/check

1 file changed

+56
-68
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 56 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,22 +1542,10 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15421542

15431543
let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did());
15441544
// For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST).
1545-
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private
1546-
// fields or `repr(C)`. We call those fields "unsuited".
15471545
struct FieldInfo<'tcx> {
15481546
span: Span,
15491547
trivial: bool,
1550-
unsuited: Option<UnsuitedInfo<'tcx>>,
1551-
}
1552-
struct UnsuitedInfo<'tcx> {
1553-
/// The source of the problem, a type that is found somewhere within the field type.
15541548
ty: Ty<'tcx>,
1555-
reason: UnsuitedReason,
1556-
}
1557-
enum UnsuitedReason {
1558-
NonExhaustive,
1559-
PrivateField,
1560-
ReprC,
15611549
}
15621550

15631551
let field_infos = adt.all_fields().map(|field| {
@@ -1566,60 +1554,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15661554
// We are currently checking the type this field came from, so it must be local
15671555
let span = tcx.hir_span_if_local(field.did).unwrap();
15681556
let trivial = layout.is_ok_and(|layout| layout.is_1zst());
1569-
if !trivial {
1570-
// No need to even compute `unsuited`.
1571-
return FieldInfo { span, trivial, unsuited: None };
1572-
}
1573-
1574-
fn check_unsuited<'tcx>(
1575-
tcx: TyCtxt<'tcx>,
1576-
typing_env: ty::TypingEnv<'tcx>,
1577-
ty: Ty<'tcx>,
1578-
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1579-
// We can encounter projections during traversal, so ensure the type is normalized.
1580-
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
1581-
match ty.kind() {
1582-
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),
1583-
ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),
1584-
ty::Adt(def, args) => {
1585-
if !def.did().is_local()
1586-
&& !find_attr!(
1587-
tcx.get_all_attrs(def.did()),
1588-
AttributeKind::PubTransparent(_)
1589-
)
1590-
{
1591-
let non_exhaustive = def.is_variant_list_non_exhaustive()
1592-
|| def
1593-
.variants()
1594-
.iter()
1595-
.any(ty::VariantDef::is_field_list_non_exhaustive);
1596-
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
1597-
if non_exhaustive || has_priv {
1598-
return ControlFlow::Break(UnsuitedInfo {
1599-
ty,
1600-
reason: if non_exhaustive {
1601-
UnsuitedReason::NonExhaustive
1602-
} else {
1603-
UnsuitedReason::PrivateField
1604-
},
1605-
});
1606-
}
1607-
}
1608-
if def.repr().c() {
1609-
return ControlFlow::Break(UnsuitedInfo {
1610-
ty,
1611-
reason: UnsuitedReason::ReprC,
1612-
});
1613-
}
1614-
def.all_fields()
1615-
.map(|field| field.ty(tcx, args))
1616-
.try_for_each(|t| check_unsuited(tcx, typing_env, t))
1617-
}
1618-
_ => ControlFlow::Continue(()),
1619-
}
1620-
}
1621-
1622-
FieldInfo { span, trivial, unsuited: check_unsuited(tcx, typing_env, ty).break_value() }
1557+
FieldInfo { span, trivial, ty }
16231558
});
16241559

16251560
let non_trivial_fields = field_infos
@@ -1637,10 +1572,63 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
16371572
return;
16381573
}
16391574

1575+
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private
1576+
// fields or `repr(C)`. We call those fields "unsuited".
1577+
struct UnsuitedInfo<'tcx> {
1578+
/// The source of the problem, a type that is found somewhere within the field type.
1579+
ty: Ty<'tcx>,
1580+
reason: UnsuitedReason,
1581+
}
1582+
enum UnsuitedReason {
1583+
NonExhaustive,
1584+
PrivateField,
1585+
ReprC,
1586+
}
1587+
1588+
fn check_unsuited<'tcx>(
1589+
tcx: TyCtxt<'tcx>,
1590+
typing_env: ty::TypingEnv<'tcx>,
1591+
ty: Ty<'tcx>,
1592+
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1593+
// We can encounter projections during traversal, so ensure the type is normalized.
1594+
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
1595+
match ty.kind() {
1596+
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),
1597+
ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),
1598+
ty::Adt(def, args) => {
1599+
if !def.did().is_local()
1600+
&& !find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::PubTransparent(_))
1601+
{
1602+
let non_exhaustive = def.is_variant_list_non_exhaustive()
1603+
|| def.variants().iter().any(ty::VariantDef::is_field_list_non_exhaustive);
1604+
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
1605+
if non_exhaustive || has_priv {
1606+
return ControlFlow::Break(UnsuitedInfo {
1607+
ty,
1608+
reason: if non_exhaustive {
1609+
UnsuitedReason::NonExhaustive
1610+
} else {
1611+
UnsuitedReason::PrivateField
1612+
},
1613+
});
1614+
}
1615+
}
1616+
if def.repr().c() {
1617+
return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC });
1618+
}
1619+
def.all_fields()
1620+
.map(|field| field.ty(tcx, args))
1621+
.try_for_each(|t| check_unsuited(tcx, typing_env, t))
1622+
}
1623+
_ => ControlFlow::Continue(()),
1624+
}
1625+
}
1626+
16401627
let mut prev_unsuited_1zst = false;
16411628
for field in field_infos {
1642-
if let Some(unsuited) = field.unsuited {
1643-
assert!(field.trivial);
1629+
if field.trivial
1630+
&& let Some(unsuited) = check_unsuited(tcx, typing_env, field.ty).break_value()
1631+
{
16441632
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
16451633
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
16461634
if non_trivial_count > 0 || prev_unsuited_1zst {

0 commit comments

Comments
 (0)