Skip to content

Commit 44cb9b1

Browse files
committed
revert code to be more like previous structure, but with explicit types
1 parent c1dcd7e commit 44cb9b1

File tree

1 file changed

+86
-66
lines changed
  • compiler/rustc_hir_analysis/src/check

1 file changed

+86
-66
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 86 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,20 +1509,97 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15091509
}
15101510

15111511
// For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST).
1512+
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private
1513+
// fields or `repr(C)`. We call those fields "unsuited".
1514+
struct FieldInfo<'tcx> {
1515+
span: Span,
1516+
trivial: bool,
1517+
unsuited: Option<UnsuitedInfo<'tcx>>,
1518+
}
1519+
struct UnsuitedInfo<'tcx> {
1520+
/// The source of the problem, a type that is found somewhere within the field type.
1521+
ty: Ty<'tcx>,
1522+
reason: UnsuitedReason,
1523+
}
1524+
enum UnsuitedReason {
1525+
NonExhaustive,
1526+
PrivateField,
1527+
ReprC,
1528+
Uninhabited,
1529+
}
1530+
15121531
let field_infos = adt.all_fields().map(|field| {
15131532
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
15141533
let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did);
15151534
let layout = tcx.layout_of(typing_env.as_query_input(ty));
15161535
// We are currently checking the type this field came from, so it must be local
15171536
let span = tcx.hir_span_if_local(field.did).unwrap();
15181537
let trivial = layout.is_ok_and(|layout| layout.is_1zst());
1519-
let uninhabited = layout.is_ok_and(|layout| layout.is_uninhabited());
1520-
(span, trivial, uninhabited, ty)
1538+
if !trivial {
1539+
// No need to even compute `unsuited`.
1540+
return FieldInfo { span, trivial, unsuited: None };
1541+
}
1542+
1543+
fn check_unsuited<'tcx>(
1544+
tcx: TyCtxt<'tcx>,
1545+
adt: DefId,
1546+
ty: Ty<'tcx>,
1547+
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1548+
match ty.kind() {
1549+
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, adt, t)),
1550+
ty::Array(ty, _) => check_unsuited(tcx, adt, *ty),
1551+
ty::Adt(def, args) => {
1552+
if !def.did().is_local()
1553+
&& !find_attr!(
1554+
tcx.get_all_attrs(def.did()),
1555+
AttributeKind::PubTransparent(_)
1556+
)
1557+
{
1558+
let non_exhaustive = def.is_variant_list_non_exhaustive()
1559+
|| def
1560+
.variants()
1561+
.iter()
1562+
.any(ty::VariantDef::is_field_list_non_exhaustive);
1563+
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
1564+
if non_exhaustive || has_priv {
1565+
return ControlFlow::Break(UnsuitedInfo {
1566+
ty,
1567+
reason: if non_exhaustive {
1568+
UnsuitedReason::NonExhaustive
1569+
} else {
1570+
UnsuitedReason::PrivateField
1571+
},
1572+
});
1573+
}
1574+
}
1575+
if def.repr().c() {
1576+
return ControlFlow::Break(UnsuitedInfo {
1577+
ty,
1578+
reason: UnsuitedReason::ReprC,
1579+
});
1580+
}
1581+
def.all_fields()
1582+
.map(|field| field.ty(tcx, args))
1583+
.try_for_each(|t| check_unsuited(tcx, adt, t))
1584+
}
1585+
_ => ControlFlow::Continue(()),
1586+
}
1587+
}
1588+
1589+
FieldInfo {
1590+
span,
1591+
trivial,
1592+
unsuited: check_unsuited(tcx, adt.did(), ty).break_value().or_else(|| {
1593+
// We don't need to check this recursively, a single top-level check suffices.
1594+
let uninhabited = layout.is_ok_and(|layout| layout.is_uninhabited());
1595+
uninhabited.then_some(UnsuitedInfo { ty, reason: UnsuitedReason::Uninhabited })
1596+
}),
1597+
}
15211598
});
15221599

1523-
let non_trivial_fields = field_infos.clone().filter_map(
1524-
|(span, trivial, _uninhabited, _non_exhaustive)| if !trivial { Some(span) } else { None },
1525-
);
1600+
let non_trivial_fields = field_infos
1601+
.clone()
1602+
.filter_map(|field| if !field.trivial { Some(field.span) } else { None });
15261603
let non_trivial_count = non_trivial_fields.clone().count();
15271604
if non_trivial_count >= 2 {
15281605
bad_non_zero_sized_fields(
@@ -1535,72 +1612,15 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15351612
return;
15361613
}
15371614

1538-
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private
1539-
// fields or `repr(C)`. We call those fields "unsuited". Search for unsuited fields and
1540-
// error if the repr(transparent) condition relies on them.
1541-
enum UnsuitedReason {
1542-
NonExhaustive,
1543-
PrivateField,
1544-
ReprC,
1545-
Uninhabited,
1546-
}
1547-
struct UnsuitedInfo<'tcx> {
1548-
ty: Ty<'tcx>,
1549-
reason: UnsuitedReason,
1550-
}
1551-
1552-
fn check_unsuited_1zst<'tcx>(
1553-
tcx: TyCtxt<'tcx>,
1554-
adt: DefId,
1555-
ty: Ty<'tcx>,
1556-
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1557-
match ty.kind() {
1558-
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited_1zst(tcx, adt, t)),
1559-
ty::Array(ty, _) => check_unsuited_1zst(tcx, adt, *ty),
1560-
ty::Adt(def, args) => {
1561-
if !def.did().is_local()
1562-
&& !find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::PubTransparent(_))
1563-
{
1564-
let non_exhaustive = def.is_variant_list_non_exhaustive()
1565-
|| def.variants().iter().any(ty::VariantDef::is_field_list_non_exhaustive);
1566-
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
1567-
if non_exhaustive || has_priv {
1568-
return ControlFlow::Break(UnsuitedInfo {
1569-
ty,
1570-
reason: if non_exhaustive {
1571-
UnsuitedReason::NonExhaustive
1572-
} else {
1573-
UnsuitedReason::PrivateField
1574-
},
1575-
});
1576-
}
1577-
}
1578-
if def.repr().c() {
1579-
return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC });
1580-
}
1581-
def.all_fields()
1582-
.map(|field| field.ty(tcx, args))
1583-
.try_for_each(|t| check_unsuited_1zst(tcx, adt, t))
1584-
}
1585-
_ => ControlFlow::Continue(()),
1586-
}
1587-
}
1588-
15891615
let mut prev_unsuited_1zst = false;
1590-
for (span, trivial, uninhabited, ty) in field_infos {
1591-
if !trivial {
1592-
continue;
1593-
}
1594-
if let Some(unsuited) =
1595-
check_unsuited_1zst(tcx, adt.did(), ty).break_value().or_else(|| {
1596-
uninhabited.then_some(UnsuitedInfo { ty, reason: UnsuitedReason::Uninhabited })
1597-
})
1598-
{
1616+
for field in field_infos {
1617+
if let Some(unsuited) = field.unsuited {
1618+
assert!(field.trivial);
15991619
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
16001620
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
16011621
if non_trivial_count > 0 || prev_unsuited_1zst {
16021622
let mut diag = tcx.dcx().struct_span_err(
1603-
span,
1623+
field.span,
16041624
"zero-sized fields in `repr(transparent)` cannot \
16051625
contain external non-exhaustive types",
16061626
);

0 commit comments

Comments
 (0)