Skip to content

Commit 1bbae50

Browse files
committedApr 19, 2022
mark payload fields of ScalarPair enums as Scalar::Union when they're not always initialized
1 parent 311e268 commit 1bbae50

File tree

3 files changed

+828
-16
lines changed

3 files changed

+828
-16
lines changed
 

‎compiler/rustc_middle/src/ty/layout.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,21 +1120,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
11201120
match st[i].abi() {
11211121
Abi::Scalar(_) => Abi::Scalar(niche_scalar),
11221122
Abi::ScalarPair(first, second) => {
1123-
// We need to use scalar_unit to reset the
1124-
// valid range to the maximal one for that
1125-
// primitive, because only the niche is
1126-
// guaranteed to be initialised, not the
1127-
// other primitive.
1123+
// Only the niche is guaranteed to be initialised,
1124+
// so use union layout for the other primitive.
11281125
if offset.bytes() == 0 {
1129-
Abi::ScalarPair(
1130-
niche_scalar,
1131-
scalar_unit(second.primitive()),
1132-
)
1126+
Abi::ScalarPair(niche_scalar, second.to_union())
11331127
} else {
1134-
Abi::ScalarPair(
1135-
scalar_unit(first.primitive()),
1136-
niche_scalar,
1137-
)
1128+
Abi::ScalarPair(first.to_union(), niche_scalar)
11381129
}
11391130
}
11401131
_ => Abi::Aggregate { sized: true },
@@ -1329,22 +1320,30 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13291320
} else {
13301321
// Try to use a ScalarPair for all tagged enums.
13311322
let mut common_prim = None;
1323+
let mut common_prim_initialized_in_all_variants = true;
13321324
for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) {
13331325
let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
13341326
bug!();
13351327
};
13361328
let mut fields =
13371329
iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
13381330
let (field, offset) = match (fields.next(), fields.next()) {
1339-
(None, None) => continue,
1331+
(None, None) => {
1332+
common_prim_initialized_in_all_variants = false;
1333+
continue;
1334+
}
13401335
(Some(pair), None) => pair,
13411336
_ => {
13421337
common_prim = None;
13431338
break;
13441339
}
13451340
};
13461341
let prim = match field.abi {
1347-
Abi::Scalar(scalar) => scalar.primitive(),
1342+
Abi::Scalar(scalar) => {
1343+
common_prim_initialized_in_all_variants &=
1344+
matches!(scalar, Scalar::Initialized { .. });
1345+
scalar.primitive()
1346+
}
13481347
_ => {
13491348
common_prim = None;
13501349
break;
@@ -1364,7 +1363,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13641363
}
13651364
}
13661365
if let Some((prim, offset)) = common_prim {
1367-
let pair = self.scalar_pair(tag, scalar_unit(prim));
1366+
let prim_scalar = if common_prim_initialized_in_all_variants {
1367+
scalar_unit(prim)
1368+
} else {
1369+
// Common prim might be uninit.
1370+
Scalar::Union { value: prim }
1371+
};
1372+
let pair = self.scalar_pair(tag, prim_scalar);
13681373
let pair_offsets = match pair.fields {
13691374
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
13701375
assert_eq!(memory_index, &[0, 1]);
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#![crate_type = "lib"]
2+
#![feature(rustc_attrs)]
3+
4+
use std::mem::MaybeUninit;
5+
6+
enum HasNiche {
7+
A,
8+
B,
9+
C,
10+
}
11+
12+
// This should result in ScalarPair(Initialized, Union),
13+
// since the u8 payload will be uninit for `None`.
14+
#[rustc_layout(debug)]
15+
pub enum MissingPayloadField { //~ ERROR: layout_of
16+
Some(u8),
17+
None
18+
}
19+
20+
// This should result in ScalarPair(Initialized, Initialized),
21+
// since the u8 field is present in all variants,
22+
// and hence will always be initialized.
23+
#[rustc_layout(debug)]
24+
pub enum CommonPayloadField { //~ ERROR: layout_of
25+
A(u8),
26+
B(u8),
27+
}
28+
29+
// This should result in ScalarPair(Initialized, Union),
30+
// since, though a u8-sized field is present in all variants, it might be uninit.
31+
#[rustc_layout(debug)]
32+
pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
33+
A(u8),
34+
B(MaybeUninit<u8>),
35+
}
36+
37+
// This should result in ScalarPair(Initialized, Union),
38+
// since only the niche field (used for the tag) is guaranteed to be initialized.
39+
#[rustc_layout(debug)]
40+
pub enum NicheFirst { //~ ERROR: layout_of
41+
A(HasNiche, u8),
42+
B,
43+
C
44+
}
45+
46+
// This should result in ScalarPair(Union, Initialized),
47+
// since only the niche field (used for the tag) is guaranteed to be initialized.
48+
#[rustc_layout(debug)]
49+
pub enum NicheSecond { //~ ERROR: layout_of
50+
A(u8, HasNiche),
51+
B,
52+
C,
53+
}
Lines changed: 754 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,754 @@
1+
error: layout_of(MissingPayloadField) = Layout {
2+
fields: Arbitrary {
3+
offsets: [
4+
Size {
5+
raw: 0,
6+
},
7+
],
8+
memory_index: [
9+
0,
10+
],
11+
},
12+
variants: Multiple {
13+
tag: Initialized {
14+
value: Int(
15+
I8,
16+
false,
17+
),
18+
valid_range: 0..=1,
19+
},
20+
tag_encoding: Direct,
21+
tag_field: 0,
22+
variants: [
23+
Layout {
24+
fields: Arbitrary {
25+
offsets: [
26+
Size {
27+
raw: 1,
28+
},
29+
],
30+
memory_index: [
31+
0,
32+
],
33+
},
34+
variants: Single {
35+
index: 0,
36+
},
37+
abi: Aggregate {
38+
sized: true,
39+
},
40+
largest_niche: None,
41+
align: AbiAndPrefAlign {
42+
abi: Align {
43+
pow2: 0,
44+
},
45+
pref: Align {
46+
pow2: 3,
47+
},
48+
},
49+
size: Size {
50+
raw: 2,
51+
},
52+
},
53+
Layout {
54+
fields: Arbitrary {
55+
offsets: [],
56+
memory_index: [],
57+
},
58+
variants: Single {
59+
index: 1,
60+
},
61+
abi: Aggregate {
62+
sized: true,
63+
},
64+
largest_niche: None,
65+
align: AbiAndPrefAlign {
66+
abi: Align {
67+
pow2: 0,
68+
},
69+
pref: Align {
70+
pow2: 3,
71+
},
72+
},
73+
size: Size {
74+
raw: 1,
75+
},
76+
},
77+
],
78+
},
79+
abi: ScalarPair(
80+
Initialized {
81+
value: Int(
82+
I8,
83+
false,
84+
),
85+
valid_range: 0..=1,
86+
},
87+
Union {
88+
value: Int(
89+
I8,
90+
false,
91+
),
92+
},
93+
),
94+
largest_niche: Some(
95+
Niche {
96+
offset: Size {
97+
raw: 0,
98+
},
99+
value: Int(
100+
I8,
101+
false,
102+
),
103+
valid_range: 0..=1,
104+
},
105+
),
106+
align: AbiAndPrefAlign {
107+
abi: Align {
108+
pow2: 0,
109+
},
110+
pref: Align {
111+
pow2: 3,
112+
},
113+
},
114+
size: Size {
115+
raw: 2,
116+
},
117+
}
118+
--> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:15:1
119+
|
120+
LL | / pub enum MissingPayloadField {
121+
LL | | Some(u8),
122+
LL | | None
123+
LL | | }
124+
| |_^
125+
126+
error: layout_of(CommonPayloadField) = Layout {
127+
fields: Arbitrary {
128+
offsets: [
129+
Size {
130+
raw: 0,
131+
},
132+
],
133+
memory_index: [
134+
0,
135+
],
136+
},
137+
variants: Multiple {
138+
tag: Initialized {
139+
value: Int(
140+
I8,
141+
false,
142+
),
143+
valid_range: 0..=1,
144+
},
145+
tag_encoding: Direct,
146+
tag_field: 0,
147+
variants: [
148+
Layout {
149+
fields: Arbitrary {
150+
offsets: [
151+
Size {
152+
raw: 1,
153+
},
154+
],
155+
memory_index: [
156+
0,
157+
],
158+
},
159+
variants: Single {
160+
index: 0,
161+
},
162+
abi: Aggregate {
163+
sized: true,
164+
},
165+
largest_niche: None,
166+
align: AbiAndPrefAlign {
167+
abi: Align {
168+
pow2: 0,
169+
},
170+
pref: Align {
171+
pow2: 3,
172+
},
173+
},
174+
size: Size {
175+
raw: 2,
176+
},
177+
},
178+
Layout {
179+
fields: Arbitrary {
180+
offsets: [
181+
Size {
182+
raw: 1,
183+
},
184+
],
185+
memory_index: [
186+
0,
187+
],
188+
},
189+
variants: Single {
190+
index: 1,
191+
},
192+
abi: Aggregate {
193+
sized: true,
194+
},
195+
largest_niche: None,
196+
align: AbiAndPrefAlign {
197+
abi: Align {
198+
pow2: 0,
199+
},
200+
pref: Align {
201+
pow2: 3,
202+
},
203+
},
204+
size: Size {
205+
raw: 2,
206+
},
207+
},
208+
],
209+
},
210+
abi: ScalarPair(
211+
Initialized {
212+
value: Int(
213+
I8,
214+
false,
215+
),
216+
valid_range: 0..=1,
217+
},
218+
Initialized {
219+
value: Int(
220+
I8,
221+
false,
222+
),
223+
valid_range: 0..=255,
224+
},
225+
),
226+
largest_niche: Some(
227+
Niche {
228+
offset: Size {
229+
raw: 0,
230+
},
231+
value: Int(
232+
I8,
233+
false,
234+
),
235+
valid_range: 0..=1,
236+
},
237+
),
238+
align: AbiAndPrefAlign {
239+
abi: Align {
240+
pow2: 0,
241+
},
242+
pref: Align {
243+
pow2: 3,
244+
},
245+
},
246+
size: Size {
247+
raw: 2,
248+
},
249+
}
250+
--> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:24:1
251+
|
252+
LL | / pub enum CommonPayloadField {
253+
LL | | A(u8),
254+
LL | | B(u8),
255+
LL | | }
256+
| |_^
257+
258+
error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
259+
fields: Arbitrary {
260+
offsets: [
261+
Size {
262+
raw: 0,
263+
},
264+
],
265+
memory_index: [
266+
0,
267+
],
268+
},
269+
variants: Multiple {
270+
tag: Initialized {
271+
value: Int(
272+
I8,
273+
false,
274+
),
275+
valid_range: 0..=1,
276+
},
277+
tag_encoding: Direct,
278+
tag_field: 0,
279+
variants: [
280+
Layout {
281+
fields: Arbitrary {
282+
offsets: [
283+
Size {
284+
raw: 1,
285+
},
286+
],
287+
memory_index: [
288+
0,
289+
],
290+
},
291+
variants: Single {
292+
index: 0,
293+
},
294+
abi: Aggregate {
295+
sized: true,
296+
},
297+
largest_niche: None,
298+
align: AbiAndPrefAlign {
299+
abi: Align {
300+
pow2: 0,
301+
},
302+
pref: Align {
303+
pow2: 3,
304+
},
305+
},
306+
size: Size {
307+
raw: 2,
308+
},
309+
},
310+
Layout {
311+
fields: Arbitrary {
312+
offsets: [
313+
Size {
314+
raw: 1,
315+
},
316+
],
317+
memory_index: [
318+
0,
319+
],
320+
},
321+
variants: Single {
322+
index: 1,
323+
},
324+
abi: Aggregate {
325+
sized: true,
326+
},
327+
largest_niche: None,
328+
align: AbiAndPrefAlign {
329+
abi: Align {
330+
pow2: 0,
331+
},
332+
pref: Align {
333+
pow2: 3,
334+
},
335+
},
336+
size: Size {
337+
raw: 2,
338+
},
339+
},
340+
],
341+
},
342+
abi: ScalarPair(
343+
Initialized {
344+
value: Int(
345+
I8,
346+
false,
347+
),
348+
valid_range: 0..=1,
349+
},
350+
Union {
351+
value: Int(
352+
I8,
353+
false,
354+
),
355+
},
356+
),
357+
largest_niche: Some(
358+
Niche {
359+
offset: Size {
360+
raw: 0,
361+
},
362+
value: Int(
363+
I8,
364+
false,
365+
),
366+
valid_range: 0..=1,
367+
},
368+
),
369+
align: AbiAndPrefAlign {
370+
abi: Align {
371+
pow2: 0,
372+
},
373+
pref: Align {
374+
pow2: 3,
375+
},
376+
},
377+
size: Size {
378+
raw: 2,
379+
},
380+
}
381+
--> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:32:1
382+
|
383+
LL | / pub enum CommonPayloadFieldIsMaybeUninit {
384+
LL | | A(u8),
385+
LL | | B(MaybeUninit<u8>),
386+
LL | | }
387+
| |_^
388+
389+
error: layout_of(NicheFirst) = Layout {
390+
fields: Arbitrary {
391+
offsets: [
392+
Size {
393+
raw: 0,
394+
},
395+
],
396+
memory_index: [
397+
0,
398+
],
399+
},
400+
variants: Multiple {
401+
tag: Initialized {
402+
value: Int(
403+
I8,
404+
false,
405+
),
406+
valid_range: 0..=4,
407+
},
408+
tag_encoding: Niche {
409+
dataful_variant: 0,
410+
niche_variants: 1..=2,
411+
niche_start: 3,
412+
},
413+
tag_field: 0,
414+
variants: [
415+
Layout {
416+
fields: Arbitrary {
417+
offsets: [
418+
Size {
419+
raw: 0,
420+
},
421+
Size {
422+
raw: 1,
423+
},
424+
],
425+
memory_index: [
426+
0,
427+
1,
428+
],
429+
},
430+
variants: Single {
431+
index: 0,
432+
},
433+
abi: ScalarPair(
434+
Initialized {
435+
value: Int(
436+
I8,
437+
false,
438+
),
439+
valid_range: 0..=2,
440+
},
441+
Initialized {
442+
value: Int(
443+
I8,
444+
false,
445+
),
446+
valid_range: 0..=255,
447+
},
448+
),
449+
largest_niche: Some(
450+
Niche {
451+
offset: Size {
452+
raw: 0,
453+
},
454+
value: Int(
455+
I8,
456+
false,
457+
),
458+
valid_range: 0..=2,
459+
},
460+
),
461+
align: AbiAndPrefAlign {
462+
abi: Align {
463+
pow2: 0,
464+
},
465+
pref: Align {
466+
pow2: 3,
467+
},
468+
},
469+
size: Size {
470+
raw: 2,
471+
},
472+
},
473+
Layout {
474+
fields: Arbitrary {
475+
offsets: [],
476+
memory_index: [],
477+
},
478+
variants: Single {
479+
index: 1,
480+
},
481+
abi: Aggregate {
482+
sized: true,
483+
},
484+
largest_niche: None,
485+
align: AbiAndPrefAlign {
486+
abi: Align {
487+
pow2: 0,
488+
},
489+
pref: Align {
490+
pow2: 3,
491+
},
492+
},
493+
size: Size {
494+
raw: 0,
495+
},
496+
},
497+
Layout {
498+
fields: Arbitrary {
499+
offsets: [],
500+
memory_index: [],
501+
},
502+
variants: Single {
503+
index: 2,
504+
},
505+
abi: Aggregate {
506+
sized: true,
507+
},
508+
largest_niche: None,
509+
align: AbiAndPrefAlign {
510+
abi: Align {
511+
pow2: 0,
512+
},
513+
pref: Align {
514+
pow2: 3,
515+
},
516+
},
517+
size: Size {
518+
raw: 0,
519+
},
520+
},
521+
],
522+
},
523+
abi: ScalarPair(
524+
Initialized {
525+
value: Int(
526+
I8,
527+
false,
528+
),
529+
valid_range: 0..=4,
530+
},
531+
Union {
532+
value: Int(
533+
I8,
534+
false,
535+
),
536+
},
537+
),
538+
largest_niche: Some(
539+
Niche {
540+
offset: Size {
541+
raw: 0,
542+
},
543+
value: Int(
544+
I8,
545+
false,
546+
),
547+
valid_range: 0..=4,
548+
},
549+
),
550+
align: AbiAndPrefAlign {
551+
abi: Align {
552+
pow2: 0,
553+
},
554+
pref: Align {
555+
pow2: 3,
556+
},
557+
},
558+
size: Size {
559+
raw: 2,
560+
},
561+
}
562+
--> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:40:1
563+
|
564+
LL | / pub enum NicheFirst {
565+
LL | | A(HasNiche, u8),
566+
LL | | B,
567+
LL | | C
568+
LL | | }
569+
| |_^
570+
571+
error: layout_of(NicheSecond) = Layout {
572+
fields: Arbitrary {
573+
offsets: [
574+
Size {
575+
raw: 1,
576+
},
577+
],
578+
memory_index: [
579+
0,
580+
],
581+
},
582+
variants: Multiple {
583+
tag: Initialized {
584+
value: Int(
585+
I8,
586+
false,
587+
),
588+
valid_range: 0..=4,
589+
},
590+
tag_encoding: Niche {
591+
dataful_variant: 0,
592+
niche_variants: 1..=2,
593+
niche_start: 3,
594+
},
595+
tag_field: 0,
596+
variants: [
597+
Layout {
598+
fields: Arbitrary {
599+
offsets: [
600+
Size {
601+
raw: 0,
602+
},
603+
Size {
604+
raw: 1,
605+
},
606+
],
607+
memory_index: [
608+
0,
609+
1,
610+
],
611+
},
612+
variants: Single {
613+
index: 0,
614+
},
615+
abi: ScalarPair(
616+
Initialized {
617+
value: Int(
618+
I8,
619+
false,
620+
),
621+
valid_range: 0..=255,
622+
},
623+
Initialized {
624+
value: Int(
625+
I8,
626+
false,
627+
),
628+
valid_range: 0..=2,
629+
},
630+
),
631+
largest_niche: Some(
632+
Niche {
633+
offset: Size {
634+
raw: 1,
635+
},
636+
value: Int(
637+
I8,
638+
false,
639+
),
640+
valid_range: 0..=2,
641+
},
642+
),
643+
align: AbiAndPrefAlign {
644+
abi: Align {
645+
pow2: 0,
646+
},
647+
pref: Align {
648+
pow2: 3,
649+
},
650+
},
651+
size: Size {
652+
raw: 2,
653+
},
654+
},
655+
Layout {
656+
fields: Arbitrary {
657+
offsets: [],
658+
memory_index: [],
659+
},
660+
variants: Single {
661+
index: 1,
662+
},
663+
abi: Aggregate {
664+
sized: true,
665+
},
666+
largest_niche: None,
667+
align: AbiAndPrefAlign {
668+
abi: Align {
669+
pow2: 0,
670+
},
671+
pref: Align {
672+
pow2: 3,
673+
},
674+
},
675+
size: Size {
676+
raw: 0,
677+
},
678+
},
679+
Layout {
680+
fields: Arbitrary {
681+
offsets: [],
682+
memory_index: [],
683+
},
684+
variants: Single {
685+
index: 2,
686+
},
687+
abi: Aggregate {
688+
sized: true,
689+
},
690+
largest_niche: None,
691+
align: AbiAndPrefAlign {
692+
abi: Align {
693+
pow2: 0,
694+
},
695+
pref: Align {
696+
pow2: 3,
697+
},
698+
},
699+
size: Size {
700+
raw: 0,
701+
},
702+
},
703+
],
704+
},
705+
abi: ScalarPair(
706+
Union {
707+
value: Int(
708+
I8,
709+
false,
710+
),
711+
},
712+
Initialized {
713+
value: Int(
714+
I8,
715+
false,
716+
),
717+
valid_range: 0..=4,
718+
},
719+
),
720+
largest_niche: Some(
721+
Niche {
722+
offset: Size {
723+
raw: 1,
724+
},
725+
value: Int(
726+
I8,
727+
false,
728+
),
729+
valid_range: 0..=4,
730+
},
731+
),
732+
align: AbiAndPrefAlign {
733+
abi: Align {
734+
pow2: 0,
735+
},
736+
pref: Align {
737+
pow2: 3,
738+
},
739+
},
740+
size: Size {
741+
raw: 2,
742+
},
743+
}
744+
--> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:49:1
745+
|
746+
LL | / pub enum NicheSecond {
747+
LL | | A(u8, HasNiche),
748+
LL | | B,
749+
LL | | C,
750+
LL | | }
751+
| |_^
752+
753+
error: aborting due to 5 previous errors
754+

0 commit comments

Comments
 (0)
Please sign in to comment.