diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 886ebddc75c97..8a0ecc5d3fc18 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1510,8 +1510,26 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) return; } - // For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with - // "known" respecting #[non_exhaustive] attributes. + // For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST). + // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private + // fields or `repr(C)` or uninhabited. We call those fields "unsuited". + struct FieldInfo<'tcx> { + span: Span, + trivial: bool, + unsuited: Option>, + } + struct UnsuitedInfo<'tcx> { + /// The source of the problem, a type that is found somewhere within the field type. + ty: Ty<'tcx>, + reason: UnsuitedReason, + } + enum UnsuitedReason { + NonExhaustive, + PrivateField, + ReprC, + Uninhabited, + } + let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did)); let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did); @@ -1520,17 +1538,28 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) let span = tcx.hir_span_if_local(field.did).unwrap(); let trivial = layout.is_ok_and(|layout| layout.is_1zst()); if !trivial { - return (span, trivial, None); + // No need to even compute `unsuited`. + return FieldInfo { span, trivial, unsuited: None }; + } + if layout.unwrap().is_uninhabited() { + // Uninhabited types aren't really "trivial"... + // See for some of the trouble + // this case used to cause. + return FieldInfo { + span, + trivial, + unsuited: Some(UnsuitedInfo { ty, reason: UnsuitedReason::Uninhabited }), + }; } - // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`. - fn check_non_exhaustive<'tcx>( + fn check_unsuited<'tcx>( tcx: TyCtxt<'tcx>, - t: Ty<'tcx>, - ) -> 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), + adt: DefId, + ty: Ty<'tcx>, + ) -> ControlFlow> { + match ty.kind() { + ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, adt, t)), + ty::Array(ty, _) => check_unsuited(tcx, adt, *ty), ty::Adt(def, args) => { if !def.did().is_local() && !find_attr!( @@ -1545,28 +1574,36 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) .any(ty::VariantDef::is_field_list_non_exhaustive); let has_priv = def.all_fields().any(|f| !f.vis.is_public()); if non_exhaustive || has_priv { - return ControlFlow::Break(( - def.descr(), - def.did(), - args, - non_exhaustive, - )); + return ControlFlow::Break(UnsuitedInfo { + ty, + reason: if non_exhaustive { + UnsuitedReason::NonExhaustive + } else { + UnsuitedReason::PrivateField + }, + }); } } + if def.repr().c() { + return ControlFlow::Break(UnsuitedInfo { + ty, + reason: UnsuitedReason::ReprC, + }); + } def.all_fields() .map(|field| field.ty(tcx, args)) - .try_for_each(|t| check_non_exhaustive(tcx, t)) + .try_for_each(|t| check_unsuited(tcx, adt, t)) } _ => ControlFlow::Continue(()), } } - (span, trivial, check_non_exhaustive(tcx, ty).break_value()) + FieldInfo { span, trivial, unsuited: check_unsuited(tcx, adt.did(), ty).break_value() } }); let non_trivial_fields = field_infos .clone() - .filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None }); + .filter_map(|field| if !field.trivial { Some(field.span) } else { None }); let non_trivial_count = non_trivial_fields.clone().count(); if non_trivial_count >= 2 { bad_non_zero_sized_fields( @@ -1578,36 +1615,39 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) ); return; } - let mut prev_non_exhaustive_1zst = false; - for (span, _trivial, non_exhaustive_1zst) in field_infos { - if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst { + + let mut prev_unsuited_1zst = false; + for field in field_infos { + if let Some(unsuited) = field.unsuited { + assert!(field.trivial); // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. - if non_trivial_count > 0 || prev_non_exhaustive_1zst { + if non_trivial_count > 0 || prev_unsuited_1zst { tcx.node_span_lint( REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, tcx.local_def_id_to_hir_id(adt.did().expect_local()), - span, + field.span, |lint| { lint.primary_message( "zero-sized fields in `repr(transparent)` cannot \ contain external non-exhaustive types", ); - let note = if non_exhaustive { - "is marked with `#[non_exhaustive]`" - } else { - "contains private fields" + let note = match unsuited.reason { + UnsuitedReason::NonExhaustive => "is marked with `#[non_exhaustive]`", + UnsuitedReason::PrivateField => "contains private fields", + UnsuitedReason::ReprC => "is marked with `#[repr(C)]`", + UnsuitedReason::Uninhabited => "is not inhabited", }; - let field_ty = tcx.def_path_str_with_args(def_id, args); lint.note(format!( - "this {descr} contains `{field_ty}`, which {note}, \ + "this field contains `{field_ty}`, which {note}, \ and makes it not a breaking change to become \ - non-zero-sized in the future." + non-zero-sized in the future.", + field_ty = unsuited.ty, )); }, - ) + ); } else { - prev_non_exhaustive_1zst = true; + prev_unsuited_1zst = true; } } } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 40a818a3c9dc7..ec26c35ffdc9f 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -403,7 +403,7 @@ pub enum FutureIncompatibilityReason { /// /// After a lint has been in this state for a while and you feel like it is ready to graduate /// to warning everyone, consider setting [`FutureIncompatibleInfo::report_in_deps`] to true. - /// (see it's documentation for more guidance) + /// (see its documentation for more guidance) /// /// After some period of time, lints with this variant can be turned into /// hard errors (and the lint removed). Preferably when there is some diff --git a/src/build_helper/src/lib.rs b/src/build_helper/src/lib.rs index 266eedc624582..50027488760cf 100644 --- a/src/build_helper/src/lib.rs +++ b/src/build_helper/src/lib.rs @@ -18,7 +18,6 @@ pub const LLVM_PGO_CRATES: &[&str] = &[ "ripgrep-14.1.1", "regex-automata-0.4.8", "clap_derive-4.5.32", - "hyper-1.6.0", ]; /// The default set of crates for opt-dist to collect rustc profiles. diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.stderr b/tests/ui/repr/repr-transparent-non-exhaustive.stderr index 808b9bc986d91..edd39dc3adaee 100644 --- a/tests/ui/repr/repr-transparent-non-exhaustive.stderr +++ b/tests/ui/repr/repr-transparent-non-exhaustive.stderr @@ -6,7 +6,7 @@ LL | pub struct T5(Sized, Private); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -21,7 +21,7 @@ LL | pub struct T6(Sized, NonExhaustive); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:47:22 @@ -31,7 +31,7 @@ LL | pub struct T7(Sized, NonExhaustiveEnum); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustiveEnum`, which is not inhabited, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:52:22 @@ -41,7 +41,7 @@ LL | pub struct T8(Sized, NonExhaustiveVariant); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:57:22 @@ -51,7 +51,7 @@ LL | pub struct T9(Sized, InternalIndirection); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:62:23 @@ -61,7 +61,7 @@ LL | pub struct T10(Sized, InternalIndirection); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:67:23 @@ -71,7 +71,7 @@ LL | pub struct T11(Sized, InternalIndirection); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `InternalIndirection`, which is not inhabited, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:72:23 @@ -81,7 +81,7 @@ LL | pub struct T12(Sized, InternalIndirection); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:77:23 @@ -91,7 +91,7 @@ LL | pub struct T13(Sized, ExternalIndirection); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:82:23 @@ -101,7 +101,7 @@ LL | pub struct T14(Sized, ExternalIndirection); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:87:23 @@ -111,7 +111,7 @@ LL | pub struct T15(Sized, ExternalIndirection); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `ExternalIndirection`, which is not inhabited, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:92:23 @@ -121,7 +121,7 @@ LL | pub struct T16(Sized, ExternalIndirection); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:97:16 @@ -131,7 +131,7 @@ LL | pub struct T17(NonExhaustive, Sized); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:102:31 @@ -141,7 +141,7 @@ LL | pub struct T18(NonExhaustive, NonExhaustive); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:107:31 @@ -151,7 +151,7 @@ LL | pub struct T19(NonExhaustive, Private); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:112:32 @@ -161,7 +161,7 @@ LL | pub struct T19Flipped(Private, NonExhaustive); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: aborting due to 16 previous errors diff --git a/tests/ui/repr/repr-transparent-repr-c.rs b/tests/ui/repr/repr-transparent-repr-c.rs new file mode 100644 index 0000000000000..17d82870e352b --- /dev/null +++ b/tests/ui/repr/repr-transparent-repr-c.rs @@ -0,0 +1,32 @@ +#![deny(repr_transparent_external_private_fields)] + +#[repr(C)] +pub struct ReprC1Zst { + pub _f: (), +} + +pub type Sized = i32; + +#[repr(transparent)] +pub struct T1(ReprC1Zst); +#[repr(transparent)] +pub struct T2((), ReprC1Zst); +#[repr(transparent)] +pub struct T3(ReprC1Zst, ()); + +#[repr(transparent)] +pub struct T5(Sized, ReprC1Zst); +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T6(ReprC1Zst, Sized); +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/tests/ui/repr/repr-transparent-repr-c.stderr b/tests/ui/repr/repr-transparent-repr-c.stderr new file mode 100644 index 0000000000000..43426d0cd6203 --- /dev/null +++ b/tests/ui/repr/repr-transparent-repr-c.stderr @@ -0,0 +1,37 @@ +error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types + --> $DIR/repr-transparent-repr-c.rs:18:22 + | +LL | pub struct T5(Sized, ReprC1Zst); + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this field contains `ReprC1Zst`, which is marked with `#[repr(C)]`, and makes it not a breaking change to become non-zero-sized in the future. +note: the lint level is defined here + --> $DIR/repr-transparent-repr-c.rs:1:9 + | +LL | #![deny(repr_transparent_external_private_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types + --> $DIR/repr-transparent-repr-c.rs:23:15 + | +LL | pub struct T6(ReprC1Zst, Sized); + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this field contains `ReprC1Zst`, which is marked with `#[repr(C)]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types + --> $DIR/repr-transparent-repr-c.rs:28:15 + | +LL | pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this field contains `ReprC1Zst`, which is marked with `#[repr(C)]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: aborting due to 3 previous errors + diff --git a/tests/ui/repr/repr-transparent-uninhabited.rs b/tests/ui/repr/repr-transparent-uninhabited.rs new file mode 100644 index 0000000000000..7f6be9684fed2 --- /dev/null +++ b/tests/ui/repr/repr-transparent-uninhabited.rs @@ -0,0 +1,25 @@ +#![feature(never_type)] +#![deny(repr_transparent_external_private_fields)] + +enum Void {} + +pub type Sized = i32; + +#[repr(transparent)] +pub struct T1(!); +#[repr(transparent)] +pub struct T2((), Void); +#[repr(transparent)] +pub struct T3(!, ()); + +#[repr(transparent)] +pub struct T5(Sized, Void); +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T6(!, Sized); +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/tests/ui/repr/repr-transparent-uninhabited.stderr b/tests/ui/repr/repr-transparent-uninhabited.stderr new file mode 100644 index 0000000000000..bd475ad25a7cc --- /dev/null +++ b/tests/ui/repr/repr-transparent-uninhabited.stderr @@ -0,0 +1,27 @@ +error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types + --> $DIR/repr-transparent-uninhabited.rs:16:22 + | +LL | pub struct T5(Sized, Void); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this field contains `Void`, which is not inhabited, and makes it not a breaking change to become non-zero-sized in the future. +note: the lint level is defined here + --> $DIR/repr-transparent-uninhabited.rs:2:9 + | +LL | #![deny(repr_transparent_external_private_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types + --> $DIR/repr-transparent-uninhabited.rs:21:15 + | +LL | pub struct T6(!, Sized); + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this field contains `!`, which is not inhabited, and makes it not a breaking change to become non-zero-sized in the future. + +error: aborting due to 2 previous errors + diff --git a/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs b/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs index e439a82be5abb..7a658d80ee893 100644 --- a/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs +++ b/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs @@ -7,6 +7,7 @@ enum Void {} // Should be ABI-compatible with T, but wasn't prior to the PR adding this test. #[repr(transparent)] +#[allow(repr_transparent_external_private_fields)] struct NoReturn(T, Void); // Returned by invisible reference (in most ABIs)