@@ -12,7 +12,9 @@ use rustc_hir::def::{CtorKind, DefKind};
1212use rustc_hir:: { LangItem , Node , attrs, find_attr, intravisit} ;
1313use rustc_infer:: infer:: { RegionVariableOrigin , TyCtxtInferExt } ;
1414use rustc_infer:: traits:: { Obligation , ObligationCauseCode , WellFormedLoc } ;
15- use rustc_lint_defs:: builtin:: UNSUPPORTED_CALLING_CONVENTIONS ;
15+ use rustc_lint_defs:: builtin:: {
16+ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS , UNSUPPORTED_CALLING_CONVENTIONS ,
17+ } ;
1618use rustc_middle:: hir:: nested_filter;
1719use rustc_middle:: middle:: resolve_bound_vars:: ResolvedArg ;
1820use rustc_middle:: middle:: stability:: EvalResult ;
@@ -1510,7 +1512,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15101512
15111513 // For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST).
15121514 // 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".
1515+ // fields or `repr(C)` or uninhabited . We call those fields "unsuited".
15141516 struct FieldInfo < ' tcx > {
15151517 span : Span ,
15161518 trivial : bool ,
@@ -1539,6 +1541,16 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15391541 // No need to even compute `unsuited`.
15401542 return FieldInfo { span, trivial, unsuited : None } ;
15411543 }
1544+ if layout. unwrap ( ) . is_uninhabited ( ) {
1545+ // Uninhabited types aren't really "trivial"...
1546+ // See <https://github.com/rust-lang/rust/issues/135802> for some of the trouble
1547+ // this case used to cause.
1548+ return FieldInfo {
1549+ span,
1550+ trivial,
1551+ unsuited : Some ( UnsuitedInfo { ty, reason : UnsuitedReason :: Uninhabited } ) ,
1552+ } ;
1553+ }
15421554
15431555 fn check_unsuited < ' tcx > (
15441556 tcx : TyCtxt < ' tcx > ,
@@ -1586,15 +1598,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15861598 }
15871599 }
15881600
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- }
1601+ FieldInfo { span, trivial, unsuited : check_unsuited ( tcx, adt. did ( ) , ty) . break_value ( ) }
15981602 } ) ;
15991603
16001604 let non_trivial_fields = field_infos
@@ -1619,24 +1623,29 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
16191623 // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
16201624 // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
16211625 if non_trivial_count > 0 || prev_unsuited_1zst {
1622- let mut diag = tcx. dcx ( ) . struct_span_err (
1626+ tcx. node_span_lint (
1627+ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS ,
1628+ tcx. local_def_id_to_hir_id ( adt. did ( ) . expect_local ( ) ) ,
16231629 field. span ,
1624- "zero-sized fields in `repr(transparent)` cannot \
1630+ |lint| {
1631+ lint. primary_message (
1632+ "zero-sized fields in `repr(transparent)` cannot \
16251633 contain external non-exhaustive types",
1626- ) ;
1627- let note = match unsuited. reason {
1628- UnsuitedReason :: NonExhaustive => "is marked with `#[non_exhaustive]`" ,
1629- UnsuitedReason :: PrivateField => "contains private fields" ,
1630- UnsuitedReason :: ReprC => "is marked with `#[repr(C)]`" ,
1631- UnsuitedReason :: Uninhabited => "is not inhabited" ,
1632- } ;
1633- diag . note ( format ! (
1634- "this field contains `{field_ty}`, which {note}, \
1634+ ) ;
1635+ let note = match unsuited. reason {
1636+ UnsuitedReason :: NonExhaustive => "is marked with `#[non_exhaustive]`" ,
1637+ UnsuitedReason :: PrivateField => "contains private fields" ,
1638+ UnsuitedReason :: ReprC => "is marked with `#[repr(C)]`" ,
1639+ UnsuitedReason :: Uninhabited => "is not inhabited" ,
1640+ } ;
1641+ lint . note ( format ! (
1642+ "this field contains `{field_ty}`, which {note}, \
16351643 and makes it not a breaking change to become \
16361644 non-zero-sized in the future.",
1637- field_ty = unsuited. ty,
1638- ) ) ;
1639- diag. emit ( ) ;
1645+ field_ty = unsuited. ty,
1646+ ) ) ;
1647+ } ,
1648+ ) ;
16401649 } else {
16411650 prev_unsuited_1zst = true ;
16421651 }
0 commit comments