]> git.proxmox.com Git - rustc.git/blob - src/librustc_lint/types.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / librustc_lint / types.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(non_snake_case)]
12
13 use rustc::hir::def_id::DefId;
14 use rustc::ty::subst::Substs;
15 use rustc::ty::{self, AdtKind, Ty, TyCtxt};
16 use rustc::ty::layout::{Layout, Primitive};
17 use rustc::traits::Reveal;
18 use middle::const_val::ConstVal;
19 use rustc_const_eval::eval_const_expr_partial;
20 use rustc_const_eval::EvalHint::ExprTypeChecked;
21 use util::nodemap::FnvHashSet;
22 use lint::{LateContext, LintContext, LintArray};
23 use lint::{LintPass, LateLintPass};
24
25 use std::cmp;
26 use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
27
28 use syntax::ast;
29 use syntax::abi::Abi;
30 use syntax::attr;
31 use syntax_pos::Span;
32 use syntax::codemap;
33
34 use rustc::hir;
35
36 register_long_diagnostics! {
37 E0519: r##"
38 It is not allowed to negate an unsigned integer.
39 You can negate a signed integer and cast it to an
40 unsigned integer or use the `!` operator.
41
42 ```
43 let x: usize = -1isize as usize;
44 let y: usize = !0;
45 assert_eq!(x, y);
46 ```
47
48 Alternatively you can use the `Wrapping` newtype
49 or the `wrapping_neg` operation that all
50 integral types support:
51
52 ```
53 use std::num::Wrapping;
54 let x: Wrapping<usize> = -Wrapping(1);
55 let Wrapping(x) = x;
56 let y: usize = 1.wrapping_neg();
57 assert_eq!(x, y);
58 ```
59 "##
60 }
61
62 declare_lint! {
63 UNUSED_COMPARISONS,
64 Warn,
65 "comparisons made useless by limits of the types involved"
66 }
67
68 declare_lint! {
69 OVERFLOWING_LITERALS,
70 Warn,
71 "literal out of range for its type"
72 }
73
74 declare_lint! {
75 EXCEEDING_BITSHIFTS,
76 Deny,
77 "shift exceeds the type's number of bits"
78 }
79
80 declare_lint! {
81 VARIANT_SIZE_DIFFERENCES,
82 Allow,
83 "detects enums with widely varying variant sizes"
84 }
85
86 #[derive(Copy, Clone)]
87 pub struct TypeLimits {
88 /// Id of the last visited negated expression
89 negated_expr_id: ast::NodeId,
90 }
91
92 impl TypeLimits {
93 pub fn new() -> TypeLimits {
94 TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID }
95 }
96 }
97
98 impl LintPass for TypeLimits {
99 fn get_lints(&self) -> LintArray {
100 lint_array!(UNUSED_COMPARISONS,
101 OVERFLOWING_LITERALS,
102 EXCEEDING_BITSHIFTS)
103 }
104 }
105
106 impl LateLintPass for TypeLimits {
107 fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
108 match e.node {
109 hir::ExprUnary(hir::UnNeg, ref expr) => {
110 if let hir::ExprLit(ref lit) = expr.node {
111 match lit.node {
112 ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
113 forbid_unsigned_negation(cx, e.span);
114 }
115 ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
116 if let ty::TyUint(_) = cx.tcx.tables().node_id_to_type(e.id).sty {
117 forbid_unsigned_negation(cx, e.span);
118 }
119 }
120 _ => (),
121 }
122 } else {
123 let t = cx.tcx.tables().node_id_to_type(expr.id);
124 if let ty::TyUint(_) = t.sty {
125 forbid_unsigned_negation(cx, e.span);
126 }
127 }
128 // propagate negation, if the negation itself isn't negated
129 if self.negated_expr_id != e.id {
130 self.negated_expr_id = expr.id;
131 }
132 }
133 hir::ExprBinary(binop, ref l, ref r) => {
134 if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) {
135 cx.span_lint(UNUSED_COMPARISONS,
136 e.span,
137 "comparison is useless due to type limits");
138 }
139
140 if binop.node.is_shift() {
141 let opt_ty_bits = match cx.tcx.tables().node_id_to_type(l.id).sty {
142 ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
143 ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
144 _ => None,
145 };
146
147 if let Some(bits) = opt_ty_bits {
148 let exceeding = if let hir::ExprLit(ref lit) = r.node {
149 if let ast::LitKind::Int(shift, _) = lit.node {
150 shift >= bits
151 } else {
152 false
153 }
154 } else {
155 match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
156 Ok(ConstVal::Integral(i)) => {
157 i.is_negative() ||
158 i.to_u64()
159 .map(|i| i >= bits)
160 .unwrap_or(true)
161 }
162 _ => false,
163 }
164 };
165 if exceeding {
166 cx.span_lint(EXCEEDING_BITSHIFTS,
167 e.span,
168 "bitshift exceeds the type's number of bits");
169 }
170 };
171 }
172 }
173 hir::ExprLit(ref lit) => {
174 match cx.tcx.tables().node_id_to_type(e.id).sty {
175 ty::TyInt(t) => {
176 match lit.node {
177 ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
178 ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => {
179 let int_type = if let ast::IntTy::Is = t {
180 cx.sess().target.int_type
181 } else {
182 t
183 };
184 let (_, max) = int_ty_range(int_type);
185 let negative = self.negated_expr_id == e.id;
186
187 // Detect literal value out of range [min, max] inclusive
188 // avoiding use of -min to prevent overflow/panic
189 if (negative && v > max as u64 + 1) ||
190 (!negative && v > max as u64) {
191 cx.span_lint(OVERFLOWING_LITERALS,
192 e.span,
193 &format!("literal out of range for {:?}", t));
194 return;
195 }
196 }
197 _ => bug!(),
198 };
199 }
200 ty::TyUint(t) => {
201 let uint_type = if let ast::UintTy::Us = t {
202 cx.sess().target.uint_type
203 } else {
204 t
205 };
206 let (min, max) = uint_ty_range(uint_type);
207 let lit_val: u64 = match lit.node {
208 // _v is u8, within range by definition
209 ast::LitKind::Byte(_v) => return,
210 ast::LitKind::Int(v, _) => v,
211 _ => bug!(),
212 };
213 if lit_val < min || lit_val > max {
214 cx.span_lint(OVERFLOWING_LITERALS,
215 e.span,
216 &format!("literal out of range for {:?}", t));
217 }
218 }
219 ty::TyFloat(t) => {
220 let (min, max) = float_ty_range(t);
221 let lit_val: f64 = match lit.node {
222 ast::LitKind::Float(ref v, _) |
223 ast::LitKind::FloatUnsuffixed(ref v) => {
224 match v.parse() {
225 Ok(f) => f,
226 Err(_) => return,
227 }
228 }
229 _ => bug!(),
230 };
231 if lit_val < min || lit_val > max {
232 cx.span_lint(OVERFLOWING_LITERALS,
233 e.span,
234 &format!("literal out of range for {:?}", t));
235 }
236 }
237 _ => (),
238 };
239 }
240 _ => (),
241 };
242
243 fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
244 match binop.node {
245 hir::BiLt => v > min && v <= max,
246 hir::BiLe => v >= min && v < max,
247 hir::BiGt => v >= min && v < max,
248 hir::BiGe => v > min && v <= max,
249 hir::BiEq | hir::BiNe => v >= min && v <= max,
250 _ => bug!(),
251 }
252 }
253
254 fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
255 codemap::respan(binop.span,
256 match binop.node {
257 hir::BiLt => hir::BiGt,
258 hir::BiLe => hir::BiGe,
259 hir::BiGt => hir::BiLt,
260 hir::BiGe => hir::BiLe,
261 _ => return binop,
262 })
263 }
264
265 // for isize & usize, be conservative with the warnings, so that the
266 // warnings are consistent between 32- and 64-bit platforms
267 fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
268 match int_ty {
269 ast::IntTy::Is => (i64::MIN, i64::MAX),
270 ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64),
271 ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64),
272 ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64),
273 ast::IntTy::I64 => (i64::MIN, i64::MAX),
274 }
275 }
276
277 fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
278 match uint_ty {
279 ast::UintTy::Us => (u64::MIN, u64::MAX),
280 ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64),
281 ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64),
282 ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64),
283 ast::UintTy::U64 => (u64::MIN, u64::MAX),
284 }
285 }
286
287 fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
288 match float_ty {
289 ast::FloatTy::F32 => (f32::MIN as f64, f32::MAX as f64),
290 ast::FloatTy::F64 => (f64::MIN, f64::MAX),
291 }
292 }
293
294 fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 {
295 match int_ty {
296 ast::IntTy::Is => int_ty_bits(target_int_ty, target_int_ty),
297 ast::IntTy::I8 => 8,
298 ast::IntTy::I16 => 16 as u64,
299 ast::IntTy::I32 => 32,
300 ast::IntTy::I64 => 64,
301 }
302 }
303
304 fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 {
305 match uint_ty {
306 ast::UintTy::Us => uint_ty_bits(target_uint_ty, target_uint_ty),
307 ast::UintTy::U8 => 8,
308 ast::UintTy::U16 => 16,
309 ast::UintTy::U32 => 32,
310 ast::UintTy::U64 => 64,
311 }
312 }
313
314 fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
315 binop: hir::BinOp,
316 l: &hir::Expr,
317 r: &hir::Expr)
318 -> bool {
319 let (lit, expr, swap) = match (&l.node, &r.node) {
320 (&hir::ExprLit(_), _) => (l, r, true),
321 (_, &hir::ExprLit(_)) => (r, l, false),
322 _ => return true,
323 };
324 // Normalize the binop so that the literal is always on the RHS in
325 // the comparison
326 let norm_binop = if swap { rev_binop(binop) } else { binop };
327 match tcx.tables().node_id_to_type(expr.id).sty {
328 ty::TyInt(int_ty) => {
329 let (min, max) = int_ty_range(int_ty);
330 let lit_val: i64 = match lit.node {
331 hir::ExprLit(ref li) => {
332 match li.node {
333 ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
334 ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
335 _ => return true,
336 }
337 }
338 _ => bug!(),
339 };
340 is_valid(norm_binop, lit_val, min, max)
341 }
342 ty::TyUint(uint_ty) => {
343 let (min, max): (u64, u64) = uint_ty_range(uint_ty);
344 let lit_val: u64 = match lit.node {
345 hir::ExprLit(ref li) => {
346 match li.node {
347 ast::LitKind::Int(v, _) => v,
348 _ => return true,
349 }
350 }
351 _ => bug!(),
352 };
353 is_valid(norm_binop, lit_val, min, max)
354 }
355 _ => true,
356 }
357 }
358
359 fn is_comparison(binop: hir::BinOp) -> bool {
360 match binop.node {
361 hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => true,
362 _ => false,
363 }
364 }
365
366 fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
367 cx.sess()
368 .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
369 .span_help(span, "use a cast or the `!` operator")
370 .emit();
371 }
372 }
373 }
374
375 declare_lint! {
376 IMPROPER_CTYPES,
377 Warn,
378 "proper use of libc types in foreign modules"
379 }
380
381 struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
382 cx: &'a LateContext<'a, 'tcx>,
383 }
384
385 enum FfiResult {
386 FfiSafe,
387 FfiUnsafe(&'static str),
388 FfiBadStruct(DefId, &'static str),
389 FfiBadUnion(DefId, &'static str),
390 FfiBadEnum(DefId, &'static str),
391 }
392
393 /// Check if this enum can be safely exported based on the
394 /// "nullable pointer optimization". Currently restricted
395 /// to function pointers and references, but could be
396 /// expanded to cover NonZero raw pointers and newtypes.
397 /// FIXME: This duplicates code in trans.
398 fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
399 def: ty::AdtDef<'tcx>,
400 substs: &Substs<'tcx>)
401 -> bool {
402 if def.variants.len() == 2 {
403 let data_idx;
404
405 if def.variants[0].fields.is_empty() {
406 data_idx = 1;
407 } else if def.variants[1].fields.is_empty() {
408 data_idx = 0;
409 } else {
410 return false;
411 }
412
413 if def.variants[data_idx].fields.len() == 1 {
414 match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
415 ty::TyFnPtr(_) => {
416 return true;
417 }
418 ty::TyRef(..) => {
419 return true;
420 }
421 _ => {}
422 }
423 }
424 }
425 false
426 }
427
428 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
429 /// Check if the given type is "ffi-safe" (has a stable, well-defined
430 /// representation which can be exported to C code).
431 fn check_type_for_ffi(&self, cache: &mut FnvHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult {
432 use self::FfiResult::*;
433 let cx = self.cx.tcx;
434
435 // Protect against infinite recursion, for example
436 // `struct S(*mut S);`.
437 // FIXME: A recursion limit is necessary as well, for irregular
438 // recusive types.
439 if !cache.insert(ty) {
440 return FfiSafe;
441 }
442
443 match ty.sty {
444 ty::TyAdt(def, substs) => {
445 match def.adt_kind() {
446 AdtKind::Struct => {
447 if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
448 return FfiUnsafe("found struct without foreign-function-safe \
449 representation annotation in foreign module, \
450 consider adding a #[repr(C)] attribute to the type");
451 }
452
453 // We can't completely trust repr(C) markings; make sure the
454 // fields are actually safe.
455 if def.struct_variant().fields.is_empty() {
456 return FfiUnsafe("found zero-size struct in foreign module, consider \
457 adding a member to this struct");
458 }
459
460 for field in &def.struct_variant().fields {
461 let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
462 let r = self.check_type_for_ffi(cache, field_ty);
463 match r {
464 FfiSafe => {}
465 FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
466 return r;
467 }
468 FfiUnsafe(s) => {
469 return FfiBadStruct(def.did, s);
470 }
471 }
472 }
473 FfiSafe
474 }
475 AdtKind::Union => {
476 if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
477 return FfiUnsafe("found union without foreign-function-safe \
478 representation annotation in foreign module, \
479 consider adding a #[repr(C)] attribute to the type");
480 }
481
482 for field in &def.struct_variant().fields {
483 let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
484 let r = self.check_type_for_ffi(cache, field_ty);
485 match r {
486 FfiSafe => {}
487 FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
488 return r;
489 }
490 FfiUnsafe(s) => {
491 return FfiBadUnion(def.did, s);
492 }
493 }
494 }
495 FfiSafe
496 }
497 AdtKind::Enum => {
498 if def.variants.is_empty() {
499 // Empty enums are okay... although sort of useless.
500 return FfiSafe;
501 }
502
503 // Check for a repr() attribute to specify the size of the
504 // discriminant.
505 let repr_hints = cx.lookup_repr_hints(def.did);
506 match &repr_hints[..] {
507 &[] => {
508 // Special-case types like `Option<extern fn()>`.
509 if !is_repr_nullable_ptr(cx, def, substs) {
510 return FfiUnsafe("found enum without foreign-function-safe \
511 representation annotation in foreign \
512 module, consider adding a #[repr(...)] \
513 attribute to the type");
514 }
515 }
516 &[ref hint] => {
517 if !hint.is_ffi_safe() {
518 // FIXME: This shouldn't be reachable: we should check
519 // this earlier.
520 return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
521 }
522
523 // Enum with an explicitly sized discriminant; either
524 // a C-style enum or a discriminated union.
525
526 // The layout of enum variants is implicitly repr(C).
527 // FIXME: Is that correct?
528 }
529 _ => {
530 // FIXME: This shouldn't be reachable: we should check
531 // this earlier.
532 return FfiUnsafe("enum has too many #[repr(...)] attributes");
533 }
534 }
535
536 // Check the contained variants.
537 for variant in &def.variants {
538 for field in &variant.fields {
539 let arg = cx.normalize_associated_type(&field.ty(cx, substs));
540 let r = self.check_type_for_ffi(cache, arg);
541 match r {
542 FfiSafe => {}
543 FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
544 return r;
545 }
546 FfiUnsafe(s) => {
547 return FfiBadEnum(def.did, s);
548 }
549 }
550 }
551 }
552 FfiSafe
553 }
554 }
555 }
556
557 ty::TyChar => {
558 FfiUnsafe("found Rust type `char` in foreign module, while \
559 `u32` or `libc::wchar_t` should be used")
560 }
561
562 // Primitive types with a stable representation.
563 ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
564
565 ty::TyBox(..) => {
566 FfiUnsafe("found Rust type Box<_> in foreign module, \
567 consider using a raw pointer instead")
568 }
569
570 ty::TySlice(_) => {
571 FfiUnsafe("found Rust slice type in foreign module, \
572 consider using a raw pointer instead")
573 }
574
575 ty::TyTrait(..) => {
576 FfiUnsafe("found Rust trait type in foreign module, \
577 consider using a raw pointer instead")
578 }
579
580 ty::TyStr => {
581 FfiUnsafe("found Rust type `str` in foreign module; \
582 consider using a `*const libc::c_char`")
583 }
584
585 ty::TyTuple(_) => {
586 FfiUnsafe("found Rust tuple type in foreign module; \
587 consider using a struct instead")
588 }
589
590 ty::TyRawPtr(ref m) |
591 ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
592
593 ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
594
595 ty::TyFnPtr(bare_fn) => {
596 match bare_fn.abi {
597 Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
598 return FfiUnsafe("found function pointer with Rust calling convention in \
599 foreign module; consider using an `extern` function \
600 pointer")
601 }
602 _ => {}
603 }
604
605 let sig = cx.erase_late_bound_regions(&bare_fn.sig);
606 if !sig.output.is_nil() {
607 let r = self.check_type_for_ffi(cache, sig.output);
608 match r {
609 FfiSafe => {}
610 _ => {
611 return r;
612 }
613 }
614 }
615 for arg in sig.inputs {
616 let r = self.check_type_for_ffi(cache, arg);
617 match r {
618 FfiSafe => {}
619 _ => {
620 return r;
621 }
622 }
623 }
624 FfiSafe
625 }
626
627 ty::TyParam(..) |
628 ty::TyInfer(..) |
629 ty::TyError |
630 ty::TyClosure(..) |
631 ty::TyProjection(..) |
632 ty::TyAnon(..) |
633 ty::TyFnDef(..) => bug!("Unexpected type in foreign function"),
634 }
635 }
636
637 fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
638 // it is only OK to use this function because extern fns cannot have
639 // any generic types right now:
640 let ty = self.cx.tcx.normalize_associated_type(&ty);
641
642 match self.check_type_for_ffi(&mut FnvHashSet(), ty) {
643 FfiResult::FfiSafe => {}
644 FfiResult::FfiUnsafe(s) => {
645 self.cx.span_lint(IMPROPER_CTYPES, sp, s);
646 }
647 FfiResult::FfiBadStruct(_, s) => {
648 // FIXME: This diagnostic is difficult to read, and doesn't
649 // point at the relevant field.
650 self.cx.span_lint(IMPROPER_CTYPES,
651 sp,
652 &format!("found non-foreign-function-safe member in struct \
653 marked #[repr(C)]: {}",
654 s));
655 }
656 FfiResult::FfiBadUnion(_, s) => {
657 // FIXME: This diagnostic is difficult to read, and doesn't
658 // point at the relevant field.
659 self.cx.span_lint(IMPROPER_CTYPES,
660 sp,
661 &format!("found non-foreign-function-safe member in union \
662 marked #[repr(C)]: {}",
663 s));
664 }
665 FfiResult::FfiBadEnum(_, s) => {
666 // FIXME: This diagnostic is difficult to read, and doesn't
667 // point at the relevant variant.
668 self.cx.span_lint(IMPROPER_CTYPES,
669 sp,
670 &format!("found non-foreign-function-safe member in enum: {}",
671 s));
672 }
673 }
674 }
675
676 fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) {
677 let def_id = self.cx.tcx.map.local_def_id(id);
678 let scheme = self.cx.tcx.lookup_item_type(def_id);
679 let sig = scheme.ty.fn_sig();
680 let sig = self.cx.tcx.erase_late_bound_regions(&sig);
681
682 for (&input_ty, input_hir) in sig.inputs.iter().zip(&decl.inputs) {
683 self.check_type_for_ffi_and_report_errors(input_hir.ty.span, &input_ty);
684 }
685
686 if let hir::Return(ref ret_hir) = decl.output {
687 let ret_ty = sig.output;
688 if !ret_ty.is_nil() {
689 self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
690 }
691 }
692 }
693
694 fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) {
695 let def_id = self.cx.tcx.map.local_def_id(id);
696 let scheme = self.cx.tcx.lookup_item_type(def_id);
697 self.check_type_for_ffi_and_report_errors(span, scheme.ty);
698 }
699 }
700
701 #[derive(Copy, Clone)]
702 pub struct ImproperCTypes;
703
704 impl LintPass for ImproperCTypes {
705 fn get_lints(&self) -> LintArray {
706 lint_array!(IMPROPER_CTYPES)
707 }
708 }
709
710 impl LateLintPass for ImproperCTypes {
711 fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
712 let mut vis = ImproperCTypesVisitor { cx: cx };
713 if let hir::ItemForeignMod(ref nmod) = it.node {
714 if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
715 for ni in &nmod.items {
716 match ni.node {
717 hir::ForeignItemFn(ref decl, _) => {
718 vis.check_foreign_fn(ni.id, decl);
719 }
720 hir::ForeignItemStatic(ref ty, _) => {
721 vis.check_foreign_static(ni.id, ty.span);
722 }
723 }
724 }
725 }
726 }
727 }
728 }
729
730 pub struct VariantSizeDifferences;
731
732 impl LintPass for VariantSizeDifferences {
733 fn get_lints(&self) -> LintArray {
734 lint_array!(VARIANT_SIZE_DIFFERENCES)
735 }
736 }
737
738 impl LateLintPass for VariantSizeDifferences {
739 fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
740 if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
741 if gens.ty_params.is_empty() {
742 // sizes only make sense for non-generic types
743 let t = cx.tcx.tables().node_id_to_type(it.id);
744 let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
745 let ty = cx.tcx.erase_regions(&t);
746 ty.layout(&infcx)
747 .unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e))
748 });
749
750 if let Layout::General { ref variants, ref size, discr, .. } = *layout {
751 let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
752
753 debug!("enum `{}` is {} bytes large", t, size.bytes());
754
755 let (largest, slargest, largest_index) = enum_definition.variants
756 .iter()
757 .zip(variants)
758 .map(|(variant, variant_layout)| {
759 // Subtract the size of the enum discriminant
760 let bytes = variant_layout.min_size
761 .bytes()
762 .saturating_sub(discr_size);
763
764 debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
765 bytes
766 })
767 .enumerate()
768 .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
769 (size, l, idx)
770 } else if size > s {
771 (l, size, li)
772 } else {
773 (l, s, li)
774 });
775
776 // we only warn if the largest variant is at least thrice as large as
777 // the second-largest.
778 if largest > slargest * 3 && slargest > 0 {
779 cx.span_lint(VARIANT_SIZE_DIFFERENCES,
780 enum_definition.variants[largest_index].span,
781 &format!("enum variant is more than three times larger \
782 ({} bytes) than the next largest",
783 largest));
784 }
785 }
786 }
787 }
788 }
789 }