@@ -197,109 +197,37 @@ pub trait LayoutCalculator {
197
197
None => VariantIdx :: new ( 0 ) ,
198
198
} ;
199
199
200
- let is_struct = !is_enum ||
201
- // Only one variant is present.
202
- ( present_second. is_none ( ) &&
203
- // Representation optimizations are allowed.
204
- !repr. inhibit_enum_layout_opt ( ) ) ;
205
- if is_struct {
206
- // Struct, or univariant enum equivalent to a struct.
207
- // (Typechecking will reject discriminant-sizing attrs.)
208
-
209
- let v = present_first;
210
- let kind = if is_enum || variants[ v] . is_empty ( ) || always_sized {
211
- StructKind :: AlwaysSized
212
- } else {
213
- StructKind :: MaybeUnsized
214
- } ;
215
-
216
- let mut st = self . univariant ( dl, & variants[ v] , repr, kind) ?;
217
- st. variants = Variants :: Single { index : v } ;
218
-
219
- if is_unsafe_cell {
220
- let hide_niches = |scalar : & mut _ | match scalar {
221
- Scalar :: Initialized { value, valid_range } => {
222
- * valid_range = WrappingRange :: full ( value. size ( dl) )
223
- }
224
- // Already doesn't have any niches
225
- Scalar :: Union { .. } => { }
226
- } ;
227
- match & mut st. abi {
228
- Abi :: Uninhabited => { }
229
- Abi :: Scalar ( scalar) => hide_niches ( scalar) ,
230
- Abi :: ScalarPair ( a, b) => {
231
- hide_niches ( a) ;
232
- hide_niches ( b) ;
233
- }
234
- Abi :: Vector { element, count : _ } => hide_niches ( element) ,
235
- Abi :: Aggregate { sized : _ } => { }
236
- }
237
- st. largest_niche = None ;
238
- return Some ( st) ;
239
- }
240
-
241
- let ( start, end) = scalar_valid_range;
242
- match st. abi {
243
- Abi :: Scalar ( ref mut scalar) | Abi :: ScalarPair ( ref mut scalar, _) => {
244
- // Enlarging validity ranges would result in missed
245
- // optimizations, *not* wrongly assuming the inner
246
- // value is valid. e.g. unions already enlarge validity ranges,
247
- // because the values may be uninitialized.
248
- //
249
- // Because of that we only check that the start and end
250
- // of the range is representable with this scalar type.
251
-
252
- let max_value = scalar. size ( dl) . unsigned_int_max ( ) ;
253
- if let Bound :: Included ( start) = start {
254
- // FIXME(eddyb) this might be incorrect - it doesn't
255
- // account for wrap-around (end < start) ranges.
256
- assert ! ( start <= max_value, "{start} > {max_value}" ) ;
257
- scalar. valid_range_mut ( ) . start = start;
258
- }
259
- if let Bound :: Included ( end) = end {
260
- // FIXME(eddyb) this might be incorrect - it doesn't
261
- // account for wrap-around (end < start) ranges.
262
- assert ! ( end <= max_value, "{end} > {max_value}" ) ;
263
- scalar. valid_range_mut ( ) . end = end;
264
- }
265
-
266
- // Update `largest_niche` if we have introduced a larger niche.
267
- let niche = Niche :: from_scalar ( dl, Size :: ZERO , * scalar) ;
268
- if let Some ( niche) = niche {
269
- match st. largest_niche {
270
- Some ( largest_niche) => {
271
- // Replace the existing niche even if they're equal,
272
- // because this one is at a lower offset.
273
- if largest_niche. available ( dl) <= niche. available ( dl) {
274
- st. largest_niche = Some ( niche) ;
275
- }
276
- }
277
- None => st. largest_niche = Some ( niche) ,
278
- }
279
- }
280
- }
281
- _ => assert ! (
282
- start == Bound :: Unbounded && end == Bound :: Unbounded ,
283
- "nonscalar layout for layout_scalar_valid_range type: {st:#?}" ,
284
- ) ,
285
- }
286
-
287
- return Some ( st) ;
200
+ // take the struct path if it is an actual struct
201
+ if !is_enum ||
202
+ // or for optimizing univariant enums
203
+ ( present_second. is_none ( ) && !repr. inhibit_enum_layout_opt ( ) )
204
+ {
205
+ layout_of_struct (
206
+ self ,
207
+ repr,
208
+ variants,
209
+ is_enum,
210
+ is_unsafe_cell,
211
+ scalar_valid_range,
212
+ always_sized,
213
+ dl,
214
+ present_first,
215
+ )
216
+ } else {
217
+ // At this point, we have handled all unions and
218
+ // structs. (We have also handled univariant enums
219
+ // that allow representation optimization.)
220
+ assert ! ( is_enum) ;
221
+ layout_of_enum (
222
+ self ,
223
+ repr,
224
+ variants,
225
+ discr_range_of_repr,
226
+ discriminants,
227
+ dont_niche_optimize_enum,
228
+ dl,
229
+ )
288
230
}
289
-
290
- // At this point, we have handled all unions and
291
- // structs. (We have also handled univariant enums
292
- // that allow representation optimization.)
293
- assert ! ( is_enum) ;
294
- layout_of_enum (
295
- self ,
296
- repr,
297
- variants,
298
- discr_range_of_repr,
299
- discriminants,
300
- dont_niche_optimize_enum,
301
- dl,
302
- )
303
231
}
304
232
305
233
fn layout_of_union <
@@ -407,6 +335,106 @@ pub trait LayoutCalculator {
407
335
}
408
336
}
409
337
338
+ /// single-variant enums are just structs, if you think about it
339
+ fn layout_of_struct < ' a , LC , FieldIdx : Idx , VariantIdx : Idx , F > (
340
+ layout_calc : & LC ,
341
+ repr : & ReprOptions ,
342
+ variants : & IndexSlice < VariantIdx , IndexVec < FieldIdx , F > > ,
343
+ is_enum : bool ,
344
+ is_unsafe_cell : bool ,
345
+ scalar_valid_range : ( Bound < u128 > , Bound < u128 > ) ,
346
+ always_sized : bool ,
347
+ dl : & TargetDataLayout ,
348
+ present_first : VariantIdx ,
349
+ ) -> Option < LayoutS < FieldIdx , VariantIdx > >
350
+ where
351
+ LC : LayoutCalculator + ?Sized ,
352
+ F : Deref < Target = & ' a LayoutS < FieldIdx , VariantIdx > > + fmt:: Debug ,
353
+ {
354
+ // Struct, or univariant enum equivalent to a struct.
355
+ // (Typechecking will reject discriminant-sizing attrs.)
356
+
357
+ let v = present_first;
358
+ let kind = if is_enum || variants[ v] . is_empty ( ) || always_sized {
359
+ StructKind :: AlwaysSized
360
+ } else {
361
+ StructKind :: MaybeUnsized
362
+ } ;
363
+
364
+ let mut st = layout_calc. univariant ( dl, & variants[ v] , repr, kind) ?;
365
+ st. variants = Variants :: Single { index : v } ;
366
+
367
+ if is_unsafe_cell {
368
+ let hide_niches = |scalar : & mut _ | match scalar {
369
+ Scalar :: Initialized { value, valid_range } => {
370
+ * valid_range = WrappingRange :: full ( value. size ( dl) )
371
+ }
372
+ // Already doesn't have any niches
373
+ Scalar :: Union { .. } => { }
374
+ } ;
375
+ match & mut st. abi {
376
+ Abi :: Uninhabited => { }
377
+ Abi :: Scalar ( scalar) => hide_niches ( scalar) ,
378
+ Abi :: ScalarPair ( a, b) => {
379
+ hide_niches ( a) ;
380
+ hide_niches ( b) ;
381
+ }
382
+ Abi :: Vector { element, count : _ } => hide_niches ( element) ,
383
+ Abi :: Aggregate { sized : _ } => { }
384
+ }
385
+ st. largest_niche = None ;
386
+ return Some ( st) ;
387
+ }
388
+
389
+ let ( start, end) = scalar_valid_range;
390
+ match st. abi {
391
+ Abi :: Scalar ( ref mut scalar) | Abi :: ScalarPair ( ref mut scalar, _) => {
392
+ // Enlarging validity ranges would result in missed
393
+ // optimizations, *not* wrongly assuming the inner
394
+ // value is valid. e.g. unions already enlarge validity ranges,
395
+ // because the values may be uninitialized.
396
+ //
397
+ // Because of that we only check that the start and end
398
+ // of the range is representable with this scalar type.
399
+
400
+ let max_value = scalar. size ( dl) . unsigned_int_max ( ) ;
401
+ if let Bound :: Included ( start) = start {
402
+ // FIXME(eddyb) this might be incorrect - it doesn't
403
+ // account for wrap-around (end < start) ranges.
404
+ assert ! ( start <= max_value, "{start} > {max_value}" ) ;
405
+ scalar. valid_range_mut ( ) . start = start;
406
+ }
407
+ if let Bound :: Included ( end) = end {
408
+ // FIXME(eddyb) this might be incorrect - it doesn't
409
+ // account for wrap-around (end < start) ranges.
410
+ assert ! ( end <= max_value, "{end} > {max_value}" ) ;
411
+ scalar. valid_range_mut ( ) . end = end;
412
+ }
413
+
414
+ // Update `largest_niche` if we have introduced a larger niche.
415
+ let niche = Niche :: from_scalar ( dl, Size :: ZERO , * scalar) ;
416
+ if let Some ( niche) = niche {
417
+ match st. largest_niche {
418
+ Some ( largest_niche) => {
419
+ // Replace the existing niche even if they're equal,
420
+ // because this one is at a lower offset.
421
+ if largest_niche. available ( dl) <= niche. available ( dl) {
422
+ st. largest_niche = Some ( niche) ;
423
+ }
424
+ }
425
+ None => st. largest_niche = Some ( niche) ,
426
+ }
427
+ }
428
+ }
429
+ _ => assert ! (
430
+ start == Bound :: Unbounded && end == Bound :: Unbounded ,
431
+ "nonscalar layout for layout_scalar_valid_range type: {st:#?}" ,
432
+ ) ,
433
+ }
434
+
435
+ Some ( st)
436
+ }
437
+
410
438
fn layout_of_enum < ' a , LC , FieldIdx : Idx , VariantIdx : Idx , F > (
411
439
layout_calc : & LC ,
412
440
repr : & ReprOptions ,
0 commit comments