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.
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.
11 #![allow(non_snake_case)]
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}
;
26 use std
::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}
;
36 register_long_diagnostics
! {
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.
43 let x: usize = -1isize as usize;
48 Alternatively you can use the `Wrapping` newtype
49 or the `wrapping_neg` operation that all
50 integral types support:
53 use std::num::Wrapping;
54 let x: Wrapping<usize> = -Wrapping(1);
56 let y: usize = 1.wrapping_neg();
65 "comparisons made useless by limits of the types involved"
71 "literal out of range for its type"
77 "shift exceeds the type's number of bits"
81 VARIANT_SIZE_DIFFERENCES
,
83 "detects enums with widely varying variant sizes"
86 #[derive(Copy, Clone)]
87 pub struct TypeLimits
{
88 /// Id of the last visited negated expression
89 negated_expr_id
: ast
::NodeId
,
93 pub fn new() -> TypeLimits
{
94 TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID }
98 impl LintPass
for TypeLimits
{
99 fn get_lints(&self) -> LintArray
{
100 lint_array
!(UNUSED_COMPARISONS
,
101 OVERFLOWING_LITERALS
,
106 impl LateLintPass
for TypeLimits
{
107 fn check_expr(&mut self, cx
: &LateContext
, e
: &hir
::Expr
) {
109 hir
::ExprUnary(hir
::UnNeg
, ref expr
) => {
110 if let hir
::ExprLit(ref lit
) = expr
.node
{
112 ast
::LitKind
::Int(_
, ast
::LitIntType
::Unsigned(_
)) => {
113 forbid_unsigned_negation(cx
, e
.span
);
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
);
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
);
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
;
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
,
137 "comparison is useless due to type limits");
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
)),
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
{
155 match eval_const_expr_partial(cx
.tcx
, &r
, ExprTypeChecked
, None
) {
156 Ok(ConstVal
::Integral(i
)) => {
166 cx
.span_lint(EXCEEDING_BITSHIFTS
,
168 "bitshift exceeds the type's number of bits");
173 hir
::ExprLit(ref lit
) => {
174 match cx
.tcx
.tables().node_id_to_type(e
.id
).sty
{
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
184 let (_
, max
) = int_ty_range(int_type
);
185 let negative
= self.negated_expr_id
== e
.id
;
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
,
193 &format
!("literal out of range for {:?}", t
));
201 let uint_type
= if let ast
::UintTy
::Us
= t
{
202 cx
.sess().target
.uint_type
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
,
213 if lit_val
< min
|| lit_val
> max
{
214 cx
.span_lint(OVERFLOWING_LITERALS
,
216 &format
!("literal out of range for {:?}", 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
) => {
231 if lit_val
< min
|| lit_val
> max
{
232 cx
.span_lint(OVERFLOWING_LITERALS
,
234 &format
!("literal out of range for {:?}", t
));
243 fn is_valid
<T
: cmp
::PartialOrd
>(binop
: hir
::BinOp
, v
: T
, min
: T
, max
: T
) -> bool
{
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
,
254 fn rev_binop(binop
: hir
::BinOp
) -> hir
::BinOp
{
255 codemap
::respan(binop
.span
,
257 hir
::BiLt
=> hir
::BiGt
,
258 hir
::BiLe
=> hir
::BiGe
,
259 hir
::BiGt
=> hir
::BiLt
,
260 hir
::BiGe
=> hir
::BiLe
,
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) {
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
),
277 fn uint_ty_range(uint_ty
: ast
::UintTy
) -> (u64, u64) {
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
),
287 fn float_ty_range(float_ty
: ast
::FloatTy
) -> (f64, f64) {
289 ast
::FloatTy
::F32
=> (f32::MIN
as f64, f32::MAX
as f64),
290 ast
::FloatTy
::F64
=> (f64::MIN
, f64::MAX
),
294 fn int_ty_bits(int_ty
: ast
::IntTy
, target_int_ty
: ast
::IntTy
) -> u64 {
296 ast
::IntTy
::Is
=> int_ty_bits(target_int_ty
, target_int_ty
),
298 ast
::IntTy
::I16
=> 16 as u64,
299 ast
::IntTy
::I32
=> 32,
300 ast
::IntTy
::I64
=> 64,
304 fn uint_ty_bits(uint_ty
: ast
::UintTy
, target_uint_ty
: ast
::UintTy
) -> u64 {
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,
314 fn check_limits
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
319 let (lit
, expr
, swap
) = match (&l
.node
, &r
.node
) {
320 (&hir
::ExprLit(_
), _
) => (l
, r
, true),
321 (_
, &hir
::ExprLit(_
)) => (r
, l
, false),
324 // Normalize the binop so that the literal is always on the RHS in
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
) => {
333 ast
::LitKind
::Int(v
, ast
::LitIntType
::Signed(_
)) |
334 ast
::LitKind
::Int(v
, ast
::LitIntType
::Unsuffixed
) => v
as i64,
340 is_valid(norm_binop
, lit_val
, min
, max
)
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
) => {
347 ast
::LitKind
::Int(v
, _
) => v
,
353 is_valid(norm_binop
, lit_val
, min
, max
)
359 fn is_comparison(binop
: hir
::BinOp
) -> bool
{
361 hir
::BiEq
| hir
::BiLt
| hir
::BiLe
| hir
::BiNe
| hir
::BiGe
| hir
::BiGt
=> true,
366 fn forbid_unsigned_negation(cx
: &LateContext
, span
: Span
) {
368 .struct_span_err_with_code(span
, "unary negation of unsigned integer", "E0519")
369 .span_help(span
, "use a cast or the `!` operator")
378 "proper use of libc types in foreign modules"
381 struct ImproperCTypesVisitor
<'a
, 'tcx
: 'a
> {
382 cx
: &'a LateContext
<'a
, 'tcx
>,
387 FfiUnsafe(&'
static str),
388 FfiBadStruct(DefId
, &'
static str),
389 FfiBadUnion(DefId
, &'
static str),
390 FfiBadEnum(DefId
, &'
static str),
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
>)
402 if def
.variants
.len() == 2 {
405 if def
.variants
[0].fields
.is_empty() {
407 } else if def
.variants
[1].fields
.is_empty() {
413 if def
.variants
[data_idx
].fields
.len() == 1 {
414 match def
.variants
[data_idx
].fields
[0].ty(tcx
, substs
).sty
{
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
;
435 // Protect against infinite recursion, for example
436 // `struct S(*mut S);`.
437 // FIXME: A recursion limit is necessary as well, for irregular
439 if !cache
.insert(ty
) {
444 ty
::TyAdt(def
, substs
) => {
445 match def
.adt_kind() {
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");
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");
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
);
465 FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
469 return FfiBadStruct(def
.did
, s
);
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");
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
);
487 FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
491 return FfiBadUnion(def
.did
, s
);
498 if def
.variants
.is_empty() {
499 // Empty enums are okay... although sort of useless.
503 // Check for a repr() attribute to specify the size of the
505 let repr_hints
= cx
.lookup_repr_hints(def
.did
);
506 match &repr_hints
[..] {
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");
517 if !hint
.is_ffi_safe() {
518 // FIXME: This shouldn't be reachable: we should check
520 return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
523 // Enum with an explicitly sized discriminant; either
524 // a C-style enum or a discriminated union.
526 // The layout of enum variants is implicitly repr(C).
527 // FIXME: Is that correct?
530 // FIXME: This shouldn't be reachable: we should check
532 return FfiUnsafe("enum has too many #[repr(...)] attributes");
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
);
543 FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
547 return FfiBadEnum(def
.did
, s
);
558 FfiUnsafe("found Rust type `char` in foreign module, while \
559 `u32` or `libc::wchar_t` should be used")
562 // Primitive types with a stable representation.
563 ty
::TyBool
| ty
::TyInt(..) | ty
::TyUint(..) | ty
::TyFloat(..) | ty
::TyNever
=> FfiSafe
,
566 FfiUnsafe("found Rust type Box<_> in foreign module, \
567 consider using a raw pointer instead")
571 FfiUnsafe("found Rust slice type in foreign module, \
572 consider using a raw pointer instead")
576 FfiUnsafe("found Rust trait type in foreign module, \
577 consider using a raw pointer instead")
581 FfiUnsafe("found Rust type `str` in foreign module; \
582 consider using a `*const libc::c_char`")
586 FfiUnsafe("found Rust tuple type in foreign module; \
587 consider using a struct instead")
590 ty
::TyRawPtr(ref m
) |
591 ty
::TyRef(_
, ref m
) => self.check_type_for_ffi(cache
, m
.ty
),
593 ty
::TyArray(ty
, _
) => self.check_type_for_ffi(cache
, ty
),
595 ty
::TyFnPtr(bare_fn
) => {
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 \
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
);
615 for arg
in sig
.inputs
{
616 let r
= self.check_type_for_ffi(cache
, arg
);
631 ty
::TyProjection(..) |
633 ty
::TyFnDef(..) => bug
!("Unexpected type in foreign function"),
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
);
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
);
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
,
652 &format
!("found non-foreign-function-safe member in struct \
653 marked #[repr(C)]: {}",
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
,
661 &format
!("found non-foreign-function-safe member in union \
662 marked #[repr(C)]: {}",
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
,
670 &format
!("found non-foreign-function-safe member in enum: {}",
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
);
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
);
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
);
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
);
701 #[derive(Copy, Clone)]
702 pub struct ImproperCTypes
;
704 impl LintPass
for ImproperCTypes
{
705 fn get_lints(&self) -> LintArray
{
706 lint_array
!(IMPROPER_CTYPES
)
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
{
717 hir
::ForeignItemFn(ref decl
, _
) => {
718 vis
.check_foreign_fn(ni
.id
, decl
);
720 hir
::ForeignItemStatic(ref ty
, _
) => {
721 vis
.check_foreign_static(ni
.id
, ty
.span
);
730 pub struct VariantSizeDifferences
;
732 impl LintPass
for VariantSizeDifferences
{
733 fn get_lints(&self) -> LintArray
{
734 lint_array
!(VARIANT_SIZE_DIFFERENCES
)
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
);
747 .unwrap_or_else(|e
| bug
!("failed to get layout for `{}`: {}", t
, e
))
750 if let Layout
::General { ref variants, ref size, discr, .. }
= *layout
{
751 let discr_size
= Primitive
::Int(discr
).size(&cx
.tcx
.data_layout
).bytes();
753 debug
!("enum `{}` is {} bytes large", t
, size
.bytes());
755 let (largest
, slargest
, largest_index
) = enum_definition
.variants
758 .map(|(variant
, variant_layout
)| {
759 // Subtract the size of the enum discriminant
760 let bytes
= variant_layout
.min_size
762 .saturating_sub(discr_size
);
764 debug
!("- variant `{}` is {} bytes large", variant
.node
.name
, bytes
);
768 .fold((0, 0, 0), |(l
, s
, li
), (idx
, size
)| if size
> l
{
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",