@@ -145,22 +145,8 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
145145 return Univariant ( mk_struct ( cx, ftys, packed) , dtor)
146146 }
147147 ty:: ty_enum( def_id, ref substs) => {
148- struct Case { discr : Disr , tys : ~[ ty:: t ] } ;
149- impl Case {
150- fn is_zerolen ( & self , cx : & mut CrateContext ) -> bool {
151- mk_struct ( cx, self . tys , false ) . size == 0
152- }
153- fn find_ptr ( & self ) -> Option < uint > {
154- self . tys . iter ( ) . position ( |& ty| mono_data_classify ( ty) == MonoNonNull )
155- }
156- }
157-
158- let cases = do ty:: enum_variants ( cx. tcx , def_id) . map |vi| {
159- let arg_tys = do vi. args . map |& raw_ty| {
160- ty:: subst ( cx. tcx , substs, raw_ty)
161- } ;
162- Case { discr : vi. disr_val , tys : arg_tys }
163- } ;
148+ let cases = get_cases ( cx. tcx , def_id, substs) ;
149+ let hint = ty:: lookup_repr_hint ( cx. tcx , def_id) ;
164150
165151 if cases. len ( ) == 0 {
166152 // Uninhabitable; represent as unit
@@ -170,7 +156,6 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
170156 if cases. iter ( ) . all ( |c| c. tys . len ( ) == 0 ) {
171157 // All bodies empty -> intlike
172158 let discrs = cases. map ( |c| c. discr ) ;
173- let hint = ty:: lookup_repr_hint ( cx. tcx , def_id) ;
174159 let bounds = IntBounds {
175160 ulo : * discrs. iter ( ) . min ( ) . unwrap ( ) ,
176161 uhi : * discrs. iter ( ) . max ( ) . unwrap ( ) ,
@@ -232,6 +217,56 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
232217 }
233218}
234219
220+ /// Determine, without doing translation, whether an ADT must be FFI-safe.
221+ /// For use in lint or similar, where being sound but slightly incomplete is acceptable.
222+ pub fn is_ffi_safe ( tcx : ty:: ctxt , def_id : ast:: DefId ) -> bool {
223+ match ty:: get ( ty:: lookup_item_type ( tcx, def_id) . ty ) . sty {
224+ ty:: ty_enum( def_id, ref substs) => {
225+ let cases = get_cases ( tcx, def_id, substs) ;
226+ // Univariant => like struct/tuple.
227+ if cases. len ( ) <= 2 {
228+ return true ;
229+ }
230+ let hint = ty:: lookup_repr_hint ( tcx, def_id) ;
231+ // Appropriate representation explicitly selected?
232+ if hint. is_ffi_safe ( ) {
233+ return true ;
234+ }
235+ // Conservative approximation of nullable pointers, for Option<~T> etc.
236+ if cases. len ( ) == 2 && hint == attr:: ReprAny &&
237+ ( cases[ 0 ] . tys . is_empty ( ) && cases[ 1 ] . find_ptr ( ) . is_some ( ) ||
238+ cases[ 1 ] . tys . is_empty ( ) && cases[ 0 ] . find_ptr ( ) . is_some ( ) ) {
239+ return true ;
240+ }
241+ false
242+ }
243+ // struct, tuple, etc.
244+ // (is this right in the present of typedefs?)
245+ _ => true
246+ }
247+ }
248+
249+ // NOTE this should probably all be in ty
250+ struct Case { discr : Disr , tys : ~[ ty:: t ] }
251+ impl Case {
252+ fn is_zerolen ( & self , cx : & mut CrateContext ) -> bool {
253+ mk_struct ( cx, self . tys , false ) . size == 0
254+ }
255+ fn find_ptr ( & self ) -> Option < uint > {
256+ self . tys . iter ( ) . position ( |& ty| mono_data_classify ( ty) == MonoNonNull )
257+ }
258+ }
259+
260+ fn get_cases ( tcx : ty:: ctxt , def_id : ast:: DefId , substs : & ty:: substs ) -> ~[ Case ] {
261+ do ty:: enum_variants ( tcx, def_id) . map |vi| {
262+ let arg_tys = do vi. args . map |& raw_ty| {
263+ ty:: subst ( tcx, substs, raw_ty)
264+ } ;
265+ Case { discr : vi. disr_val , tys : arg_tys }
266+ }
267+ }
268+
269+
235270fn mk_struct ( cx : & mut CrateContext , tys : & [ ty:: t ] , packed : bool ) -> Struct {
236271 let lltys = tys. map ( |& ty| type_of:: sizing_type_of ( cx, ty) ) ;
237272 let llty_rec = Type :: struct_ ( lltys, packed) ;
0 commit comments