Skip to content

Commit 4a7e152

Browse files
Rollup merge of #147514 - RalfJung:transparent-nonexhaustive-normalize, r=lcnr
repr_transparent_external_private_fields: normalize types during traversal Determining whether a type is a 1-ZST will internally do full normalization, so we better do the same when scanning for non-exhaustive types. r? ``@lcnr``
2 parents 3545698 + 3452415 commit 4a7e152

File tree

3 files changed

+49
-22
lines changed

3 files changed

+49
-22
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,11 +1510,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15101510
return;
15111511
}
15121512

1513+
let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did());
15131514
// For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with
15141515
// "known" respecting #[non_exhaustive] attributes.
15151516
let field_infos = adt.all_fields().map(|field| {
15161517
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
1517-
let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did);
15181518
let layout = tcx.layout_of(typing_env.as_query_input(ty));
15191519
// We are currently checking the type this field came from, so it must be local
15201520
let span = tcx.hir_span_if_local(field.did).unwrap();
@@ -1526,11 +1526,16 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15261526

15271527
fn check_non_exhaustive<'tcx>(
15281528
tcx: TyCtxt<'tcx>,
1529+
typing_env: ty::TypingEnv<'tcx>,
15291530
t: Ty<'tcx>,
15301531
) -> ControlFlow<(&'static str, DefId, GenericArgsRef<'tcx>, bool)> {
1532+
// We can encounter projections during traversal, so ensure the type is normalized.
1533+
let t = tcx.try_normalize_erasing_regions(typing_env, t).unwrap_or(t);
15311534
match t.kind() {
1532-
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
1533-
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
1535+
ty::Tuple(list) => {
1536+
list.iter().try_for_each(|t| check_non_exhaustive(tcx, typing_env, t))
1537+
}
1538+
ty::Array(ty, _) => check_non_exhaustive(tcx, typing_env, *ty),
15341539
ty::Adt(def, args) => {
15351540
if !def.did().is_local()
15361541
&& !find_attr!(
@@ -1555,13 +1560,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15551560
}
15561561
def.all_fields()
15571562
.map(|field| field.ty(tcx, args))
1558-
.try_for_each(|t| check_non_exhaustive(tcx, t))
1563+
.try_for_each(|t| check_non_exhaustive(tcx, typing_env, t))
15591564
}
15601565
_ => ControlFlow::Continue(()),
15611566
}
15621567
}
15631568

1564-
(span, trivial, check_non_exhaustive(tcx, ty).break_value())
1569+
(span, trivial, check_non_exhaustive(tcx, typing_env, ty).break_value())
15651570
});
15661571

