@@ -91,6 +91,8 @@ pub enum Repr {
91
91
* field is known to be nonnull due to its type; if that field is null, then
92
92
* it represents the other case, which is inhabited by at most one value
93
93
* (and all other fields are undefined/unused).
94
+ * If the case with the nullable pointer has a single field then we don't
95
+ * wrap it in a struct and instead just deal with it directly as a pointer.
94
96
*
95
97
* For example, `std::option::Option` instantiated at a safe pointer type
96
98
* is represented such that `None` is a null pointer and `Some` is the
@@ -413,8 +415,11 @@ pub fn incomplete_type_of(cx: &CrateContext, r: &Repr, name: &str) -> Type {
413
415
}
414
416
pub fn finish_type_of ( cx : & CrateContext , r : & Repr , llty : & mut Type ) {
415
417
match * r {
416
- CEnum ( ..) | General ( ..) => { }
417
- Univariant ( ref st, _) | NullablePointer { nonnull : ref st, .. } =>
418
+ CEnum ( ..) | General ( ..) => {
419
+ }
420
+ NullablePointer { nonnull : ref st, .. } if st. fields . len ( ) == 1 => {
421
+ }
422
+ Univariant ( ref st, _) | NullablePointer { nonnull : ref st, .. } =>
418
423
llty. set_struct_body ( struct_llfields ( cx, st, false ) . as_slice ( ) ,
419
424
st. packed )
420
425
}
@@ -423,7 +428,14 @@ pub fn finish_type_of(cx: &CrateContext, r: &Repr, llty: &mut Type) {
423
428
fn generic_type_of ( cx : & CrateContext , r : & Repr , name : Option < & str > , sizing : bool ) -> Type {
424
429
match * r {
425
430
CEnum ( ity, _, _) => ll_inttype ( cx, ity) ,
426
- Univariant ( ref st, _) | NullablePointer { nonnull : ref st, .. } => {
431
+ NullablePointer { nonnull : ref st, .. } if st. fields . len ( ) == 1 => {
432
+ if sizing {
433
+ type_of:: sizing_type_of ( cx, * st. fields . get ( 0 ) )
434
+ } else {
435
+ type_of:: type_of ( cx, * st. fields . get ( 0 ) )
436
+ }
437
+ }
438
+ Univariant ( ref st, _) | NullablePointer { nonnull : ref st, .. } => {
427
439
match name {
428
440
None => {
429
441
Type :: struct_ ( cx, struct_llfields ( cx, st, sizing) . as_slice ( ) ,
@@ -498,7 +510,7 @@ pub fn trans_switch(bcx: &Block, r: &Repr, scrutinee: ValueRef)
498
510
CEnum ( ..) | General ( ..) => {
499
511
( _match:: switch, Some ( trans_get_discr ( bcx, r, scrutinee, None ) ) )
500
512
}
501
- NullablePointer { nonnull : ref nonnull, nndiscr, ptrfield, .. } => {
513
+ NullablePointer { nonnull : ref nonnull, nndiscr, ptrfield, .. } => {
502
514
( _match:: switch, Some ( nullable_bitdiscr ( bcx, nonnull, nndiscr, ptrfield, scrutinee) ) )
503
515
}
504
516
Univariant ( ..) => {
@@ -528,7 +540,7 @@ pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Opti
528
540
val = C_u8 ( bcx. ccx ( ) , 0 ) ;
529
541
signed = false ;
530
542
}
531
- NullablePointer { nonnull : ref nonnull, nndiscr, ptrfield, .. } => {
543
+ NullablePointer { nonnull : ref nonnull, nndiscr, ptrfield, .. } => {
532
544
val = nullable_bitdiscr ( bcx, nonnull, nndiscr, ptrfield, scrutinee) ;
533
545
signed = false ;
534
546
}
@@ -541,8 +553,12 @@ pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Opti
541
553
542
554
fn nullable_bitdiscr ( bcx : & Block , nonnull : & Struct , nndiscr : Disr , ptrfield : uint ,
543
555
scrutinee : ValueRef ) -> ValueRef {
556
+ let llptr = if nonnull. fields . len ( ) == 1 {
557
+ Load ( bcx, scrutinee)
558
+ } else {
559
+ Load ( bcx, GEPi ( bcx, scrutinee, [ 0 , ptrfield] ) )
560
+ } ;
544
561
let cmp = if nndiscr == 0 { IntEQ } else { IntNE } ;
545
- let llptr = Load ( bcx, GEPi ( bcx, scrutinee, [ 0 , ptrfield] ) ) ;
546
562
let llptrty = type_of:: type_of ( bcx. ccx ( ) , * nonnull. fields . get ( ptrfield) ) ;
547
563
ICmp ( bcx, cmp, llptr, C_null ( llptrty) )
548
564
}
@@ -590,7 +606,7 @@ pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
590
606
Univariant ( ..) => {
591
607
bcx. ccx ( ) . sess ( ) . bug ( "no cases for univariants or structs" )
592
608
}
593
- NullablePointer { .. } => {
609
+ NullablePointer { .. } => {
594
610
assert ! ( discr == 0 || discr == 1 ) ;
595
611
_match:: single_result ( Result :: new ( bcx, C_i1 ( bcx. ccx ( ) , discr != 0 ) ) )
596
612
}
@@ -621,9 +637,13 @@ pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
621
637
Univariant ( ..) => {
622
638
assert_eq ! ( discr, 0 ) ;
623
639
}
624
- NullablePointer { nonnull : ref nonnull, nndiscr, ptrfield, .. } => {
640
+ NullablePointer { nonnull : ref nonnull, nndiscr, ptrfield, .. } => {
625
641
if discr != nndiscr {
626
- let llptrptr = GEPi ( bcx, val, [ 0 , ptrfield] ) ;
642
+ let llptrptr = if nonnull. fields . len ( ) == 1 {
643
+ val
644
+ } else {
645
+ GEPi ( bcx, val, [ 0 , ptrfield] )
646
+ } ;
627
647
let llptrty = type_of:: type_of ( bcx. ccx ( ) ,
628
648
* nonnull. fields . get ( ptrfield) ) ;
629
649
Store ( bcx, C_null ( llptrty) , llptrptr)
@@ -651,7 +671,7 @@ pub fn num_args(r: &Repr, discr: Disr) -> uint {
651
671
st. fields . len ( ) - ( if dtor { 1 } else { 0 } )
652
672
}
653
673
General ( _, ref cases) => cases. get ( discr as uint ) . fields . len ( ) - 1 ,
654
- NullablePointer { nonnull : ref nonnull, nndiscr,
674
+ NullablePointer { nonnull : ref nonnull, nndiscr,
655
675
nullfields : ref nullfields, .. } => {
656
676
if discr == nndiscr { nonnull. fields . len ( ) } else { nullfields. len ( ) }
657
677
}
@@ -675,10 +695,15 @@ pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
675
695
General ( _, ref cases) => {
676
696
struct_field_ptr ( bcx, cases. get ( discr as uint ) , val, ix + 1 , true )
677
697
}
678
- NullablePointer { nonnull : ref nonnull, nullfields : ref nullfields,
698
+ NullablePointer { nonnull : ref nonnull, nullfields : ref nullfields,
679
699
nndiscr, .. } => {
680
700
if discr == nndiscr {
681
- struct_field_ptr ( bcx, nonnull, val, ix, false )
701
+ if nonnull. fields . len ( ) == 1 {
702
+ assert_eq ! ( ix, 0 ) ;
703
+ val
704
+ } else {
705
+ struct_field_ptr ( bcx, nonnull, val, ix, false )
706
+ }
682
707
} else {
683
708
// The unit-like case might have a nonzero number of unit-like fields.
684
709
// (e.g., Result or Either with () as one side.)
@@ -759,7 +784,15 @@ pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr,
759
784
let contents = build_const_struct ( ccx, st, vals) ;
760
785
C_struct ( ccx, contents. as_slice ( ) , st. packed )
761
786
}
762
- NullablePointer { nonnull : ref nonnull, nndiscr, .. } => {
787
+ NullablePointer { nonnull : ref st, nndiscr, .. } if st. fields . len ( ) == 1 => {
788
+ if discr == nndiscr {
789
+ assert_eq ! ( vals. len( ) , 1 ) ;
790
+ vals[ 0 ]
791
+ } else {
792
+ C_null ( type_of:: sizing_type_of ( ccx, * st. fields . get ( 0 ) ) )
793
+ }
794
+ }
795
+ NullablePointer { nonnull : ref nonnull, nndiscr, .. } => {
763
796
if discr == nndiscr {
764
797
C_struct ( ccx, build_const_struct ( ccx,
765
798
nonnull,
@@ -867,7 +900,15 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
867
900
}
868
901
}
869
902
Univariant ( ..) => 0 ,
870
- NullablePointer { nndiscr, ptrfield, .. } => {
903
+ NullablePointer { nonnull : ref st, nndiscr, .. } if st. fields . len ( ) == 1 => {
904
+ if is_null ( val) {
905
+ /* subtraction as uint is ok because nndiscr is either 0 or 1 */
906
+ ( 1 - nndiscr) as Disr
907
+ } else {
908
+ nndiscr
909
+ }
910
+ }
911
+ NullablePointer { nndiscr, ptrfield, .. } => {
871
912
if is_null ( const_struct_field ( ccx, val, ptrfield) ) {
872
913
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
873
914
( 1 - nndiscr) as Disr
@@ -891,6 +932,10 @@ pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
891
932
CEnum ( ..) => ccx. sess ( ) . bug ( "element access in C-like enum const" ) ,
892
933
Univariant ( ..) => const_struct_field ( ccx, val, ix) ,
893
934
General ( ..) => const_struct_field ( ccx, val, ix + 1 ) ,
935
+ NullablePointer { nonnull : ref st, .. } if st. fields . len ( ) == 1 => {
936
+ assert_eq ! ( ix, 0 ) ;
937
+ val
938
+ }
894
939
NullablePointer { .. } => const_struct_field ( ccx, val, ix)
895
940
}
896
941
}
0 commit comments