Skip to content

Commit eee5199

Browse files
committed
also complain about uninhabited types being ignored in repr(transparent)
1 parent 24d6a9a commit eee5199

File tree

5 files changed

+77
-40
lines changed

5 files changed

+77
-40
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,21 +1541,24 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15411541
NonExhaustive,
15421542
PrivateField,
15431543
ReprC,
1544+
Uninhabited,
15441545
}
15451546
struct UnsuitedInfo<'tcx> {
1546-
descr: &'static str,
1547-
def_id: DefId,
1548-
args: GenericArgsRef<'tcx>,
1547+
ty: Ty<'tcx>,
15491548
reason: UnsuitedReason,
15501549
}
15511550

15521551
fn check_unsuited_1zst<'tcx>(
15531552
tcx: TyCtxt<'tcx>,
1554-
t: Ty<'tcx>,
1553+
adt: DefId,
1554+
ty: Ty<'tcx>,
15551555
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1556-
match t.kind() {
1557-
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited_1zst(tcx, t)),
1558-
ty::Array(ty, _) => check_unsuited_1zst(tcx, *ty),
1556+
if !ty.is_inhabited_from(tcx, adt, ty::TypingEnv::non_body_analysis(tcx, adt)) {
1557+
return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::Uninhabited });
1558+
}
1559+
match ty.kind() {
1560+
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited_1zst(tcx, adt, t)),
1561+
ty::Array(ty, _) => check_unsuited_1zst(tcx, adt, *ty),
15591562
ty::Adt(def, args) => {
15601563
if !def.did().is_local()
15611564
&& !find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::PubTransparent(_))
@@ -1565,9 +1568,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15651568
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
15661569
if non_exhaustive || has_priv {
15671570
return ControlFlow::Break(UnsuitedInfo {
1568-
descr: def.descr(),
1569-
def_id: def.did(),
1570-
args,
1571+
ty,
15711572
reason: if non_exhaustive {
15721573
UnsuitedReason::NonExhaustive
15731574
} else {
@@ -1577,16 +1578,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15771578
}
15781579
}
15791580
if def.repr().c() {
1580-
return ControlFlow::Break(UnsuitedInfo {
1581-
descr: def.descr(),
1582-
def_id: def.did(),
1583-
args,
1584-
reason: UnsuitedReason::ReprC,
1585-
});
1581+
return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC });
15861582
}
15871583
def.all_fields()
15881584
.map(|field| field.ty(tcx, args))
1589-
.try_for_each(|t| check_unsuited_1zst(tcx, t))
1585+
.try_for_each(|t| check_unsuited_1zst(tcx, adt, t))
15901586
}
15911587
_ => ControlFlow::Continue(()),
15921588
}
@@ -1597,7 +1593,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15971593
if !trivial {
15981594
continue;
15991595
}
1600-
if let Some(unsuited) = check_unsuited_1zst(tcx, ty).break_value() {
1596+
if let Some(unsuited) = check_unsuited_1zst(tcx, adt.did(), ty).break_value() {
16011597
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
16021598
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
16031599
if non_trivial_count > 0 || prev_unsuited_1zst {
@@ -1610,13 +1606,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
16101606
UnsuitedReason::NonExhaustive => "is marked with `#[non_exhaustive]`",
16111607
UnsuitedReason::PrivateField => "contains private fields",
16121608
UnsuitedReason::ReprC => "is marked with `#[repr(C)]`",
1609+
UnsuitedReason::Uninhabited => "is not (publicly) inhabited",
16131610
};
1614-
let field_ty = tcx.def_path_str_with_args(unsuited.def_id, unsuited.args);
16151611
diag.note(format!(
1616-
"this {descr} contains `{field_ty}`, which {note}, \
1612+
"this field contains `{field_ty}`, which {note}, \
16171613
and makes it not a breaking change to become \
16181614
non-zero-sized in the future.",
1619-
descr = unsuited.descr,
1615+
field_ty = unsuited.ty,
16201616
));
16211617
diag.emit();
16221618
} else {

tests/ui/repr/repr-transparent-non-exhaustive.stderr

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,127 +4,127 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha
44
LL | pub struct T5(Sized, Private);
55
| ^^^^^^^
66
|
7-
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
7+
= note: this field contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
88

99
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
1010
--> $DIR/repr-transparent-non-exhaustive.rs:41:22
1111
|
1212
LL | pub struct T6(Sized, NonExhaustive);
1313
| ^^^^^^^^^^^^^
1414
|
15-
= 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.
15+
= 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.
1616

1717
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
1818
--> $DIR/repr-transparent-non-exhaustive.rs:45:22
1919
|
2020
LL | pub struct T7(Sized, NonExhaustiveEnum);
2121
| ^^^^^^^^^^^^^^^^^
2222
|
23-
= 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.
23+
= note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
2424

2525
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
2626
--> $DIR/repr-transparent-non-exhaustive.rs:49:22
2727
|
2828
LL | pub struct T8(Sized, NonExhaustiveVariant);
2929
| ^^^^^^^^^^^^^^^^^^^^
3030
|
31-
= 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.
31+
= 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.
3232

3333
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
3434
--> $DIR/repr-transparent-non-exhaustive.rs:53:22
3535
|
3636
LL | pub struct T9(Sized, InternalIndirection<Private>);
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3838
|
39-
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
39+
= note: this field contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
4040

4141
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
4242
--> $DIR/repr-transparent-non-exhaustive.rs:57:23
4343
|
4444
LL | pub struct T10(Sized, InternalIndirection<NonExhaustive>);
4545
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4646
|
47-
= 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.
47+
= 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.
4848

4949
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
5050
--> $DIR/repr-transparent-non-exhaustive.rs:61:23
5151
|
5252
LL | pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
5353
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5454
|
55-
= 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.
55+
= note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
5656

5757
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
5858
--> $DIR/repr-transparent-non-exhaustive.rs:65:23
5959
|
6060
LL | pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
6161
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6262
|
63-
= 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.
63+
= 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.
6464

6565
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
6666
--> $DIR/repr-transparent-non-exhaustive.rs:69:23
6767
|
6868
LL | pub struct T13(Sized, ExternalIndirection<Private>);
6969
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7070
|
71-
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
71+
= note: this field contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
7272

7373
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
7474
--> $DIR/repr-transparent-non-exhaustive.rs:73:23
7575
|
7676
LL | pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
7777
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7878
|
79-
= 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.
79+
= 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.
8080

8181
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
8282
--> $DIR/repr-transparent-non-exhaustive.rs:77:23
8383
|
8484
LL | pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
8585
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8686
|
87-
= 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.
87+
= note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
8888

8989
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
9090
--> $DIR/repr-transparent-non-exhaustive.rs:81:23
9191
|
9292
LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
9393
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9494
|
95-
= 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.
95+
= 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.
9696

9797
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
9898
--> $DIR/repr-transparent-non-exhaustive.rs:85:16
9999
|
100100
LL | pub struct T17(NonExhaustive, Sized);
101101
| ^^^^^^^^^^^^^
102102
|
103-
= 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.
103+
= 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.
104104

105105
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
106106
--> $DIR/repr-transparent-non-exhaustive.rs:89:31
107107
|
108108
LL | pub struct T18(NonExhaustive, NonExhaustive);
109109
| ^^^^^^^^^^^^^
110110
|
111-
= 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.
111+
= 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.
112112

113113
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
114114
--> $DIR/repr-transparent-non-exhaustive.rs:93:31
115115
|
116116
LL | pub struct T19(NonExhaustive, Private);
117117
| ^^^^^^^
118118
|
119-
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
119+
= note: this field contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
120120

121121
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
122122
--> $DIR/repr-transparent-non-exhaustive.rs:97:32
123123
|
124124
LL | pub struct T19Flipped(Private, NonExhaustive);
125125
| ^^^^^^^^^^^^^
126126
|
127-
= 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.
127+
= 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.
128128

129129
error: aborting due to 16 previous errors
130130

tests/ui/repr/repr-transparent-repr-c.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha
44
LL | pub struct T5(Sized, ReprC1Zst);
55
| ^^^^^^^^^
66
|
7-
= note: this struct contains `ReprC1Zst`, which is marked with `#[repr(C)]`, and makes it not a breaking change to become non-zero-sized in the future.
7+
= 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.
88

99
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
1010
--> $DIR/repr-transparent-repr-c.rs:22:15
1111
|
1212
LL | pub struct T6(ReprC1Zst, Sized);
1313
| ^^^^^^^^^
1414
|
15-
= note: this struct contains `ReprC1Zst`, which is marked with `#[repr(C)]`, and makes it not a breaking change to become non-zero-sized in the future.
15+
= 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.
1616

1717
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
1818
--> $DIR/repr-transparent-repr-c.rs:26:15
1919
|
2020
LL | pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type
2121
| ^^
2222
|
23-
= note: this struct contains `ReprC1Zst`, which is marked with `#[repr(C)]`, and makes it not a breaking change to become non-zero-sized in the future.
23+
= 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.
2424

2525
error: aborting due to 3 previous errors
2626

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![feature(never_type)]
2+
#![deny(repr_transparent_external_private_fields)]
3+
4+
enum Void {}
5+
6+
pub type Sized = i32;
7+
8+
#[repr(transparent)]
9+
pub struct T1(!);
10+
#[repr(transparent)]
11+
pub struct T2((), Void);
12+
#[repr(transparent)]
13+
pub struct T3(!, ());
14+
15+
#[repr(transparent)]
16+
pub struct T5(Sized, Void);
17+
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
18+
19+
#[repr(transparent)]
20+
pub struct T6(!, Sized);
21+
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
22+
23+
fn main() {}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
2+
--> $DIR/repr-transparent-uninhabited.rs:16:22
3+
|
4+
LL | pub struct T5(Sized, Void);
5+
| ^^^^
6+
|
7+
= note: this field contains `Void`, which is not (publicly) inhabited, and makes it not a breaking change to become non-zero-sized in the future.
8+
9+
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
10+
--> $DIR/repr-transparent-uninhabited.rs:20:15
11+
|
12+
LL | pub struct T6(!, Sized);
13+
| ^
14+
|
15+
= note: this field contains `!`, which is not (publicly) inhabited, and makes it not a breaking change to become non-zero-sized in the future.
16+
17+
error: aborting due to 2 previous errors
18+

0 commit comments

Comments
 (0)