Skip to content

Commit 9fcd3c8

Browse files
Auto merge of #148243 - RalfJung:perf-transparent-checks, r=<try>
perf experiment for #147185
2 parents c6d42d7 + dd40018 commit 9fcd3c8

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
@@ -1508,22 +1508,10 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15081508

15091509
let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did());
15101510
// For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST).
1511-
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private
1512-
// fields or `repr(C)`. We call those fields "unsuited".
15131511
struct FieldInfo<'tcx> {
15141512
span: Span,
15151513
trivial: bool,
1516-
unsuited: Option<UnsuitedInfo<'tcx>>,
1517-
}
1518-
struct UnsuitedInfo<'tcx> {
1519-
/// The source of the problem, a type that is found somewhere within the field type.
15201514
ty: Ty<'tcx>,
1521-
reason: UnsuitedReason,
1522-
}
1523-
enum UnsuitedReason {
1524-
NonExhaustive,
1525-
PrivateField,
1526-
ReprC,
15271515
}
15281516

15291517
let field_infos = adt.all_fields().map(|field| {
@@ -1532,60 +1520,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15321520
// We are currently checking the type this field came from, so it must be local
15331521
let span = tcx.hir_span_if_local(field.did).unwrap();
15341522
let trivial = layout.is_ok_and(|layout| layout.is_1zst());
1535-
if !trivial {
1536-
// No need to even compute `unsuited`.
1537-
return FieldInfo { span, trivial, unsuited: None };
1538-
}
1539-
1540-
fn check_unsuited<'tcx>(
1541-
tcx: TyCtxt<'tcx>,
1542-
typing_env: ty::TypingEnv<'tcx>,
1543-
ty: Ty<'tcx>,
1544-
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1545-
// We can encounter projections during traversal, so ensure the type is normalized.
1546-
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
1547-
match ty.kind() {
1548-
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),
1549-
ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),
1550-
ty::Adt(def, args) => {
1551-
if !def.did().is_local()
1552-
&& !find_attr!(
1553-
tcx.get_all_attrs(def.did()),
1554-
AttributeKind::PubTransparent(_)
1555-
)
1556-
{
1557-
let non_exhaustive = def.is_variant_list_non_exhaustive()
1558-
|| def
1559-
.variants()
1560-
.iter()
1561-
.any(ty::VariantDef::is_field_list_non_exhaustive);
1562-
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
1563-
if non_exhaustive || has_priv {
1564-
return ControlFlow::Break(UnsuitedInfo {
1565-
ty,
1566-
reason: if non_exhaustive {
1567-
UnsuitedReason::NonExhaustive
1568-
} else {
1569-
UnsuitedReason::PrivateField
1570-
},
1571-
});
1572-
}
1573-
}
1574-
if def.repr().c() {
1575-
return ControlFlow::Break(UnsuitedInfo {
1576-
ty,
1577-
reason: UnsuitedReason::ReprC,
1578-
});
1579-
}
1580-
def.all_fields()
1581-
.map(|field| field.ty(tcx, args))
1582-
.try_for_each(|t| check_unsuited(tcx, typing_env, t))
1583-
}
1584-
_ => ControlFlow::Continue(()),
1585-
}
1586-
}
1587-
1588-
FieldInfo { span, trivial, unsuited: check_unsuited(tcx, typing_env, ty).break_value() }
1523+
return FieldInfo { span, trivial, ty };
15891524
});
15901525

15911526
let non_trivial_fields = field_infos
@@ -1603,10 +1538,63 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
16031538
return;
16041539
}
16051540

1541+
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private
1542+
// fields or `repr(C)`. We call those fields "unsuited".
1543+
struct UnsuitedInfo<'tcx> {
1544+
/// The source of the problem, a type that is found somewhere within the field type.
1545+
ty: Ty<'tcx>,
1546+
reason: UnsuitedReason,
1547+
}
1548+
enum UnsuitedReason {
1549+
NonExhaustive,
1550+
PrivateField,
1551+
ReprC,
1552+
}
1553+
1554+
fn check_unsuited<'tcx>(
1555+
tcx: TyCtxt<'tcx>,
1556+
typing_env: ty::TypingEnv<'tcx>,
1557+
ty: Ty<'tcx>,
1558+
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1559+
// We can encounter projections during traversal, so ensure the type is normalized.
1560+
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
1561+
match ty.kind() {
1562+
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),
1563+
ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),
1564+
ty::Adt(def, args) => {
1565+
if !def.did().is_local()
1566+
&& !find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::PubTransparent(_))
1567+
{
1568+
let non_exhaustive = def.is_variant_list_non_exhaustive()
1569+
|| def.variants().iter().any(ty::VariantDef::is_field_list_non_exhaustive);
1570+
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
1571+
if non_exhaustive || has_priv {
1572+
return ControlFlow::Break(UnsuitedInfo {
1573+
ty,
1574+
reason: if non_exhaustive {
1575+
UnsuitedReason::NonExhaustive
1576+
} else {
1577+
UnsuitedReason::PrivateField
1578+
},
1579+
});
1580+
}
1581+
}
1582+
if def.repr().c() {
1583+
return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC });
1584+
}
1585+
def.all_fields()
1586+
.map(|field| field.ty(tcx, args))
1587+
.try_for_each(|t| check_unsuited(tcx, typing_env, t))
1588+
}
1589+
_ => ControlFlow::Continue(()),
1590+
}
1591+
}
1592+
16061593
let mut prev_unsuited_1zst = false;
16071594
for field in field_infos {
1608-
if let Some(unsuited) = field.unsuited {
1609-
assert!(field.trivial);
1595+
if field.trivial
1596+
&& let Some(unsuited) = check_unsuited(tcx, typing_env, field.ty).break_value()
1597+
{
16101598
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
16111599
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
16121600
if non_trivial_count > 0 || prev_unsuited_1zst {

0 commit comments

Comments
 (0)