@@ -416,7 +416,7 @@ impl Integer {
416416 /// signed discriminant range and #[repr] attribute.
417417 /// N.B.: u64 values above i64::MAX will be treated as signed, but
418418 /// that shouldn't affect anything, other than maybe debuginfo.
419- pub fn repr_discr ( tcx : TyCtxt , ty : Ty , hint : attr:: ReprAttr , min : i64 , max : i64 )
419+ fn repr_discr ( tcx : TyCtxt , ty : Ty , hints : & [ attr:: ReprAttr ] , min : i64 , max : i64 )
420420 -> ( Integer , bool ) {
421421 // Theoretically, negative values could be larger in unsigned representation
422422 // than the unsigned representation of the signed minimum. However, if there
@@ -425,33 +425,44 @@ impl Integer {
425425 let unsigned_fit = Integer :: fit_unsigned ( cmp:: max ( min as u64 , max as u64 ) ) ;
426426 let signed_fit = cmp:: max ( Integer :: fit_signed ( min) , Integer :: fit_signed ( max) ) ;
427427
428- let at_least = match hint {
429- attr:: ReprInt ( ity) => {
430- let discr = Integer :: from_attr ( & tcx. data_layout , ity) ;
431- let fit = if ity. is_signed ( ) { signed_fit } else { unsigned_fit } ;
432- if discr < fit {
433- bug ! ( "Integer::repr_discr: `#[repr]` hint too small for \
434- discriminant range of enum `{}", ty)
428+ let mut min_from_extern = None ;
429+ let min_default = I8 ;
430+
431+ for & r in hints. iter ( ) {
432+ match r {
433+ attr:: ReprInt ( ity) => {
434+ let discr = Integer :: from_attr ( & tcx. data_layout , ity) ;
435+ let fit = if ity. is_signed ( ) { signed_fit } else { unsigned_fit } ;
436+ if discr < fit {
437+ bug ! ( "Integer::repr_discr: `#[repr]` hint too small for \
438+ discriminant range of enum `{}", ty)
439+ }
440+ return ( discr, ity. is_signed ( ) ) ;
435441 }
436- return ( discr, ity. is_signed ( ) ) ;
437- }
438- attr:: ReprExtern => {
439- match & tcx. sess . target . target . arch [ ..] {
440- // WARNING: the ARM EABI has two variants; the one corresponding
441- // to `at_least == I32` appears to be used on Linux and NetBSD,
442- // but some systems may use the variant corresponding to no
443- // lower bound. However, we don't run on those yet...?
444- "arm" => I32 ,
445- _ => I32 ,
442+ attr:: ReprExtern => {
443+ match & tcx. sess . target . target . arch [ ..] {
444+ // WARNING: the ARM EABI has two variants; the one corresponding
445+ // to `at_least == I32` appears to be used on Linux and NetBSD,
446+ // but some systems may use the variant corresponding to no
447+ // lower bound. However, we don't run on those yet...?
448+ "arm" => min_from_extern = Some ( I32 ) ,
449+ _ => min_from_extern = Some ( I32 ) ,
450+ }
451+ }
452+ attr:: ReprAny => { } ,
453+ attr:: ReprPacked => {
454+ bug ! ( "Integer::repr_discr: found #[repr(packed)] on enum `{}" , ty) ;
455+ }
456+ attr:: ReprSimd => {
457+ bug ! ( "Integer::repr_discr: found #[repr(simd)] on enum `{}" , ty) ;
446458 }
447459 }
448- attr:: ReprAny => I8 ,
449- attr:: ReprPacked => {
450- bug ! ( "Integer::repr_discr: found #[repr(packed)] on enum `{}" , ty) ;
451- }
452- attr:: ReprSimd => {
453- bug ! ( "Integer::repr_discr: found #[repr(simd)] on enum `{}" , ty) ;
454- }
460+ }
461+
462+ let at_least = if let Some ( i) = min_from_extern {
463+ i
464+ } else {
465+ min_default
455466 } ;
456467
457468 // If there are no negative values, we can use the unsigned fit.
@@ -536,10 +547,11 @@ enum StructKind {
536547}
537548
538549impl < ' a , ' gcx , ' tcx > Struct {
550+ // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
539551 fn new ( dl : & TargetDataLayout , fields : & Vec < & ' a Layout > ,
540- repr : attr:: ReprAttr , kind : StructKind ,
552+ reprs : & [ attr:: ReprAttr ] , kind : StructKind ,
541553 scapegoat : Ty < ' gcx > ) -> Result < Struct , LayoutError < ' gcx > > {
542- let packed = repr == attr:: ReprPacked ;
554+ let packed = reprs . contains ( & attr:: ReprPacked ) ;
543555 let mut ret = Struct {
544556 align : if packed { dl. i8_align } else { dl. aggregate_align } ,
545557 packed : packed,
@@ -549,23 +561,37 @@ impl<'a, 'gcx, 'tcx> Struct {
549561 min_size : Size :: from_bytes ( 0 ) ,
550562 } ;
551563
552- // 1-member and 2-member structs don't optimize.
564+ if fields. len ( ) == 0 { return Ok ( ret) } ;
565+
566+ // Anything with ReprExtern or ReprPacked doesn't optimize.
567+ // Neither do 1-member and 2-member structs.
553568 // In addition, code in trans assume that 2-element structs can become pairs.
554569 // It's easier to just short-circuit here.
555- let can_optimize_struct = fields. len ( ) > 2 ;
570+ let mut can_optimize = fields. len ( ) > 2 || StructKind :: EnumVariant == kind;
571+ if can_optimize {
572+ // This exhaustive match makes new reprs force the adder to modify this function.
573+ // Otherwise, things can silently break.
574+ // Note the inversion, return true to stop matching.
575+ can_optimize = !reprs. iter ( ) . any ( |r| {
576+ match * r {
577+ attr:: ReprAny => false ,
578+ attr:: ReprInt ( _) => false ,
579+ attr:: ReprExtern => true ,
580+ attr:: ReprPacked => true ,
581+ attr:: ReprSimd => bug ! ( "Simd vectors should be represented as a layout::Vector" )
582+ }
583+ } ) ;
584+ }
556585
557- let ( optimize, sort_ascending) = match ( repr , kind) {
558- ( attr :: ReprAny , StructKind :: AlwaysSizedUnivariant ) => ( can_optimize_struct , false ) ,
559- ( attr :: ReprAny , StructKind :: MaybeUnsizedUnivariant ) => ( can_optimize_struct , true ) ,
560- ( attr :: ReprAny , StructKind :: EnumVariant ) => {
586+ let ( optimize, sort_ascending) = match kind {
587+ StructKind :: AlwaysSizedUnivariant => ( can_optimize , false ) ,
588+ StructKind :: MaybeUnsizedUnivariant => ( can_optimize , true ) ,
589+ StructKind :: EnumVariant => {
561590 assert ! ( fields. len( ) >= 1 , "Enum variants must have discriminants." ) ;
562- ( true , fields[ 0 ] . size ( dl) . bytes ( ) == 1 )
591+ ( can_optimize , fields[ 0 ] . size ( dl) . bytes ( ) == 1 )
563592 }
564- _ => ( false , false )
565593 } ;
566594
567- if fields. len ( ) == 0 { return Ok ( ret) } ;
568-
569595 ret. offsets = vec ! [ Size :: from_bytes( 0 ) ; fields. len( ) ] ;
570596 let mut inverse_memory_index: Vec < u32 > = ( 0 ..fields. len ( ) as u32 ) . collect ( ) ;
571597
@@ -590,6 +616,7 @@ impl<'a, 'gcx, 'tcx> Struct {
590616 }
591617 }
592618
619+ // inverse_memory_index holds field indices by increasing memory offset.
593620 // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
594621 // We now write field offsets to the corresponding offset slot;
595622 // field 5 with offset 0 puts 0 in offsets[5].
@@ -1021,7 +1048,7 @@ impl<'a, 'gcx, 'tcx> Layout {
10211048
10221049 // The never type.
10231050 ty:: TyNever => Univariant {
1024- variant : Struct :: new ( dl, & vec ! [ ] , attr :: ReprAny ,
1051+ variant : Struct :: new ( dl, & vec ! [ ] , & [ ] ,
10251052 StructKind :: AlwaysSizedUnivariant , ty) ?,
10261053 non_zero : false
10271054 } ,
@@ -1076,12 +1103,12 @@ impl<'a, 'gcx, 'tcx> Layout {
10761103 ty:: TyFnDef ( ..) => {
10771104 Univariant {
10781105 variant : Struct :: new ( dl, & vec ! [ ] ,
1079- attr :: ReprAny , StructKind :: AlwaysSizedUnivariant , ty) ?,
1106+ & [ ] , StructKind :: AlwaysSizedUnivariant , ty) ?,
10801107 non_zero : false
10811108 }
10821109 }
10831110 ty:: TyDynamic ( _) => {
1084- let mut unit = Struct :: new ( dl, & vec ! [ ] , attr :: ReprAny ,
1111+ let mut unit = Struct :: new ( dl, & vec ! [ ] , & [ ] ,
10851112 StructKind :: AlwaysSizedUnivariant , ty) ?;
10861113 unit. sized = false ;
10871114 Univariant { variant : unit, non_zero : false }
@@ -1093,7 +1120,7 @@ impl<'a, 'gcx, 'tcx> Layout {
10931120 let st = Struct :: new ( dl,
10941121 & tys. map ( |ty| ty. layout ( infcx) )
10951122 . collect :: < Result < Vec < _ > , _ > > ( ) ?,
1096- attr :: ReprAny ,
1123+ & [ ] ,
10971124 StructKind :: AlwaysSizedUnivariant , ty) ?;
10981125 Univariant { variant : st, non_zero : false }
10991126 }
@@ -1104,7 +1131,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11041131 let st = Struct :: new ( dl,
11051132 & tys. iter ( ) . map ( |ty| ty. layout ( infcx) )
11061133 . collect :: < Result < Vec < _ > , _ > > ( ) ?,
1107- attr :: ReprAny , StructKind :: AlwaysSizedUnivariant , ty) ?;
1134+ & [ ] , StructKind :: AlwaysSizedUnivariant , ty) ?;
11081135 Univariant { variant : st, non_zero : false }
11091136 }
11101137
@@ -1128,17 +1155,16 @@ impl<'a, 'gcx, 'tcx> Layout {
11281155
11291156 // ADTs.
11301157 ty:: TyAdt ( def, substs) => {
1131- let hint = * tcx. lookup_repr_hints ( def. did ) . get ( 0 )
1132- . unwrap_or ( & attr:: ReprAny ) ;
1158+ let hints = & tcx. lookup_repr_hints ( def. did ) [ ..] ;
11331159
11341160 if def. variants . is_empty ( ) {
11351161 // Uninhabitable; represent as unit
11361162 // (Typechecking will reject discriminant-sizing attrs.)
1137- assert_eq ! ( hint , attr :: ReprAny ) ;
1163+ assert_eq ! ( hints . len ( ) , 0 ) ;
11381164
11391165 return success ( Univariant {
11401166 variant : Struct :: new ( dl, & vec ! [ ] ,
1141- hint , StructKind :: AlwaysSizedUnivariant , ty) ?,
1167+ & hints [ .. ] , StructKind :: AlwaysSizedUnivariant , ty) ?,
11421168 non_zero : false
11431169 } ) ;
11441170 }
@@ -1153,7 +1179,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11531179 if x > max { max = x; }
11541180 }
11551181
1156- let ( discr, signed) = Integer :: repr_discr ( tcx, ty, hint , min, max) ;
1182+ let ( discr, signed) = Integer :: repr_discr ( tcx, ty, & hints [ .. ] , min, max) ;
11571183 return success ( CEnum {
11581184 discr : discr,
11591185 signed : signed,
@@ -1163,7 +1189,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11631189 } ) ;
11641190 }
11651191
1166- if !def. is_enum ( ) || def. variants . len ( ) == 1 && hint == attr :: ReprAny {
1192+ if !def. is_enum ( ) || def. variants . len ( ) == 1 && hints . len ( ) == 0 {
11671193 // Struct, or union, or univariant enum equivalent to a struct.
11681194 // (Typechecking will reject discriminant-sizing attrs.)
11691195
@@ -1190,7 +1216,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11901216 un. extend ( dl, fields. iter ( ) . map ( |& f| Ok ( f) ) , ty) ?;
11911217 UntaggedUnion { variants : un }
11921218 } else {
1193- let st = Struct :: new ( dl, & fields, hint ,
1219+ let st = Struct :: new ( dl, & fields, & hints [ .. ] ,
11941220 kind, ty) ?;
11951221 let non_zero = Some ( def. did ) == tcx. lang_items . non_zero ( ) ;
11961222 Univariant { variant : st, non_zero : non_zero }
@@ -1213,7 +1239,7 @@ impl<'a, 'gcx, 'tcx> Layout {
12131239 v. fields . iter ( ) . map ( |field| field. ty ( tcx, substs) ) . collect :: < Vec < _ > > ( )
12141240 } ) . collect :: < Vec < _ > > ( ) ;
12151241
1216- if variants. len ( ) == 2 && hint == attr :: ReprAny {
1242+ if variants. len ( ) == 2 && hints . len ( ) == 0 {
12171243 // Nullable pointer optimization
12181244 for discr in 0 ..2 {
12191245 let other_fields = variants[ 1 - discr] . iter ( ) . map ( |ty| {
@@ -1245,7 +1271,7 @@ impl<'a, 'gcx, 'tcx> Layout {
12451271 let st = Struct :: new ( dl,
12461272 & variants[ discr] . iter ( ) . map ( |ty| ty. layout ( infcx) )
12471273 . collect :: < Result < Vec < _ > , _ > > ( ) ?,
1248- hint , StructKind :: AlwaysSizedUnivariant , ty) ?;
1274+ & hints [ .. ] , StructKind :: AlwaysSizedUnivariant , ty) ?;
12491275
12501276 // We have to fix the last element of path here.
12511277 let mut i = * path. last ( ) . unwrap ( ) ;
@@ -1265,7 +1291,7 @@ impl<'a, 'gcx, 'tcx> Layout {
12651291 // The general case.
12661292 let discr_max = ( variants. len ( ) - 1 ) as i64 ;
12671293 assert ! ( discr_max >= 0 ) ;
1268- let ( min_ity, _) = Integer :: repr_discr ( tcx, ty, hint , 0 , discr_max) ;
1294+ let ( min_ity, _) = Integer :: repr_discr ( tcx, ty, & hints [ .. ] , 0 , discr_max) ;
12691295
12701296 let mut align = dl. aggregate_align ;
12711297 let mut size = Size :: from_bytes ( 0 ) ;
@@ -1283,7 +1309,7 @@ impl<'a, 'gcx, 'tcx> Layout {
12831309 fields. insert ( 0 , & discr) ;
12841310 let st = Struct :: new ( dl,
12851311 & fields,
1286- hint , StructKind :: EnumVariant , ty) ?;
1312+ & hints [ .. ] , StructKind :: EnumVariant , ty) ?;
12871313 // Find the first field we can't move later
12881314 // to make room for a larger discriminant.
12891315 // It is important to skip the first field.
0 commit comments