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