15671572
let non_trivial_fields = field_infos

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ pub struct InternalIndirection<T> {
2424

2525
pub type Sized = i32;
2626

27+
pub trait Trait {
28+
type Assoc;
29+
}
30+
impl Trait for i32 {
31+
type Assoc = NonExhaustive;
32+
}
33+
2734
#[repr(transparent)]
2835
pub struct T1(Sized, InternalPrivate);
2936
#[repr(transparent)]
@@ -43,6 +50,11 @@ pub struct T6(Sized, NonExhaustive);
4350
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
4451
//~| WARN this was previously accepted by the compiler
4552

53+
#[repr(transparent)]
54+
pub struct T6a(Sized, <i32 as Trait>::Assoc); // normalizes to `NonExhaustive`
55+
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
56+
//~| WARN this was previously accepted by the compiler
57+
4658
#[repr(transparent)]
4759
pub struct T7(Sized, NonExhaustiveEnum);
4860
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types

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

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
2-
--> $DIR/repr-transparent-non-exhaustive.rs:37:22
2+
--> $DIR/repr-transparent-non-exhaustive.rs:44:22
33
|
44
LL | pub struct T5(Sized, Private);
55
| ^^^^^^^
@@ -14,7 +14,7 @@ LL | #![deny(repr_transparent_external_private_fields)]
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1515

1616
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
17-
--> $DIR/repr-transparent-non-exhaustive.rs:42:22
17+
--> $DIR/repr-transparent-non-exhaustive.rs:49:22
1818
|
1919
LL | pub struct T6(Sized, NonExhaustive);
2020
| ^^^^^^^^^^^^^
@@ -24,7 +24,17 @@ LL | pub struct T6(Sized, NonExhaustive);
2424
= 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.
2525

2626
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
27-
--> $DIR/repr-transparent-non-exhaustive.rs:47:22
27+
--> $DIR/repr-transparent-non-exhaustive.rs:54:23
28+
|
29+
LL | pub struct T6a(Sized, <i32 as Trait>::Assoc); // normalizes to `NonExhaustive`
30+
| ^^^^^^^^^^^^^^^^^^^^^
31+
|
32+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
33+
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
34+
= 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.
35+
36+
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
37+
--> $DIR/repr-transparent-non-exhaustive.rs:59:22
2838
|
2939
LL | pub struct T7(Sized, NonExhaustiveEnum);
3040
| ^^^^^^^^^^^^^^^^^
@@ -34,7 +44,7 @@ LL | pub struct T7(Sized, NonExhaustiveEnum);
3444
= 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.
3545

3646
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
37-
--> $DIR/repr-transparent-non-exhaustive.rs:52:22
47+
--> $DIR/repr-transparent-non-exhaustive.rs:64:22
3848
|
3949
LL | pub struct T8(Sized, NonExhaustiveVariant);
4050
| ^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +54,7 @@ LL | pub struct T8(Sized, NonExhaustiveVariant);
4454
= 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.
4555

4656
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
47-
--> $DIR/repr-transparent-non-exhaustive.rs:57:22
57+
--> $DIR/repr-transparent-non-exhaustive.rs:69:22
4858
|
4959
LL | pub struct T9(Sized, InternalIndirection<Private>);
5060
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -54,7 +64,7 @@ LL | pub struct T9(Sized, InternalIndirection<Private>);
5464
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
5565

5666
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
57-
--> $DIR/repr-transparent-non-exhaustive.rs:62:23
67+
--> $DIR/repr-transparent-non-exhaustive.rs:74:23
5868
|
5969
LL | pub struct T10(Sized, InternalIndirection<NonExhaustive>);
6070
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +74,7 @@ LL | pub struct T10(Sized, InternalIndirection<NonExhaustive>);
6474
= 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.
6575

6676
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
67-
--> $DIR/repr-transparent-non-exhaustive.rs:67:23
77+
--> $DIR/repr-transparent-non-exhaustive.rs:79:23
6878
|
6979
LL | pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
7080
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -74,7 +84,7 @@ LL | pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
7484
= 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.
7585

7686
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
77-
--> $DIR/repr-transparent-non-exhaustive.rs:72:23
87+
--> $DIR/repr-transparent-non-exhaustive.rs:84:23
7888
|
7989
LL | pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
8090
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -84,7 +94,7 @@ LL | pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
8494
= 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.
8595

8696
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
87-
--> $DIR/repr-transparent-non-exhaustive.rs:77:23
97+
--> $DIR/repr-transparent-non-exhaustive.rs:89:23
8898
|
8999
LL | pub struct T13(Sized, ExternalIndirection<Private>);
90100
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +104,7 @@ LL | pub struct T13(Sized, ExternalIndirection<Private>);
94104
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
95105

96106
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
97-
--> $DIR/repr-transparent-non-exhaustive.rs:82:23
107+
--> $DIR/repr-transparent-non-exhaustive.rs:94:23
98108
|
99109
LL | pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
100110
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +114,7 @@ LL | pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
104114
= 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.
105115

106116
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
107-
--> $DIR/repr-transparent-non-exhaustive.rs:87:23
117+
--> $DIR/repr-transparent-non-exhaustive.rs:99:23
108118
|
109119
LL | pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
110120
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -114,7 +124,7 @@ LL | pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
114124
= 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.
115125

116126
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
117-
--> $DIR/repr-transparent-non-exhaustive.rs:92:23
127+
--> $DIR/repr-transparent-non-exhaustive.rs:104:23
118128
|
119129
LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
120130
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -124,7 +134,7 @@ LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
124134
= 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.
125135

126136
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
127-
--> $DIR/repr-transparent-non-exhaustive.rs:97:16
137+
--> $DIR/repr-transparent-non-exhaustive.rs:109:16
128138
|
129139
LL | pub struct T17(NonExhaustive, Sized);
130140
| ^^^^^^^^^^^^^
@@ -134,7 +144,7 @@ LL | pub struct T17(NonExhaustive, Sized);
134144
= 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.
135145

136146
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
137-
--> $DIR/repr-transparent-non-exhaustive.rs:102:31
147+
--> $DIR/repr-transparent-non-exhaustive.rs:114:31
138148
|
139149
LL | pub struct T18(NonExhaustive, NonExhaustive);
140150
| ^^^^^^^^^^^^^
@@ -144,7 +154,7 @@ LL | pub struct T18(NonExhaustive, NonExhaustive);
144154
= 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.
145155

146156
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
147-
--> $DIR/repr-transparent-non-exhaustive.rs:107:31
157+
--> $DIR/repr-transparent-non-exhaustive.rs:119:31
148158
|
149159
LL | pub struct T19(NonExhaustive, Private);
150160
| ^^^^^^^
@@ -154,7 +164,7 @@ LL | pub struct T19(NonExhaustive, Private);
154164
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
155165

156166
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
157-
--> $DIR/repr-transparent-non-exhaustive.rs:112:32
167+
--> $DIR/repr-transparent-non-exhaustive.rs:124:32
158168
|
159169
LL | pub struct T19Flipped(Private, NonExhaustive);
160170
| ^^^^^^^^^^^^^
@@ -163,5 +173,5 @@ LL | pub struct T19Flipped(Private, NonExhaustive);
163173
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
164174
= 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.
165175

166-
error: aborting due to 16 previous errors
176+
error: aborting due to 17 previous errors
167177

0 commit comments

Comments
 (0)