]> git.lizzy.rs Git - rust.git/blob - src/librustc_lint/types.rs
Suggest type for overflowing bin/hex-literals
[rust.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::map as hir_map;
14 use rustc::ty::subst::Substs;
15 use rustc::ty::{self, AdtKind, Ty, TyCtxt};
16 use rustc::ty::layout::{self, LayoutOf};
17 use middle::const_val::ConstVal;
18 use rustc_const_eval::ConstContext;
19 use util::nodemap::FxHashSet;
20 use lint::{LateContext, LintContext, LintArray};
21 use lint::{LintPass, LateLintPass};
22
23 use std::cmp;
24 use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
25
26 use syntax::ast;
27 use syntax::abi::Abi;
28 use syntax_pos::Span;
29 use syntax::codemap;
30
31 use rustc::hir;
32
33 declare_lint! {
34     UNUSED_COMPARISONS,
35     Warn,
36     "comparisons made useless by limits of the types involved"
37 }
38
39 declare_lint! {
40     OVERFLOWING_LITERALS,
41     Warn,
42     "literal out of range for its type"
43 }
44
45 declare_lint! {
46     EXCEEDING_BITSHIFTS,
47     Deny,
48     "shift exceeds the type's number of bits"
49 }
50
51 declare_lint! {
52     VARIANT_SIZE_DIFFERENCES,
53     Allow,
54     "detects enums with widely varying variant sizes"
55 }
56
57 #[derive(Copy, Clone)]
58 pub struct TypeLimits {
59     /// Id of the last visited negated expression
60     negated_expr_id: ast::NodeId,
61 }
62
63 impl TypeLimits {
64     pub fn new() -> TypeLimits {
65         TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID }
66     }
67 }
68
69 impl LintPass for TypeLimits {
70     fn get_lints(&self) -> LintArray {
71         lint_array!(UNUSED_COMPARISONS,
72                     OVERFLOWING_LITERALS,
73                     EXCEEDING_BITSHIFTS)
74     }
75 }
76
77 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
78     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) {
79         match e.node {
80             hir::ExprUnary(hir::UnNeg, ref expr) => {
81                 // propagate negation, if the negation itself isn't negated
82                 if self.negated_expr_id != e.id {
83                     self.negated_expr_id = expr.id;
84                 }
85             }
86             hir::ExprBinary(binop, ref l, ref r) => {
87                 if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
88                     cx.span_lint(UNUSED_COMPARISONS,
89                                  e.span,
90                                  "comparison is useless due to type limits");
91                 }
92
93                 if binop.node.is_shift() {
94                     let opt_ty_bits = match cx.tables.node_id_to_type(l.hir_id).sty {
95                         ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.isize_ty)),
96                         ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.usize_ty)),
97                         _ => None,
98                     };
99
100                     if let Some(bits) = opt_ty_bits {
101                         let exceeding = if let hir::ExprLit(ref lit) = r.node {
102                             if let ast::LitKind::Int(shift, _) = lit.node {
103                                 shift as u64 >= bits
104                             } else {
105                                 false
106                             }
107                         } else {
108                             // HACK(eddyb) This might be quite inefficient.
109                             // This would be better left to MIR constant propagation,
110                             // perhaps even at trans time (like is the case already
111                             // when the value being shifted is *also* constant).
112                             let parent_item = cx.tcx.hir.get_parent(e.id);
113                             let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
114                             let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
115                             let const_cx = ConstContext::new(cx.tcx,
116                                                              cx.param_env.and(substs),
117                                                              cx.tables);
118                             match const_cx.eval(&r) {
119                                 Ok(&ty::Const { val: ConstVal::Integral(i), .. }) => {
120                                     i.is_negative() ||
121                                     i.to_u64()
122                                         .map(|i| i >= bits)
123                                         .unwrap_or(true)
124                                 }
125                                 _ => false,
126                             }
127                         };
128                         if exceeding {
129                             cx.span_lint(EXCEEDING_BITSHIFTS,
130                                          e.span,
131                                          "bitshift exceeds the type's number of bits");
132                         }
133                     };
134                 }
135             }
136             hir::ExprLit(ref lit) => {
137                 match cx.tables.node_id_to_type(e.hir_id).sty {
138                     ty::TyInt(t) => {
139                         match lit.node {
140                             ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
141                             ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => {
142                                 let int_type = if let ast::IntTy::Isize = t {
143                                     cx.sess().target.isize_ty
144                                 } else {
145                                     t
146                                 };
147                                 let (_, max) = int_ty_range(int_type);
148                                 let max = max as u128;
149                                 let negative = self.negated_expr_id == e.id;
150
151                                 // Detect literal value out of range [min, max] inclusive
152                                 // avoiding use of -min to prevent overflow/panic
153                                 if (negative && v > max + 1) || (!negative && v > max) {
154                                     if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
155                                         let bits = int_ty_bits(t, cx.sess().target.isize_ty);
156                                         let mut actually = v as i128;
157                                         if bits < 128 {
158                                             // v & 0b0..01..1, |1| = bits
159                                             let trimmed = v & ((1 << bits) - 1);
160                                             actually = if v & (1 << (bits - 1)) == 0 {
161                                                 // positive
162                                                 trimmed as i128
163                                             } else {
164                                                 // negative -> two's complement
165                                                 (((-1 as i128 as u128) << bits) | trimmed) as i128
166                                             };
167                                         }
168                                         let mut err = cx.struct_span_lint(
169                                             OVERFLOWING_LITERALS,
170                                             e.span,
171                                             &format!("literal out of range for {:?}", t),
172                                         );
173                                         err.note(&format!(
174                                             "the literal `{}` (decimal `{}`) does not fit into \
175                                              an `{:?}` and will become `{}{:?}`.",
176                                             repr_str, v, t, actually, t
177                                         ));
178                                         let sugg_ty = get_fitting_type(
179                                             &cx.tables.node_id_to_type(e.hir_id).sty,
180                                             v,
181                                             negative,
182                                         ).map_or(String::new(), |ty| match ty {
183                                             ty::TyUint(t) => format!("Consider using `{:?}`", t),
184                                             ty::TyInt(t) => format!("Consider using `{:?}`", t),
185                                             _ => String::new(),
186                                         });
187                                         if !sugg_ty.is_empty() {
188                                             err.help(&sugg_ty);
189                                         }
190
191                                         err.emit();
192                                         return;
193                                     }
194                                     cx.span_lint(
195                                         OVERFLOWING_LITERALS,
196                                         e.span,
197                                         &format!("literal out of range for {:?}", t),
198                                     );
199                                     return;
200                                 }
201                             }
202                             _ => bug!(),
203                         };
204                     }
205                     ty::TyUint(t) => {
206                         let uint_type = if let ast::UintTy::Usize = t {
207                             cx.sess().target.usize_ty
208                         } else {
209                             t
210                         };
211                         let (min, max) = uint_ty_range(uint_type);
212                         let lit_val: u128 = match lit.node {
213                             // _v is u8, within range by definition
214                             ast::LitKind::Byte(_v) => return,
215                             ast::LitKind::Int(v, _) => v,
216                             _ => bug!(),
217                         };
218                         if lit_val < min || lit_val > max {
219                             let parent_id = cx.tcx.hir.get_parent_node(e.id);
220                             if let hir_map::NodeExpr(parent_expr) = cx.tcx.hir.get(parent_id) {
221                                 if let hir::ExprCast(..) = parent_expr.node {
222                                     if let ty::TyChar = cx.tables.expr_ty(parent_expr).sty {
223                                         let mut err = cx.struct_span_lint(
224                                             OVERFLOWING_LITERALS,
225                                             parent_expr.span,
226                                             "only u8 can be casted into char",
227                                         );
228                                         err.span_suggestion(
229                                             parent_expr.span,
230                                             &"use a char literal instead",
231                                             format!("'\\u{{{:X}}}'", lit_val),
232                                         );
233                                         err.emit();
234                                         return;
235                                     }
236                                 }
237                             }
238                             if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
239                                 let bits = uint_ty_bits(t, cx.sess().target.usize_ty);
240                                 // u128 cannot be greater than max -> compiler error
241                                 let actually = lit_val & ((1 << bits) - 1);
242                                 let mut err = cx.struct_span_lint(
243                                     OVERFLOWING_LITERALS,
244                                     e.span,
245                                     &format!("literal out of range for {:?}", t),
246                                 );
247                                 err.note(&format!(
248                                     "the literal `{}` (decimal `{}`) does not fit into \
249                                      an `{:?}` and will become `{}{:?}`.",
250                                     repr_str, lit_val, t, actually, t
251                                 ));
252                                 let sugg_ty = get_fitting_type(
253                                     &cx.tables.node_id_to_type(e.hir_id).sty,
254                                     lit_val,
255                                     false,
256                                 ).map_or(
257                                     String::new(),
258                                     |ty| {
259                                         if let ty::TyUint(t) = ty {
260                                             format!("Consider using `{:?}`", t)
261                                         } else {
262                                             String::new()
263                                         }
264                                     },
265                                 );
266                                 if !sugg_ty.is_empty() {
267                                     err.help(&sugg_ty);
268                                 }
269
270                                 err.emit();
271                                 return;
272                             }
273                             cx.span_lint(
274                                 OVERFLOWING_LITERALS,
275                                 e.span,
276                                 &format!("literal out of range for {:?}", t),
277                             );
278                         }
279                     }
280                     ty::TyFloat(t) => {
281                         let is_infinite = match lit.node {
282                             ast::LitKind::Float(v, _) | ast::LitKind::FloatUnsuffixed(v) => match t
283                             {
284                                 ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
285                                 ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
286                             },
287                             _ => bug!(),
288                         };
289                         if is_infinite == Ok(true) {
290                             cx.span_lint(
291                                 OVERFLOWING_LITERALS,
292                                 e.span,
293                                 &format!("literal out of range for {:?}", t),
294                             );
295                         }
296                     }
297                     _ => (),
298                 };
299             }
300             _ => (),
301         };
302
303         fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
304             match binop.node {
305                 hir::BiLt => v > min && v <= max,
306                 hir::BiLe => v >= min && v < max,
307                 hir::BiGt => v >= min && v < max,
308                 hir::BiGe => v > min && v <= max,
309                 hir::BiEq | hir::BiNe => v >= min && v <= max,
310                 _ => bug!(),
311             }
312         }
313
314         fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
315             codemap::respan(binop.span,
316                             match binop.node {
317                                 hir::BiLt => hir::BiGt,
318                                 hir::BiLe => hir::BiGe,
319                                 hir::BiGt => hir::BiLt,
320                                 hir::BiGe => hir::BiLe,
321                                 _ => return binop,
322                             })
323         }
324
325         // for isize & usize, be conservative with the warnings, so that the
326         // warnings are consistent between 32- and 64-bit platforms
327         fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) {
328             match int_ty {
329                 ast::IntTy::Isize => (i64::min_value() as i128, i64::max_value() as i128),
330                 ast::IntTy::I8 => (i8::min_value() as i64 as i128, i8::max_value() as i128),
331                 ast::IntTy::I16 => (i16::min_value() as i64 as i128, i16::max_value() as i128),
332                 ast::IntTy::I32 => (i32::min_value() as i64 as i128, i32::max_value() as i128),
333                 ast::IntTy::I64 => (i64::min_value() as i128, i64::max_value() as i128),
334                 ast::IntTy::I128 =>(i128::min_value() as i128, i128::max_value()),
335             }
336         }
337
338         fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) {
339             match uint_ty {
340                 ast::UintTy::Usize => (u64::min_value() as u128, u64::max_value() as u128),
341                 ast::UintTy::U8 => (u8::min_value() as u128, u8::max_value() as u128),
342                 ast::UintTy::U16 => (u16::min_value() as u128, u16::max_value() as u128),
343                 ast::UintTy::U32 => (u32::min_value() as u128, u32::max_value() as u128),
344                 ast::UintTy::U64 => (u64::min_value() as u128, u64::max_value() as u128),
345                 ast::UintTy::U128 => (u128::min_value(), u128::max_value()),
346             }
347         }
348
349         fn int_ty_bits(int_ty: ast::IntTy, isize_ty: ast::IntTy) -> u64 {
350             match int_ty {
351                 ast::IntTy::Isize => int_ty_bits(isize_ty, isize_ty),
352                 ast::IntTy::I8 => 8,
353                 ast::IntTy::I16 => 16 as u64,
354                 ast::IntTy::I32 => 32,
355                 ast::IntTy::I64 => 64,
356                 ast::IntTy::I128 => 128,
357             }
358         }
359
360         fn uint_ty_bits(uint_ty: ast::UintTy, usize_ty: ast::UintTy) -> u64 {
361             match uint_ty {
362                 ast::UintTy::Usize => uint_ty_bits(usize_ty, usize_ty),
363                 ast::UintTy::U8 => 8,
364                 ast::UintTy::U16 => 16,
365                 ast::UintTy::U32 => 32,
366                 ast::UintTy::U64 => 64,
367                 ast::UintTy::U128 => 128,
368             }
369         }
370
371         fn check_limits(cx: &LateContext,
372                         binop: hir::BinOp,
373                         l: &hir::Expr,
374                         r: &hir::Expr)
375                         -> bool {
376             let (lit, expr, swap) = match (&l.node, &r.node) {
377                 (&hir::ExprLit(_), _) => (l, r, true),
378                 (_, &hir::ExprLit(_)) => (r, l, false),
379                 _ => return true,
380             };
381             // Normalize the binop so that the literal is always on the RHS in
382             // the comparison
383             let norm_binop = if swap { rev_binop(binop) } else { binop };
384             match cx.tables.node_id_to_type(expr.hir_id).sty {
385                 ty::TyInt(int_ty) => {
386                     let (min, max) = int_ty_range(int_ty);
387                     let lit_val: i128 = match lit.node {
388                         hir::ExprLit(ref li) => {
389                             match li.node {
390                                 ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
391                                 ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i128,
392                                 _ => return true
393                             }
394                         },
395                         _ => bug!()
396                     };
397                     is_valid(norm_binop, lit_val, min, max)
398                 }
399                 ty::TyUint(uint_ty) => {
400                     let (min, max) :(u128, u128) = uint_ty_range(uint_ty);
401                     let lit_val: u128 = match lit.node {
402                         hir::ExprLit(ref li) => {
403                             match li.node {
404                                 ast::LitKind::Int(v, _) => v,
405                                 _ => return true
406                             }
407                         },
408                         _ => bug!()
409                     };
410                     is_valid(norm_binop, lit_val, min, max)
411                 }
412                 _ => true,
413             }
414         }
415
416         fn is_comparison(binop: hir::BinOp) -> bool {
417             match binop.node {
418                 hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => true,
419                 _ => false,
420             }
421         }
422
423         fn get_bin_hex_repr(cx: &LateContext, lit: &ast::Lit) -> Option<String> {
424             if let Some(src) = cx.sess().codemap().span_to_snippet(lit.span).ok() {
425                 if let Some(firstch) = src.chars().next() {
426                     if let Some(0) = char::to_digit(firstch, 10) {
427                         if let Some(base) = src.chars().nth(1) {
428                             if base == 'x' || base == 'b' {
429                                 return Some(src);
430                             }
431                         }
432                     }
433                 }
434             }
435
436             None
437         }
438
439         fn get_fitting_type<'a>(
440             t: &ty::TypeVariants,
441             val: u128,
442             negative: bool,
443         ) -> Option<ty::TypeVariants<'a>> {
444             use syntax::ast::IntTy::*;
445             use syntax::ast::UintTy::*;
446             macro_rules! find_fit {
447                 ($ty:expr, $val:expr, $negative:expr,
448                  $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => {
449                     {
450                         let _neg = if negative { 1 } else { 0 };
451                         match $ty {
452                             $($type => {
453                                 $(if !negative && val <= uint_ty_range($utypes).1 {
454                                     return Some(ty::TyUint($utypes))
455                                 })*
456                                 $(if val <= int_ty_range($itypes).1 as u128 + _neg {
457                                     return Some(ty::TyInt($itypes))
458                                 })*
459                                 None
460                             },)*
461                             _ => None
462                         }
463                     }
464                 }
465             }
466             if let &ty::TyInt(i) = t {
467                 return find_fit!(i, val, negative,
468                                  I8 => [U8] => [I16, I32, I64, I128],
469                                  I16 => [U16] => [I32, I64, I128],
470                                  I32 => [U32] => [I64, I128],
471                                  I64 => [U64] => [I128],
472                                  I128 => [U128] => []);
473             }
474             if let &ty::TyUint(u) = t {
475                 return find_fit!(u, val, negative,
476                                  U8 => [U8, U16, U32, U64, U128] => [],
477                                  U16 => [U16, U32, U64, U128] => [],
478                                  U32 => [U32, U64, U128] => [],
479                                  U64 => [U64, U128] => [],
480                                  U128 => [U128] => []);
481             }
482
483             None
484         }
485     }
486 }
487
488 declare_lint! {
489     IMPROPER_CTYPES,
490     Warn,
491     "proper use of libc types in foreign modules"
492 }
493
494 struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
495     cx: &'a LateContext<'a, 'tcx>,
496 }
497
498 enum FfiResult<'tcx> {
499     FfiSafe,
500     FfiPhantom(Ty<'tcx>),
501     FfiUnsafe {
502         ty: Ty<'tcx>,
503         reason: &'static str,
504         help: Option<&'static str>,
505     },
506 }
507
508 /// Check if this enum can be safely exported based on the
509 /// "nullable pointer optimization". Currently restricted
510 /// to function pointers and references, but could be
511 /// expanded to cover NonZero raw pointers and newtypes.
512 /// FIXME: This duplicates code in trans.
513 fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
514                                   def: &'tcx ty::AdtDef,
515                                   substs: &Substs<'tcx>)
516                                   -> bool {
517     if def.variants.len() == 2 {
518         let data_idx;
519
520         if def.variants[0].fields.is_empty() {
521             data_idx = 1;
522         } else if def.variants[1].fields.is_empty() {
523             data_idx = 0;
524         } else {
525             return false;
526         }
527
528         if def.variants[data_idx].fields.len() == 1 {
529             match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
530                 ty::TyFnPtr(_) => {
531                     return true;
532                 }
533                 ty::TyRef(..) => {
534                     return true;
535                 }
536                 _ => {}
537             }
538         }
539     }
540     false
541 }
542
543 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
544     /// Check if the given type is "ffi-safe" (has a stable, well-defined
545     /// representation which can be exported to C code).
546     fn check_type_for_ffi(&self,
547                           cache: &mut FxHashSet<Ty<'tcx>>,
548                           ty: Ty<'tcx>) -> FfiResult<'tcx> {
549         use self::FfiResult::*;
550
551         let cx = self.cx.tcx;
552
553         // Protect against infinite recursion, for example
554         // `struct S(*mut S);`.
555         // FIXME: A recursion limit is necessary as well, for irregular
556         // recusive types.
557         if !cache.insert(ty) {
558             return FfiSafe;
559         }
560
561         match ty.sty {
562             ty::TyAdt(def, substs) => {
563                 if def.is_phantom_data() {
564                     return FfiPhantom(ty);
565                 }
566                 match def.adt_kind() {
567                     AdtKind::Struct => {
568                         if !def.repr.c() && !def.repr.transparent() {
569                             return FfiUnsafe {
570                                 ty: ty,
571                                 reason: "this struct has unspecified layout",
572                                 help: Some("consider adding a #[repr(C)] or #[repr(transparent)] \
573                                             attribute to this struct"),
574                             };
575                         }
576
577                         if def.non_enum_variant().fields.is_empty() {
578                             return FfiUnsafe {
579                                 ty: ty,
580                                 reason: "this struct has no fields",
581                                 help: Some("consider adding a member to this struct"),
582                             };
583                         }
584
585                         // We can't completely trust repr(C) and repr(transparent) markings;
586                         // make sure the fields are actually safe.
587                         let mut all_phantom = true;
588                         for field in &def.non_enum_variant().fields {
589                             let field_ty = cx.fully_normalize_associated_types_in(
590                                 &field.ty(cx, substs)
591                             );
592                             // repr(transparent) types are allowed to have arbitrary ZSTs, not just
593                             // PhantomData -- skip checking all ZST fields
594                             if def.repr.transparent() {
595                                 let is_zst = cx
596                                     .layout_of(cx.param_env(field.did).and(field_ty))
597                                     .map(|layout| layout.is_zst())
598                                     .unwrap_or(false);
599                                 if is_zst {
600                                     continue;
601                                 }
602                             }
603                             let r = self.check_type_for_ffi(cache, field_ty);
604                             match r {
605                                 FfiSafe => {
606                                     all_phantom = false;
607                                 }
608                                 FfiPhantom(..) => {}
609                                 FfiUnsafe { .. } => {
610                                     return r;
611                                 }
612                             }
613                         }
614
615                         if all_phantom { FfiPhantom(ty) } else { FfiSafe }
616                     }
617                     AdtKind::Union => {
618                         if !def.repr.c() {
619                             return FfiUnsafe {
620                                 ty: ty,
621                                 reason: "this union has unspecified layout",
622                                 help: Some("consider adding a #[repr(C)] attribute to this union"),
623                             };
624                         }
625
626                         if def.non_enum_variant().fields.is_empty() {
627                             return FfiUnsafe {
628                                 ty: ty,
629                                 reason: "this union has no fields",
630                                 help: Some("consider adding a field to this union"),
631                             };
632                         }
633
634                         let mut all_phantom = true;
635                         for field in &def.non_enum_variant().fields {
636                             let field_ty = cx.fully_normalize_associated_types_in(
637                                 &field.ty(cx, substs)
638                             );
639                             let r = self.check_type_for_ffi(cache, field_ty);
640                             match r {
641                                 FfiSafe => {
642                                     all_phantom = false;
643                                 }
644                                 FfiPhantom(..) => {}
645                                 FfiUnsafe { .. } => {
646                                     return r;
647                                 }
648                             }
649                         }
650
651                         if all_phantom { FfiPhantom(ty) } else { FfiSafe }
652                     }
653                     AdtKind::Enum => {
654                         if def.variants.is_empty() {
655                             // Empty enums are okay... although sort of useless.
656                             return FfiSafe;
657                         }
658
659                         // Check for a repr() attribute to specify the size of the
660                         // discriminant.
661                         if !def.repr.c() && def.repr.int.is_none() {
662                             // Special-case types like `Option<extern fn()>`.
663                             if !is_repr_nullable_ptr(cx, def, substs) {
664                                 return FfiUnsafe {
665                                     ty: ty,
666                                     reason: "enum has no representation hint",
667                                     help: Some("consider adding a #[repr(...)] attribute \
668                                                 to this enum"),
669                                 };
670                             }
671                         }
672
673                         // Check the contained variants.
674                         for variant in &def.variants {
675                             for field in &variant.fields {
676                                 let arg = cx.fully_normalize_associated_types_in(
677                                     &field.ty(cx, substs)
678                                 );
679                                 let r = self.check_type_for_ffi(cache, arg);
680                                 match r {
681                                     FfiSafe => {}
682                                     FfiUnsafe { .. } => {
683                                         return r;
684                                     }
685                                     FfiPhantom(..) => {
686                                         return FfiUnsafe {
687                                             ty: ty,
688                                             reason: "this enum contains a PhantomData field",
689                                             help: None,
690                                         };
691                                     }
692                                 }
693                             }
694                         }
695                         FfiSafe
696                     }
697                 }
698             }
699
700             ty::TyChar => FfiUnsafe {
701                 ty: ty,
702                 reason: "the `char` type has no C equivalent",
703                 help: Some("consider using `u32` or `libc::wchar_t` instead"),
704             },
705
706             ty::TyInt(ast::IntTy::I128) | ty::TyUint(ast::UintTy::U128) => FfiUnsafe {
707                 ty: ty,
708                 reason: "128-bit integers don't currently have a known stable ABI",
709                 help: None,
710             },
711
712             // Primitive types with a stable representation.
713             ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
714
715             ty::TySlice(_) => FfiUnsafe {
716                 ty: ty,
717                 reason: "slices have no C equivalent",
718                 help: Some("consider using a raw pointer instead"),
719             },
720
721             ty::TyDynamic(..) => FfiUnsafe {
722                 ty: ty,
723                 reason: "trait objects have no C equivalent",
724                 help: None,
725             },
726
727             ty::TyStr => FfiUnsafe {
728                 ty: ty,
729                 reason: "string slices have no C equivalent",
730                 help: Some("consider using `*const u8` and a length instead"),
731             },
732
733             ty::TyTuple(..) => FfiUnsafe {
734                 ty: ty,
735                 reason: "tuples have unspecified layout",
736                 help: Some("consider using a struct instead"),
737             },
738
739             ty::TyRawPtr(ref m) |
740             ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
741
742             ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
743
744             ty::TyFnPtr(sig) => {
745                 match sig.abi() {
746                     Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
747                         return FfiUnsafe {
748                             ty: ty,
749                             reason: "this function pointer has Rust-specific calling convention",
750                             help: Some("consider using an `fn \"extern\"(...) -> ...` \
751                                         function pointer instead"),
752                         }
753                     }
754                     _ => {}
755                 }
756
757                 let sig = cx.erase_late_bound_regions(&sig);
758                 if !sig.output().is_nil() {
759                     let r = self.check_type_for_ffi(cache, sig.output());
760                     match r {
761                         FfiSafe => {}
762                         _ => {
763                             return r;
764                         }
765                     }
766                 }
767                 for arg in sig.inputs() {
768                     let r = self.check_type_for_ffi(cache, arg);
769                     match r {
770                         FfiSafe => {}
771                         _ => {
772                             return r;
773                         }
774                     }
775                 }
776                 FfiSafe
777             }
778
779             ty::TyForeign(..) => FfiSafe,
780
781             ty::TyParam(..) |
782             ty::TyInfer(..) |
783             ty::TyError |
784             ty::TyClosure(..) |
785             ty::TyGenerator(..) |
786             ty::TyGeneratorWitness(..) |
787             ty::TyProjection(..) |
788             ty::TyAnon(..) |
789             ty::TyFnDef(..) => bug!("Unexpected type in foreign function"),
790         }
791     }
792
793     fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
794         // it is only OK to use this function because extern fns cannot have
795         // any generic types right now:
796         let ty = self.cx.tcx.fully_normalize_associated_types_in(&ty);
797
798         match self.check_type_for_ffi(&mut FxHashSet(), ty) {
799             FfiResult::FfiSafe => {}
800             FfiResult::FfiPhantom(ty) => {
801                 self.cx.span_lint(IMPROPER_CTYPES,
802                                   sp,
803                                   &format!("`extern` block uses type `{}` which is not FFI-safe: \
804                                             composed only of PhantomData", ty));
805             }
806             FfiResult::FfiUnsafe { ty: unsafe_ty, reason, help } => {
807                 let msg = format!("`extern` block uses type `{}` which is not FFI-safe: {}",
808                                   unsafe_ty, reason);
809                 let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
810                 if let Some(s) = help {
811                     diag.help(s);
812                 }
813                 if let ty::TyAdt(def, _) = unsafe_ty.sty {
814                     if let Some(sp) = self.cx.tcx.hir.span_if_local(def.did) {
815                         diag.span_note(sp, "type defined here");
816                     }
817                 }
818                 diag.emit();
819             }
820         }
821     }
822
823     fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) {
824         let def_id = self.cx.tcx.hir.local_def_id(id);
825         let sig = self.cx.tcx.fn_sig(def_id);
826         let sig = self.cx.tcx.erase_late_bound_regions(&sig);
827
828         for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
829             self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
830         }
831
832         if let hir::Return(ref ret_hir) = decl.output {
833             let ret_ty = sig.output();
834             if !ret_ty.is_nil() {
835                 self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
836             }
837         }
838     }
839
840     fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) {
841         let def_id = self.cx.tcx.hir.local_def_id(id);
842         let ty = self.cx.tcx.type_of(def_id);
843         self.check_type_for_ffi_and_report_errors(span, ty);
844     }
845 }
846
847 #[derive(Copy, Clone)]
848 pub struct ImproperCTypes;
849
850 impl LintPass for ImproperCTypes {
851     fn get_lints(&self) -> LintArray {
852         lint_array!(IMPROPER_CTYPES)
853     }
854 }
855
856 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
857     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
858         let mut vis = ImproperCTypesVisitor { cx: cx };
859         if let hir::ItemForeignMod(ref nmod) = it.node {
860             if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
861                 for ni in &nmod.items {
862                     match ni.node {
863                         hir::ForeignItemFn(ref decl, _, _) => {
864                             vis.check_foreign_fn(ni.id, decl);
865                         }
866                         hir::ForeignItemStatic(ref ty, _) => {
867                             vis.check_foreign_static(ni.id, ty.span);
868                         }
869                         hir::ForeignItemType => ()
870                     }
871                 }
872             }
873         }
874     }
875 }
876
877 pub struct VariantSizeDifferences;
878
879 impl LintPass for VariantSizeDifferences {
880     fn get_lints(&self) -> LintArray {
881         lint_array!(VARIANT_SIZE_DIFFERENCES)
882     }
883 }
884
885 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
886     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
887         if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
888             if gens.params.iter().all(|param| param.is_lifetime_param()) {
889                 // sizes only make sense for non-generic types
890                 let item_def_id = cx.tcx.hir.local_def_id(it.id);
891                 let t = cx.tcx.type_of(item_def_id);
892                 let ty = cx.tcx.erase_regions(&t);
893                 let layout = cx.layout_of(ty).unwrap_or_else(|e| {
894                     bug!("failed to get layout for `{}`: {}", t, e)
895                 });
896
897                 if let layout::Variants::Tagged { ref variants, ref discr, .. } = layout.variants {
898                     let discr_size = discr.value.size(cx.tcx).bytes();
899
900                     debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
901                       t, layout.size.bytes(), layout);
902
903                     let (largest, slargest, largest_index) = enum_definition.variants
904                         .iter()
905                         .zip(variants)
906                         .map(|(variant, variant_layout)| {
907                             // Subtract the size of the enum discriminant
908                             let bytes = variant_layout.size.bytes()
909                                 .saturating_sub(discr_size);
910
911                             debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
912                             bytes
913                         })
914                         .enumerate()
915                         .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
916                             (size, l, idx)
917                         } else if size > s {
918                             (l, size, li)
919                         } else {
920                             (l, s, li)
921                         });
922
923                     // we only warn if the largest variant is at least thrice as large as
924                     // the second-largest.
925                     if largest > slargest * 3 && slargest > 0 {
926                         cx.span_lint(VARIANT_SIZE_DIFFERENCES,
927                                      enum_definition.variants[largest_index].span,
928                                      &format!("enum variant is more than three times larger \
929                                                ({} bytes) than the next largest",
930                                               largest));
931                     }
932                 }
933             }
934         }
935     }
936 }