Lint non-FFI-safe enums. · rust-lang/rust@25f9534 (original) (raw)
`@@ -145,22 +145,8 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
`
145
145
`return Univariant(mk_struct(cx, ftys, packed), dtor)
`
146
146
`}
`
147
147
` 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 {
`
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);
`
164
150
``
165
151
`if cases.len() == 0 {
`
166
152
`// Uninhabitable; represent as unit
`
`@@ -170,7 +156,6 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
`
170
156
`if cases.iter().all(|c| c.tys.len() == 0) {
`
171
157
`// All bodies empty -> intlike
`
172
158
`let discrs = cases.map(|c| c.discr);
`
173
``
`-
let hint = ty::lookup_repr_hint(cx.tcx, def_id);
`
174
159
`let bounds = IntBounds {
`
175
160
`ulo: *discrs.iter().min().unwrap(),
`
176
161
`uhi: *discrs.iter().max().unwrap(),
`
`@@ -232,6 +217,56 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
`
232
217
`}
`
233
218
`}
`
234
219
``
``
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 {
`
``
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
+
235
270
`fn mk_struct(cx: &mut CrateContext, tys: &[ty::t], packed: bool) -> Struct {
`
236
271
`let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty));
`
237
272
`let llty_rec = Type::struct_(lltys, packed);
`