Auto merge of #22940 - Manishearth:rollup, r=Manishearth

This commit is contained in:
bors 2015-03-02 00:37:24 +00:00
commit 4b3b02f8f4
32 changed files with 592 additions and 329 deletions

View file

@ -39,7 +39,7 @@
//! distribution.
//!
//! * `rust_begin_unwind` - This function takes three arguments, a
//! `fmt::Arguments`, a `&str`, and a `uint`. These three arguments dictate
//! `fmt::Arguments`, a `&str`, and a `usize`. These three arguments dictate
//! the panic message, the file at which panic was invoked, and the line.
//! It is up to consumers of this core library to define this panic
//! function; it is only required to never return.
@ -88,14 +88,12 @@ mod int_macros;
#[macro_use]
mod uint_macros;
#[path = "num/int.rs"] pub mod int;
#[path = "num/isize.rs"] pub mod isize;
#[path = "num/i8.rs"] pub mod i8;
#[path = "num/i16.rs"] pub mod i16;
#[path = "num/i32.rs"] pub mod i32;
#[path = "num/i64.rs"] pub mod i64;
#[path = "num/uint.rs"] pub mod uint;
#[path = "num/usize.rs"] pub mod usize;
#[path = "num/u8.rs"] pub mod u8;
#[path = "num/u16.rs"] pub mod u16;

View file

@ -1,21 +0,0 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Deprecated: replaced by `isize`.
//!
//! The rollout of the new type will gradually take place over the
//! alpha cycle along with the development of clearer conventions
//! around integer types.
#![unstable(feature = "core")]
#![deprecated(since = "1.0.0", reason = "replaced by isize")]
#[cfg(target_pointer_width = "32")] int_module! { int, 32 }
#[cfg(target_pointer_width = "64")] int_module! { int, 64 }

View file

@ -1,20 +0,0 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Deprecated: replaced by `usize`.
//!
//! The rollout of the new type will gradually take place over the
//! alpha cycle along with the development of clearer conventions
//! around integer types.
#![unstable(feature = "core")]
#![deprecated(since = "1.0.0", reason = "replaced by usize")]
uint_module! { uint, int, ::int::BITS }

View file

@ -12,7 +12,7 @@ use core::iter::*;
use core::iter::order::*;
use core::iter::MinMaxResult::*;
use core::num::SignedInt;
use core::uint;
use core::usize;
use core::cmp;
use test::Bencher;
@ -292,7 +292,7 @@ fn test_unfoldr() {
fn test_cycle() {
let cycle_len = 3;
let it = count(0, 1).take(cycle_len).cycle();
assert_eq!(it.size_hint(), (uint::MAX, None));
assert_eq!(it.size_hint(), (usize::MAX, None));
for (i, x) in it.take(100).enumerate() {
assert_eq!(i % cycle_len, x);
}
@ -365,19 +365,19 @@ fn test_iterator_size_hint() {
let v2 = &[10, 11, 12];
let vi = v.iter();
assert_eq!(c.size_hint(), (uint::MAX, None));
assert_eq!(c.size_hint(), (usize::MAX, None));
assert_eq!(vi.clone().size_hint(), (10, Some(10)));
assert_eq!(c.clone().take(5).size_hint(), (5, Some(5)));
assert_eq!(c.clone().skip(5).size_hint().1, None);
assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None));
assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None));
assert_eq!(c.clone().enumerate().size_hint(), (uint::MAX, None));
assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (uint::MAX, None));
assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None));
assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None));
assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10)));
assert_eq!(c.clone().scan(0, |_,_| Some(0)).size_hint(), (0, None));
assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None));
assert_eq!(c.clone().map(|_| 0).size_hint(), (uint::MAX, None));
assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None));
assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None));
assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5)));
@ -753,7 +753,7 @@ fn test_range() {
assert_eq!((0..100).size_hint(), (100, Some(100)));
// this test is only meaningful when sizeof uint < sizeof u64
assert_eq!((uint::MAX - 1..uint::MAX).size_hint(), (1, Some(1)));
assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1)));
assert_eq!((-10..-1).size_hint(), (9, Some(9)));
assert_eq!((-1..-10).size_hint(), (0, Some(0)));
}

View file

@ -1,11 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
int_module!(int, int);

View file

@ -12,7 +12,7 @@ macro_rules! int_module { ($T:ty, $T_i:ident) => (
#[cfg(test)]
mod tests {
use core::$T_i::*;
use core::int;
use core::isize;
use core::num::{FromStrRadix, Int, SignedInt};
use core::ops::{Shl, Shr, Not, BitXor, BitAnd, BitOr};
use num;
@ -153,7 +153,7 @@ mod tests {
fn test_signed_checked_div() {
assert!(10.checked_div(2) == Some(5));
assert!(5.checked_div(0) == None);
assert!(int::MIN.checked_div(-1) == None);
assert!(isize::MIN.checked_div(-1) == None);
}
#[test]

View file

@ -21,7 +21,6 @@ mod i8;
mod i16;
mod i32;
mod i64;
mod int;
#[macro_use]
mod uint_macros;
@ -30,7 +29,6 @@ mod u8;
mod u16;
mod u32;
mod u64;
mod uint;
/// Helper function for testing numeric operations
pub fn test_num<T>(ten: T, two: T) where

View file

@ -1,11 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
uint_module!(uint, uint);

View file

@ -963,7 +963,7 @@ fn test_split_within() {
"little lamb".to_string(),
"Little lamb".to_string()
]);
t("\nMary had a little lamb\nLittle lamb\n", ::std::uint::MAX,
t("\nMary had a little lamb\nLittle lamb\n", ::std::usize::MAX,
&["Mary had a little lamb\nLittle lamb".to_string()]);
}

View file

@ -1115,7 +1115,6 @@ pub mod types {
pub mod posix88 {
pub type off_t = i64;
pub type dev_t = u32;
pub type ino_t = u32;
pub type pid_t = i32;
pub type uid_t = u32;
pub type gid_t = u32;

View file

@ -12,18 +12,18 @@
use core::prelude::*;
use core::char;
use core::int;
use core::uint;
use core::isize;
use core::usize;
use {Rand,Rng};
impl Rand for int {
impl Rand for isize {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> int {
if int::BITS == 32 {
rng.gen::<i32>() as int
fn rand<R: Rng>(rng: &mut R) -> isize {
if isize::BITS == 32 {
rng.gen::<i32>() as isize
} else {
rng.gen::<i64>() as int
rng.gen::<i64>() as isize
}
}
}
@ -56,13 +56,13 @@ impl Rand for i64 {
}
}
impl Rand for uint {
impl Rand for usize {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> uint {
if uint::BITS == 32 {
rng.gen::<u32>() as uint
fn rand<R: Rng>(rng: &mut R) -> usize {
if usize::BITS == 32 {
rng.gen::<u32>() as usize
} else {
rng.gen::<u64>() as uint
rng.gen::<u64>() as usize
}
}
}

View file

@ -612,7 +612,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
}
fn visit_trait_item(&mut self, m: &ast::TraitItem) {
run_lints!(self, check_trait_method, m);
run_lints!(self, check_trait_item, m);
visit::walk_trait_item(self, m);
}

View file

@ -144,7 +144,7 @@ pub trait LintPass {
fn check_fn(&mut self, _: &Context,
_: FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
fn check_ty_method(&mut self, _: &Context, _: &ast::TypeMethod) { }
fn check_trait_method(&mut self, _: &Context, _: &ast::TraitItem) { }
fn check_trait_item(&mut self, _: &Context, _: &ast::TraitItem) { }
fn check_struct_def(&mut self, _: &Context,
_: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
fn check_struct_def_post(&mut self, _: &Context,

View file

@ -51,8 +51,8 @@
//! enclosing function. On the way down the tree, it identifies those AST
//! nodes and variable IDs that will be needed for the liveness analysis
//! and assigns them contiguous IDs. The liveness id for an AST node is
//! called a `live_node` (it's a newtype'd uint) and the id for a variable
//! is called a `variable` (another newtype'd uint).
//! called a `live_node` (it's a newtype'd usize) and the id for a variable
//! is called a `variable` (another newtype'd usize).
//!
//! On the way back up the tree, as we are about to exit from a function
//! declaration we allocate a `liveness` instance. Now that we know
@ -118,7 +118,7 @@ use middle::ty::ClosureTyper;
use lint;
use util::nodemap::NodeMap;
use std::{fmt, old_io, uint};
use std::{fmt, old_io, usize};
use std::rc::Rc;
use std::iter::repeat;
use syntax::ast::{self, NodeId, Expr};
@ -138,17 +138,17 @@ enum LoopKind<'a> {
}
#[derive(Copy, PartialEq)]
struct Variable(uint);
struct Variable(usize);
#[derive(Copy, PartialEq)]
struct LiveNode(uint);
struct LiveNode(usize);
impl Variable {
fn get(&self) -> uint { let Variable(v) = *self; v }
fn get(&self) -> usize { let Variable(v) = *self; v }
}
impl LiveNode {
fn get(&self) -> uint { let LiveNode(v) = *self; v }
fn get(&self) -> usize { let LiveNode(v) = *self; v }
}
impl Clone for LiveNode {
@ -232,11 +232,11 @@ impl fmt::Debug for Variable {
impl LiveNode {
fn is_valid(&self) -> bool {
self.get() != uint::MAX
self.get() != usize::MAX
}
}
fn invalid_node() -> LiveNode { LiveNode(uint::MAX) }
fn invalid_node() -> LiveNode { LiveNode(usize::MAX) }
struct CaptureInfo {
ln: LiveNode,
@ -260,8 +260,8 @@ enum VarKind {
struct IrMaps<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
num_live_nodes: uint,
num_vars: uint,
num_live_nodes: usize,
num_vars: usize,
live_node_map: NodeMap<LiveNode>,
variable_map: NodeMap<Variable>,
capture_info_map: NodeMap<Rc<Vec<CaptureInfo>>>,
@ -540,9 +540,9 @@ struct Specials {
clean_exit_var: Variable
}
static ACC_READ: uint = 1;
static ACC_WRITE: uint = 2;
static ACC_USE: uint = 4;
static ACC_READ: u32 = 1;
static ACC_WRITE: u32 = 2;
static ACC_USE: u32 = 4;
struct Liveness<'a, 'tcx: 'a> {
ir: &'a mut IrMaps<'a, 'tcx>,
@ -631,7 +631,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
succ
}
fn idx(&self, ln: LiveNode, var: Variable) -> uint {
fn idx(&self, ln: LiveNode, var: Variable) -> usize {
ln.get() * self.ir.num_vars + var.get()
}
@ -670,7 +670,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
fn indices2<F>(&mut self, ln: LiveNode, succ_ln: LiveNode, mut op: F) where
F: FnMut(&mut Liveness<'a, 'tcx>, uint, uint),
F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize),
{
let node_base_idx = self.idx(ln, Variable(0));
let succ_base_idx = self.idx(succ_ln, Variable(0));
@ -684,7 +684,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
ln: LiveNode,
mut test: F)
-> old_io::IoResult<()> where
F: FnMut(uint) -> LiveNode,
F: FnMut(usize) -> LiveNode,
{
let node_base_idx = self.idx(ln, Variable(0));
for var_idx in 0..self.ir.num_vars {
@ -807,7 +807,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
// Either read, write, or both depending on the acc bitset
fn acc(&mut self, ln: LiveNode, var: Variable, acc: uint) {
fn acc(&mut self, ln: LiveNode, var: Variable, acc: u32) {
debug!("{:?} accesses[{:x}] {:?}: {}",
ln, acc, var, self.ln_str(ln));
@ -1283,7 +1283,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
// see comment on propagate_through_lvalue()
fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: uint)
fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
-> LiveNode {
match expr.node {
ast::ExprPath(..) => {
@ -1298,7 +1298,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
}
fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: uint)
fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
-> LiveNode {
match self.ir.tcx.def_map.borrow()[expr.id].full_def() {
DefLocal(nid) => {

View file

@ -28,8 +28,6 @@
//! Use the former for unit-like structs and the latter for structs with
//! a `pub fn new()`.
use self::MethodContext::*;
use metadata::{csearch, decoder};
use middle::def::*;
use middle::subst::Substs;
@ -228,7 +226,9 @@ impl LintPass for TypeLimits {
ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => {
let int_type = if let ast::TyIs(_) = t {
cx.sess().target.int_type
} else { t };
} else {
t
};
let (min, max) = int_ty_range(int_type);
let negative = self.negated_expr_id == e.id;
@ -245,14 +245,16 @@ impl LintPass for TypeLimits {
ty::ty_uint(t) => {
let uint_type = if let ast::TyUs(_) = t {
cx.sess().target.uint_type
} else { t };
} else {
t
};
let (min, max) = uint_ty_range(uint_type);
let lit_val: u64 = match lit.node {
ast::LitByte(_v) => return, // _v is u8, within range by definition
ast::LitInt(v, _) => v,
_ => panic!()
};
if lit_val < min || lit_val > max {
if lit_val < min || lit_val > max {
cx.span_lint(OVERFLOWING_LITERALS, e.span,
&*format!("literal out of range for {:?}", t));
}
@ -262,9 +264,9 @@ impl LintPass for TypeLimits {
let lit_val: f64 = match lit.node {
ast::LitFloat(ref v, _) |
ast::LitFloatUnsuffixed(ref v) => {
match v.parse().ok() {
Some(f) => f,
None => return
match v.parse() {
Ok(f) => f,
Err(_) => return
}
}
_ => panic!()
@ -302,52 +304,52 @@ impl LintPass for TypeLimits {
})
}
// for int & uint, be conservative with the warnings, so that the
// for isize & usize, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms
fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
match int_ty {
ast::TyIs(_) => (i64::MIN, i64::MAX),
ast::TyI8 => (i8::MIN as i64, i8::MAX as i64),
ast::TyI16 => (i16::MIN as i64, i16::MAX as i64),
ast::TyI32 => (i32::MIN as i64, i32::MAX as i64),
ast::TyI64 => (i64::MIN, i64::MAX)
ast::TyIs(_) => (i64::MIN, i64::MAX),
ast::TyI8 => (i8::MIN as i64, i8::MAX as i64),
ast::TyI16 => (i16::MIN as i64, i16::MAX as i64),
ast::TyI32 => (i32::MIN as i64, i32::MAX as i64),
ast::TyI64 => (i64::MIN, i64::MAX)
}
}
fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
match uint_ty {
ast::TyUs(_) => (u64::MIN, u64::MAX),
ast::TyU8 => (u8::MIN as u64, u8::MAX as u64),
ast::TyU16 => (u16::MIN as u64, u16::MAX as u64),
ast::TyU32 => (u32::MIN as u64, u32::MAX as u64),
ast::TyU64 => (u64::MIN, u64::MAX)
ast::TyUs(_) => (u64::MIN, u64::MAX),
ast::TyU8 => (u8::MIN as u64, u8::MAX as u64),
ast::TyU16 => (u16::MIN as u64, u16::MAX as u64),
ast::TyU32 => (u32::MIN as u64, u32::MAX as u64),
ast::TyU64 => (u64::MIN, u64::MAX)
}
}
fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
match float_ty {
ast::TyF32 => (f32::MIN as f64, f32::MAX as f64),
ast::TyF64 => (f64::MIN, f64::MAX)
ast::TyF32 => (f32::MIN as f64, f32::MAX as f64),
ast::TyF64 => (f64::MIN, f64::MAX)
}
}
fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 {
match int_ty {
ast::TyIs(_) => int_ty_bits(target_int_ty, target_int_ty),
ast::TyI8 => i8::BITS as u64,
ast::TyI16 => i16::BITS as u64,
ast::TyI32 => i32::BITS as u64,
ast::TyI64 => i64::BITS as u64
ast::TyIs(_) => int_ty_bits(target_int_ty, target_int_ty),
ast::TyI8 => i8::BITS as u64,
ast::TyI16 => i16::BITS as u64,
ast::TyI32 => i32::BITS as u64,
ast::TyI64 => i64::BITS as u64
}
}
fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 {
match uint_ty {
ast::TyUs(_) => uint_ty_bits(target_uint_ty, target_uint_ty),
ast::TyU8 => u8::BITS as u64,
ast::TyU16 => u16::BITS as u64,
ast::TyU32 => u32::BITS as u64,
ast::TyU64 => u64::BITS as u64
ast::TyUs(_) => uint_ty_bits(target_uint_ty, target_uint_ty),
ast::TyU8 => u8::BITS as u64,
ast::TyU16 => u16::BITS as u64,
ast::TyU32 => u32::BITS as u64,
ast::TyU64 => u64::BITS as u64
}
}
@ -360,7 +362,11 @@ impl LintPass for TypeLimits {
};
// Normalize the binop so that the literal is always on the RHS in
// the comparison
let norm_binop = if swap { rev_binop(binop) } else { binop };
let norm_binop = if swap {
rev_binop(binop)
} else {
binop
};
match ty::expr_ty(tcx, expr).sty {
ty::ty_int(int_ty) => {
let (min, max) = int_ty_range(int_ty);
@ -432,9 +438,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if !ty::is_ffi_safe(self.cx.tcx, tty) {
self.cx.span_lint(IMPROPER_CTYPES, sp,
"found type without foreign-function-safe
representation annotation in foreign module, consider \
adding a #[repr(...)] attribute to the type");
"found type without foreign-function-safe \
representation annotation in foreign module, consider \
adding a #[repr(...)] attribute to the type");
}
}
_ => ()
@ -595,7 +601,7 @@ impl LintPass for RawPointerDerive {
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
if !attr::contains_name(&item.attrs, "automatically_derived") {
return
return;
}
let did = match item.node {
ast::ItemImpl(_, _, _, ref t_ref_opt, _, _) => {
@ -603,7 +609,7 @@ impl LintPass for RawPointerDerive {
if let &Some(ref trait_ref) = t_ref_opt {
let def_id = ty::trait_ref_to_def_id(cx.tcx, trait_ref);
if Some(def_id) == cx.tcx.lang_items.copy_trait() {
return
return;
}
}
@ -615,12 +621,16 @@ impl LintPass for RawPointerDerive {
}
_ => return,
};
if !ast_util::is_local(did) { return }
if !ast_util::is_local(did) {
return;
}
let item = match cx.tcx.map.find(did.node) {
Some(ast_map::NodeItem(item)) => item,
_ => return,
};
if !self.checked_raw_pointers.insert(item.id) { return }
if !self.checked_raw_pointers.insert(item.id) {
return;
}
match item.node {
ast::ItemStruct(..) | ast::ItemEnum(..) => {
let mut visitor = RawPtrDeriveVisitor { cx: cx };
@ -646,6 +656,7 @@ impl LintPass for UnusedAttributes {
}
fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
// Note that check_name() marks the attribute as used if it matches.
for &(ref name, ty) in KNOWN_ATTRIBUTES {
match ty {
AttributeType::Whitelisted
@ -730,23 +741,24 @@ impl LintPass for UnusedResults {
}
let t = ty::expr_ty(cx.tcx, expr);
let mut warned = false;
match t.sty {
let warned = match t.sty {
ty::ty_tup(ref tys) if tys.is_empty() => return,
ty::ty_bool => return,
ty::ty_struct(did, _) |
ty::ty_enum(did, _) => {
if ast_util::is_local(did) {
if let ast_map::NodeItem(it) = cx.tcx.map.get(did.node) {
warned |= check_must_use(cx, &it.attrs, s.span);
check_must_use(cx, &it.attrs, s.span)
} else {
false
}
} else {
let attrs = csearch::get_item_attrs(&cx.sess().cstore, did);
warned |= check_must_use(cx, &attrs[..], s.span);
check_must_use(cx, &attrs[..], s.span)
}
}
_ => {}
}
_ => false,
};
if !warned {
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
}
@ -785,7 +797,9 @@ impl NonCamelCaseTypes {
fn check_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
fn is_camel_case(ident: ast::Ident) -> bool {
let ident = token::get_ident(ident);
if ident.is_empty() { return true; }
if ident.is_empty() {
return true;
}
let ident = ident.trim_matches('_');
// start with a non-lowercase letter rather than non-uppercase
@ -795,8 +809,11 @@ impl NonCamelCaseTypes {
fn to_camel_case(s: &str) -> String {
s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)|
if i == 0 { c.to_uppercase() }
else { c }
if i == 0 {
c.to_uppercase()
} else {
c
}
)).collect()
}
@ -820,11 +837,13 @@ impl LintPass for NonCamelCaseTypes {
}
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
let has_extern_repr = it.attrs.iter().map(|attr| {
let has_extern_repr = it.attrs.iter().any(|attr| {
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
.any(|r| r == &attr::ReprExtern)
}).any(|x| x);
if has_extern_repr { return }
});
if has_extern_repr {
return;
}
match it.node {
ast::ItemTy(..) | ast::ItemStruct(..) => {
@ -834,7 +853,9 @@ impl LintPass for NonCamelCaseTypes {
self.check_case(cx, "trait", it.ident, it.span)
}
ast::ItemEnum(ref enum_definition, _) => {
if has_extern_repr { return }
if has_extern_repr {
return;
}
self.check_case(cx, "type", it.ident, it.span);
for variant in &enum_definition.variants {
self.check_case(cx, "variant", variant.node.name, variant.span);
@ -866,32 +887,28 @@ fn method_context(cx: &Context, m: &ast::Method) -> MethodContext {
match cx.tcx.impl_or_trait_items.borrow().get(&did).cloned() {
None => cx.sess().span_bug(m.span, "missing method descriptor?!"),
Some(md) => {
match md {
ty::MethodTraitItem(md) => {
match md.container {
ty::TraitContainer(..) => TraitDefaultImpl,
ty::ImplContainer(cid) => {
match ty::impl_trait_ref(cx.tcx, cid) {
Some(..) => TraitImpl,
None => PlainImpl
}
}
}
}
ty::TypeTraitItem(typedef) => {
match typedef.container {
ty::TraitContainer(..) => TraitDefaultImpl,
ty::ImplContainer(cid) => {
match ty::impl_trait_ref(cx.tcx, cid) {
Some(..) => TraitImpl,
None => PlainImpl
}
}
Some(ty::MethodTraitItem(md)) => {
match md.container {
ty::TraitContainer(..) => MethodContext::TraitDefaultImpl,
ty::ImplContainer(cid) => {
match ty::impl_trait_ref(cx.tcx, cid) {
Some(..) => MethodContext::TraitImpl,
None => MethodContext::PlainImpl
}
}
}
}
},
Some(ty::TypeTraitItem(typedef)) => {
match typedef.container {
ty::TraitContainer(..) => MethodContext::TraitDefaultImpl,
ty::ImplContainer(cid) => {
match ty::impl_trait_ref(cx.tcx, cid) {
Some(..) => MethodContext::TraitImpl,
None => MethodContext::PlainImpl
}
}
}
},
}
}
@ -912,12 +929,16 @@ impl NonSnakeCase {
if c == '_' {
words.push(String::new());
true
} else { false }
} else {
false
}
});
for s in str.split('_') {
let mut last_upper = false;
let mut buf = String::new();
if s.is_empty() { continue; }
if s.is_empty() {
continue;
}
for ch in s.chars() {
if !buf.is_empty() && buf != "'"
&& ch.is_uppercase()
@ -936,7 +957,9 @@ impl NonSnakeCase {
fn check_snake_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
fn is_snake_case(ident: ast::Ident) -> bool {
let ident = token::get_ident(ident);
if ident.is_empty() { return true; }
if ident.is_empty() {
return true;
}
let ident = ident.trim_left_matches('\'');
let ident = ident.trim_matches('_');
@ -979,14 +1002,17 @@ impl LintPass for NonSnakeCase {
_: &ast::Block, span: Span, _: ast::NodeId) {
match fk {
visit::FkMethod(ident, _, m) => match method_context(cx, m) {
PlainImpl
=> self.check_snake_case(cx, "method", ident, span),
TraitDefaultImpl
=> self.check_snake_case(cx, "trait method", ident, span),
MethodContext::PlainImpl => {
self.check_snake_case(cx, "method", ident, span)
},
MethodContext::TraitDefaultImpl => {
self.check_snake_case(cx, "trait method", ident, span)
},
_ => (),
},
visit::FkItemFn(ident, _, _, _)
=> self.check_snake_case(cx, "function", ident, span),
visit::FkItemFn(ident, _, _, _) => {
self.check_snake_case(cx, "function", ident, span)
},
_ => (),
}
}
@ -1015,7 +1041,7 @@ impl LintPass for NonSnakeCase {
}
fn check_struct_def(&mut self, cx: &Context, s: &ast::StructDef,
_: ast::Ident, _: &ast::Generics, _: ast::NodeId) {
_: ast::Ident, _: &ast::Generics, _: ast::NodeId) {
for sf in &s.fields {
if let ast::StructField_ { kind: ast::NamedField(ident, _), .. } = sf.node {
self.check_snake_case(cx, "structure field", ident, sf.span);
@ -1094,13 +1120,12 @@ pub struct UnusedParens;
impl UnusedParens {
fn check_unused_parens_core(&self, cx: &Context, value: &ast::Expr, msg: &str,
struct_lit_needs_parens: bool) {
struct_lit_needs_parens: bool) {
if let ast::ExprParen(ref inner) = value.node {
let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&**inner);
if !necessary {
cx.span_lint(UNUSED_PARENS, value.span,
&format!("unnecessary parentheses around {}",
msg))
&format!("unnecessary parentheses around {}", msg))
}
}
@ -1193,26 +1218,17 @@ impl LintPass for UnusedImportBraces {
}
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
match item.node {
ast::ItemUse(ref view_path) => {
match view_path.node {
ast::ViewPathList(_, ref items) => {
if items.len() == 1 {
match items[0].node {
ast::PathListIdent {ref name, ..} => {
let m = format!("braces around {} is unnecessary",
&token::get_ident(*name));
cx.span_lint(UNUSED_IMPORT_BRACES, item.span,
&m[..]);
},
_ => ()
}
}
if let ast::ItemUse(ref view_path) = item.node {
if let ast::ViewPathList(_, ref items) = view_path.node {
if items.len() == 1 {
if let ast::PathListIdent {ref name, ..} = items[0].node {
let m = format!("braces around {} is unnecessary",
&token::get_ident(*name));
cx.span_lint(UNUSED_IMPORT_BRACES, item.span,
&m[..]);
}
_ => ()
}
},
_ => ()
}
}
}
}
@ -1234,9 +1250,10 @@ impl LintPass for NonShorthandFieldPatterns {
fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) {
let def_map = cx.tcx.def_map.borrow();
if let ast::PatStruct(_, ref v, _) = pat.node {
let field_pats = v.iter()
.filter(|fieldpat| !fieldpat.node.is_shorthand)
.filter(|fieldpat| {
let field_pats = v.iter().filter(|fieldpat| {
if fieldpat.node.is_shorthand {
return false;
}
let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def());
def == Some(def::DefLocal(fieldpat.node.pat.id))
});
@ -1482,10 +1499,14 @@ impl MissingDoc {
desc: &'static str) {
// If we're building a test harness, then warning about
// documentation is probably not really relevant right now.
if cx.sess().opts.test { return }
if cx.sess().opts.test {
return;
}
// `#[doc(hidden)]` disables missing_docs check.
if self.doc_hidden() { return }
if self.doc_hidden() {
return;
}
// Only check publicly-visible items, using the result from the privacy pass.
// It's an option so the crate root can also use this function (it doesn't
@ -1504,7 +1525,7 @@ impl MissingDoc {
});
if !has_doc {
cx.span_lint(MISSING_DOCS, sp,
&format!("missing documentation for {}", desc));
&format!("missing documentation for {}", desc));
}
}
}
@ -1528,20 +1549,19 @@ impl LintPass for MissingDoc {
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
}
fn check_struct_def(&mut self, _: &Context,
_: &ast::StructDef, _: ast::Ident, _: &ast::Generics, id: ast::NodeId) {
fn check_struct_def(&mut self, _: &Context, _: &ast::StructDef,
_: ast::Ident, _: &ast::Generics, id: ast::NodeId) {
self.struct_def_stack.push(id);
}
fn check_struct_def_post(&mut self, _: &Context,
_: &ast::StructDef, _: ast::Ident, _: &ast::Generics, id: ast::NodeId) {
fn check_struct_def_post(&mut self, _: &Context, _: &ast::StructDef,
_: ast::Ident, _: &ast::Generics, id: ast::NodeId) {
let popped = self.struct_def_stack.pop().expect("empty struct_def_stack");
assert!(popped == id);
}
fn check_crate(&mut self, cx: &Context, krate: &ast::Crate) {
self.check_missing_docs_attrs(cx, None, &krate.attrs,
krate.span, "crate");
self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate");
}
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
@ -1554,30 +1574,28 @@ impl LintPass for MissingDoc {
ast::ItemTy(..) => "a type alias",
_ => return
};
self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs,
it.span, desc);
self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc);
}
fn check_fn(&mut self, cx: &Context,
fk: visit::FnKind, _: &ast::FnDecl,
_: &ast::Block, _: Span, _: ast::NodeId) {
fn check_fn(&mut self, cx: &Context, fk: visit::FnKind, _: &ast::FnDecl,
_: &ast::Block, _: Span, _: ast::NodeId) {
if let visit::FkMethod(_, _, m) = fk {
// If the method is an impl for a trait, don't doc.
if method_context(cx, m) == TraitImpl { return; }
if method_context(cx, m) == MethodContext::TraitImpl {
return;
}
// Otherwise, doc according to privacy. This will also check
// doc for default methods defined on traits.
self.check_missing_docs_attrs(cx, Some(m.id), &m.attrs,
m.span, "a method");
self.check_missing_docs_attrs(cx, Some(m.id), &m.attrs, m.span, "a method");
}
}
fn check_ty_method(&mut self, cx: &Context, tm: &ast::TypeMethod) {
self.check_missing_docs_attrs(cx, Some(tm.id), &tm.attrs,
tm.span, "a type method");
self.check_missing_docs_attrs(cx, Some(tm.id), &tm.attrs, tm.span, "a type method");
}
fn check_trait_method(&mut self, cx: &Context, it: &ast::TraitItem) {
fn check_trait_item(&mut self, cx: &Context, it: &ast::TraitItem) {
if let ast::TraitItem::TypeTraitItem(ref ty) = *it {
let assoc_ty = &ty.ty_param;
self.check_missing_docs_attrs(cx, Some(assoc_ty.id), &ty.attrs,
@ -1598,8 +1616,7 @@ impl LintPass for MissingDoc {
}
fn check_variant(&mut self, cx: &Context, v: &ast::Variant, _: &ast::Generics) {
self.check_missing_docs_attrs(cx, Some(v.node.id), &v.node.attrs,
v.span, "a variant");
self.check_missing_docs_attrs(cx, Some(v.node.id), &v.node.attrs, v.span, "a variant");
assert!(!self.in_variant);
self.in_variant = true;
}
@ -1626,18 +1643,18 @@ impl LintPass for MissingCopyImplementations {
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
if !cx.exported_items.contains(&item.id) {
return
return;
}
if cx.tcx
.destructor_for_type
.borrow()
.contains_key(&ast_util::local_def(item.id)) {
return
return;
}
let ty = match item.node {
ast::ItemStruct(_, ref ast_generics) => {
if ast_generics.is_parameterized() {
return
return;
}
ty::mk_struct(cx.tcx,
ast_util::local_def(item.id),
@ -1645,7 +1662,7 @@ impl LintPass for MissingCopyImplementations {
}
ast::ItemEnum(_, ref ast_generics) => {
if ast_generics.is_parameterized() {
return
return;
}
ty::mk_enum(cx.tcx,
ast_util::local_def(item.id),
@ -1655,7 +1672,7 @@ impl LintPass for MissingCopyImplementations {
};
let parameter_environment = ty::empty_parameter_environment(cx.tcx);
if !ty::type_moves_by_default(&parameter_environment, item.span, ty) {
return
return;
}
if ty::can_type_implement_copy(&parameter_environment, item.span, ty).is_ok() {
cx.span_lint(MISSING_COPY_IMPLEMENTATIONS,
@ -1709,10 +1726,10 @@ impl LintPass for MissingDebugImplementations {
let impls = match impls.get(&debug) {
Some(impls) => {
impls.borrow().iter()
.filter(|d| d.krate == ast::LOCAL_CRATE)
.filter_map(|d| ty::ty_to_def_id(ty::node_id_to_type(cx.tcx, d.node)))
.map(|d| d.node)
.collect()
.filter(|d| d.krate == ast::LOCAL_CRATE)
.filter_map(|d| ty::ty_to_def_id(ty::node_id_to_type(cx.tcx, d.node)))
.map(|d| d.node)
.collect()
}
None => NodeSet(),
};
@ -1741,8 +1758,7 @@ pub struct Stability;
impl Stability {
fn lint(&self, cx: &Context, _id: ast::DefId, span: Span, stability: &Option<attr::Stability>) {
// deprecated attributes apply in-crate and cross-crate
// Deprecated attributes apply in-crate and cross-crate.
let (lint, label) = match *stability {
Some(attr::Stability { deprecated_since: Some(_), .. }) =>
(DEPRECATED, "deprecated"),
@ -1857,25 +1873,27 @@ impl LintPass for UnconditionalRecursion {
let mut visited = BitSet::new();
while let Some(idx) = work_queue.pop() {
let cfg_id = idx.node_id();
if idx == cfg.exit {
// found a path!
reached_exit_without_self_call = true;
break
} else if visited.contains(&cfg_id) {
break;
}
let cfg_id = idx.node_id();
if visited.contains(&cfg_id) {
// already done
continue
continue;
}
visited.insert(cfg_id);
let node_id = cfg.graph.node_data(idx).id();
// is this a recursive call?
if node_id != ast::DUMMY_NODE_ID && checker(cx.tcx, impl_node_id, id, name, node_id) {
self_call_spans.push(cx.tcx.map.span(node_id));
// this is a self call, so we shouldn't explore past
// this node in the CFG.
continue
continue;
}
// add the successors of this node to explore the graph further.
cfg.graph.each_outgoing_edge(idx, |_, edge| {
@ -1888,7 +1906,7 @@ impl LintPass for UnconditionalRecursion {
});
}
// check the number of sell calls because a function that
// Check the number of self calls because a function that
// doesn't return (e.g. calls a `-> !` function or `loop { /*
// no break */ }`) shouldn't be linted unless it actually
// recurs.
@ -1920,7 +1938,7 @@ impl LintPass for UnconditionalRecursion {
_: ast::Ident,
id: ast::NodeId) -> bool {
tcx.def_map.borrow().get(&id)
.map_or(false, |def| def.def_id() == ast_util::local_def(fn_id))
.map_or(false, |def| def.def_id() == ast_util::local_def(fn_id))
}
// check if the method call `id` refers to method `method_id`
@ -1962,7 +1980,7 @@ impl LintPass for UnconditionalRecursion {
tcx.map.span(id),
"non-method call expr behaving like a method call?")
};
// it matches if it comes from the same impl,
// It matches if it comes from the same impl,
// and has the same method name.
return ast_util::is_local(impl_def_id)
&& impl_def_id.node == impl_id
@ -2013,7 +2031,7 @@ impl LintPass for PluginAsLibrary {
if decoder::get_plugin_registrar_fn(md.data()).is_some() {
cx.span_lint(PLUGIN_AS_LIBRARY, it.span,
"compiler plugin used as an ordinary library");
"compiler plugin used as an ordinary library");
}
}
}
@ -2069,7 +2087,7 @@ impl LintPass for InvalidNoMangleItems {
// Const items do not refer to a particular location in memory, and therefore
// don't have anything to attach a symbol to
let msg = "const items should never be #[no_mangle], consider instead using \
`pub static`";
`pub static`";
cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
}
}
@ -2082,15 +2100,17 @@ impl LintPass for InvalidNoMangleItems {
#[derive(Copy)]
pub struct UnstableFeatures;
declare_lint!(UNSTABLE_FEATURES, Allow,
"enabling unstable features");
declare_lint! {
UNSTABLE_FEATURES,
Allow,
"enabling unstable features"
}
impl LintPass for UnstableFeatures {
fn get_lints(&self) -> LintArray {
lint_array!(UNSTABLE_FEATURES)
}
fn check_attribute(&mut self, ctx: &Context, attr: &ast::Attribute) {
use syntax::attr;
if attr::contains_name(&[attr.node.value.clone()], "feature") {
ctx.span_lint(UNSTABLE_FEATURES, attr.span, "unstable feature");
}

View file

@ -789,7 +789,7 @@ fn pick_column_to_specialize(def_map: &DefMap, m: &[Match]) -> Option<uint> {
// Irrefutable columns always go first, they'd only be duplicated in the branches.
if total_score == 0 {
std::uint::MAX
std::usize::MAX
} else {
total_score
}

View file

@ -2435,21 +2435,19 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
use middle::ty::{BrAnon, ReLateBound};
let function_type;
let (fn_sig, abi, has_env) = match fn_ty.sty {
ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, false),
let (fn_sig, abi, env_ty) = match fn_ty.sty {
ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None),
ty::ty_closure(closure_did, _, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs);
(&function_type.sig, RustCall, true)
let self_type = self_type_for_closure(ccx, closure_did, fn_ty);
(&function_type.sig, RustCall, Some(self_type))
}
_ => ccx.sess().bug("expected closure or function.")
};
let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig);
// Since index 0 is the return value of the llvm func, we start
// at either 1 or 2 depending on whether there's an env slot or not
let mut first_arg_offset = if has_env { 2 } else { 1 };
let mut attrs = llvm::AttrBuilder::new();
let ret_ty = fn_sig.output;
@ -2460,7 +2458,11 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
assert!(abi == RustCall);
match fn_sig.inputs[0].sty {
ty::ty_tup(ref inputs) => inputs.clone(),
ty::ty_tup(ref inputs) => {
let mut full_inputs = vec![env_ty.expect("Missing closure environment")];
full_inputs.push_all(inputs);
full_inputs
}
_ => ccx.sess().bug("expected tuple'd inputs")
}
},
@ -2478,6 +2480,8 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
_ => fn_sig.inputs.clone()
};
// Index 0 is the return value of the llvm func, so we start at 1
let mut first_arg_offset = 1;
if let ty::FnConverging(ret_ty) = ret_ty {
// A function pointer is called without the declaration
// available, so we have to apply any attributes with ABI

View file

@ -603,7 +603,18 @@ pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let _icx = push_ctxt("trans_method_call");
debug!("trans_method_call(call_expr={})", call_expr.repr(bcx.tcx()));
let method_call = MethodCall::expr(call_expr.id);
let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty;
let method_ty = match bcx.tcx().method_map.borrow().get(&method_call) {
Some(method) => match method.origin {
ty::MethodTraitObject(_) => match method.ty.sty {
ty::ty_bare_fn(_, ref fty) => {
ty::mk_bare_fn(bcx.tcx(), None, meth::opaque_method_ty(bcx.tcx(), fty))
}
_ => method.ty
},
_ => method.ty
},
None => panic!("method not found in trans_method_call")
};
trans_call_inner(
bcx,
call_expr.debug_loc(),
@ -927,20 +938,21 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
tuple_expr.id));
let repr = adt::represent_type(bcx.ccx(), tuple_type);
let repr_ptr = &*repr;
for i in 0..field_types.len() {
llargs.extend(field_types.iter().enumerate().map(|(i, field_type)| {
let arg_datum = tuple_lvalue_datum.get_element(
bcx,
field_types[i],
field_type,
|srcval| {
adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i)
});
let arg_datum = arg_datum.to_expr_datum();
let arg_datum =
unpack_datum!(bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
let arg_datum =
unpack_datum!(bcx, arg_datum.to_appropriate_datum(bcx));
llargs.push(arg_datum.add_clean(bcx.fcx, arg_cleanup_scope));
}
}).to_expr_datum();
unpack_result!(bcx, trans_arg_datum(
bcx,
field_type,
arg_datum,
arg_cleanup_scope,
DontAutorefArg)
)
}));
}
_ => {
bcx.sess().span_bug(tuple_expr.span,

View file

@ -589,15 +589,16 @@ pub fn trans_object_shim<'a, 'tcx>(
};
let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
let fty = tcx.mk_bare_fn(fty);
debug!("trans_object_shim: fty={}", fty.repr(tcx));
let method_ty = opaque_method_ty(tcx, fty);
debug!("trans_object_shim: fty={} method_ty={}", fty.repr(tcx), method_ty.repr(tcx));
//
let method_bare_fn_ty =
ty::mk_bare_fn(tcx, None, fty);
let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty);
let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty);
let function_name =
link::mangle_internal_name_by_type_and_seq(ccx, method_bare_fn_ty, "object_shim");
link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
let llfn =
decl_internal_rust_fn(ccx, method_bare_fn_ty, &function_name);
decl_internal_rust_fn(ccx, shim_fn_ty, &function_name);
let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig);
@ -866,3 +867,20 @@ pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
bcx
}
/// Replace the self type (&Self or Box<Self>) with an opaque pointer.
pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
-> &'tcx ty::BareFnTy<'tcx> {
let mut inputs = method_ty.sig.0.inputs.clone();
inputs[0] = ty::mk_mut_ptr(tcx, ty::mk_mach_int(tcx, ast::TyI8));
tcx.mk_bare_fn(ty::BareFnTy {
unsafety: method_ty.unsafety,
abi: method_ty.abi,
sig: ty::Binder(ty::FnSig {
inputs: inputs,
output: method_ty.sig.0.output,
variadic: method_ty.sig.0.variadic,
}),
})
}

View file

@ -14,8 +14,9 @@ use middle::infer;
use middle::region;
use middle::subst;
use middle::ty::{self, Ty};
use util::ppaux::{Repr};
use util::ppaux::{Repr, UserString};
use syntax::ast;
use syntax::codemap::Span;
pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
@ -28,29 +29,98 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
// types that have been traversed so far by `traverse_type_if_unseen`
let mut breadcrumbs: Vec<Ty<'tcx>> = Vec::new();
iterate_over_potentially_unsafe_regions_in_type(
let result = iterate_over_potentially_unsafe_regions_in_type(
rcx,
&mut breadcrumbs,
TypeContext::Root,
typ,
span,
scope,
0,
0);
match result {
Ok(()) => {}
Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
let tcx = rcx.tcx();
span_err!(tcx.sess, span, E0320,
"overflow while adding drop-check rules for {}",
typ.user_string(rcx.tcx()));
match *ctxt {
TypeContext::Root => {
// no need for an additional note if the overflow
// was somehow on the root.
}
TypeContext::EnumVariant { def_id, variant, arg_index } => {
// FIXME (pnkfelix): eventually lookup arg_name
// for the given index on struct variants.
span_note!(
rcx.tcx().sess,
span,
"overflowed on enum {} variant {} argument {} type: {}",
ty::item_path_str(tcx, def_id),
variant,
arg_index,
detected_on_typ.user_string(rcx.tcx()));
}
TypeContext::Struct { def_id, field } => {
span_note!(
rcx.tcx().sess,
span,
"overflowed on struct {} field {} type: {}",
ty::item_path_str(tcx, def_id),
field,
detected_on_typ.user_string(rcx.tcx()));
}
}
}
}
}
enum Error<'tcx> {
Overflow(TypeContext, ty::Ty<'tcx>),
}
enum TypeContext {
Root,
EnumVariant {
def_id: ast::DefId,
variant: ast::Name,
arg_index: usize,
},
Struct {
def_id: ast::DefId,
field: ast::Name,
}
}
// The `depth` counts the number of calls to this function;
// the `xref_depth` counts the subset of such calls that go
// across a `Box<T>` or `PhantomData<T>`.
fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
rcx: &mut Rcx<'a, 'tcx>,
breadcrumbs: &mut Vec<Ty<'tcx>>,
context: TypeContext,
ty_root: ty::Ty<'tcx>,
span: Span,
scope: region::CodeExtent,
depth: uint)
depth: uint,
xref_depth: uint) -> Result<(), Error<'tcx>>
{
// Issue #22443: Watch out for overflow. While we are careful to
// handle regular types properly, non-regular ones cause problems.
let recursion_limit = rcx.tcx().sess.recursion_limit.get();
if xref_depth >= recursion_limit {
return Err(Error::Overflow(context, ty_root))
}
let origin = || infer::SubregionOrigin::SafeDestructor(span);
let mut walker = ty_root.walk();
let opt_phantom_data_def_id = rcx.tcx().lang_items.phantom_data();
let destructor_for_type = rcx.tcx().destructor_for_type.borrow();
let xref_depth_orig = xref_depth;
while let Some(typ) = walker.next() {
// Avoid recursing forever.
if breadcrumbs.contains(&typ) {
@ -61,20 +131,33 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
// If we encounter `PhantomData<T>`, then we should replace it
// with `T`, the type it represents as owned by the
// surrounding context, before doing further analysis.
let typ = if let ty::ty_struct(struct_did, substs) = typ.sty {
if opt_phantom_data_def_id == Some(struct_did) {
let item_type = ty::lookup_item_type(rcx.tcx(), struct_did);
let tp_def = item_type.generics.types
.opt_get(subst::TypeSpace, 0).unwrap();
let new_typ = substs.type_for_def(tp_def);
debug!("replacing phantom {} with {}",
typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
new_typ
} else {
typ
let (typ, xref_depth) = match typ.sty {
ty::ty_struct(struct_did, substs) => {
if opt_phantom_data_def_id == Some(struct_did) {
let item_type = ty::lookup_item_type(rcx.tcx(), struct_did);
let tp_def = item_type.generics.types
.opt_get(subst::TypeSpace, 0).unwrap();
let new_typ = substs.type_for_def(tp_def);
debug!("replacing phantom {} with {}",
typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
(new_typ, xref_depth_orig + 1)
} else {
(typ, xref_depth_orig)
}
}
// Note: When ty_uniq is removed from compiler, the
// definition of `Box<T>` must carry a PhantomData that
// puts us into the previous case.
ty::ty_uniq(new_typ) => {
debug!("replacing ty_uniq {} with {}",
typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
(new_typ, xref_depth_orig + 1)
}
_ => {
(typ, xref_depth_orig)
}
} else {
typ
};
let opt_type_did = match typ.sty {
@ -87,9 +170,9 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
opt_type_did.and_then(|did| destructor_for_type.get(&did));
debug!("iterate_over_potentially_unsafe_regions_in_type \
{}typ: {} scope: {:?} opt_dtor: {:?}",
{}typ: {} scope: {:?} opt_dtor: {:?} xref: {}",
(0..depth).map(|_| ' ').collect::<String>(),
typ.repr(rcx.tcx()), scope, opt_dtor);
typ.repr(rcx.tcx()), scope, opt_dtor, xref_depth);
// If `typ` has a destructor, then we must ensure that all
// borrowed data reachable via `typ` must outlive the parent
@ -228,6 +311,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
match typ.sty {
ty::ty_struct(struct_did, substs) => {
debug!("typ: {} is struct; traverse structure and not type-expression",
typ.repr(rcx.tcx()));
// Don't recurse; we extract type's substructure,
// so do not process subparts of type expression.
walker.skip_current_subtree();
@ -240,17 +325,24 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
struct_did,
field.id,
substs);
iterate_over_potentially_unsafe_regions_in_type(
try!(iterate_over_potentially_unsafe_regions_in_type(
rcx,
breadcrumbs,
TypeContext::Struct {
def_id: struct_did,
field: field.name,
},
field_type,
span,
scope,
depth+1)
depth+1,
xref_depth))
}
}
ty::ty_enum(enum_did, substs) => {
debug!("typ: {} is enum; traverse structure and not type-expression",
typ.repr(rcx.tcx()));
// Don't recurse; we extract type's substructure,
// so do not process subparts of type expression.
walker.skip_current_subtree();
@ -260,14 +352,20 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
enum_did,
substs);
for variant_info in all_variant_info.iter() {
for argument_type in variant_info.args.iter() {
iterate_over_potentially_unsafe_regions_in_type(
for (i, arg_type) in variant_info.args.iter().enumerate() {
try!(iterate_over_potentially_unsafe_regions_in_type(
rcx,
breadcrumbs,
*argument_type,
TypeContext::EnumVariant {
def_id: enum_did,
variant: variant_info.name,
arg_index: i,
},
*arg_type,
span,
scope,
depth+1)
depth+1,
xref_depth));
}
}
}
@ -290,4 +388,6 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
// is done.
}
}
return Ok(());
}

View file

@ -174,7 +174,8 @@ register_diagnostics! {
E0249, // expected constant expr for array length
E0250, // expected constant expr for array length
E0318, // can't create default impls for traits outside their crates
E0319 // trait impls for defaulted traits allowed just for structs/enums
E0319, // trait impls for defaulted traits allowed just for structs/enums
E0320 // recursive overflow during dropck
}
__build_diagnostic_array! { DIAGNOSTICS }

View file

@ -109,7 +109,7 @@
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(int_uint)]
#![feature(hash)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(linkage, thread_local, asm)]
@ -221,14 +221,12 @@ mod int_macros;
mod uint_macros;
#[path = "num/isize.rs"] pub mod isize;
pub use isize as int;
#[path = "num/i8.rs"] pub mod i8;
#[path = "num/i16.rs"] pub mod i16;
#[path = "num/i32.rs"] pub mod i32;
#[path = "num/i64.rs"] pub mod i64;
#[path = "num/usize.rs"] pub mod usize;
pub use usize as uint;
#[path = "num/u8.rs"] pub mod u8;
#[path = "num/u16.rs"] pub mod u16;
#[path = "num/u32.rs"] pub mod u32;

View file

@ -0,0 +1,37 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Issue 22443: Reject code using non-regular types that would
// otherwise cause dropck to loop infinitely.
use std::marker::PhantomData;
struct Digit<T> {
elem: T
}
struct Node<T:'static> { m: PhantomData<&'static T> }
enum FingerTree<T:'static> {
Single(T),
// Bug report said Digit after Box would stack overflow (versus
// Digit before Box; see dropck_no_diverge_on_nonregular_2).
Deep(
Box<FingerTree<Node<T>>>,
Digit<T>,
)
}
fn main() {
let ft = //~ ERROR overflow while adding drop-check rules for FingerTree
FingerTree::Single(1);
//~^ ERROR overflow while adding drop-check rules for FingerTree
}

View file

@ -0,0 +1,36 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Issue 22443: Reject code using non-regular types that would
// otherwise cause dropck to loop infinitely.
use std::marker::PhantomData;
struct Digit<T> {
elem: T
}
struct Node<T:'static> { m: PhantomData<&'static T> }
enum FingerTree<T:'static> {
Single(T),
// Bug report said Digit before Box would infinite loop (versus
// Digit after Box; see dropck_no_diverge_on_nonregular_1).
Deep(
Digit<T>,
Box<FingerTree<Node<T>>>,
)
}
fn main() {
let ft = //~ ERROR overflow while adding drop-check rules for FingerTree
FingerTree::Single(1);
//~^ ERROR overflow while adding drop-check rules for FingerTree
}

View file

@ -0,0 +1,46 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Issue 22443: Reject code using non-regular types that would
// otherwise cause dropck to loop infinitely.
//
// This version is just checking that we still sanely handle a trivial
// wrapper around the non-regular type. (It also demonstrates how the
// error messages will report different types depending on which type
// dropck is analyzing.)
use std::marker::PhantomData;
struct Digit<T> {
elem: T
}
struct Node<T:'static> { m: PhantomData<&'static T> }
enum FingerTree<T:'static> {
Single(T),
// According to the bug report, Digit before Box would infinite loop.
Deep(
Digit<T>,
Box<FingerTree<Node<T>>>,
)
}
enum Wrapper<T:'static> {
Simple,
Other(FingerTree<T>),
}
fn main() {
let w = //~ ERROR overflow while adding drop-check rules for core::option
Some(Wrapper::Simple::<u32>);
//~^ ERROR overflow while adding drop-check rules for core::option::Option
//~| ERROR overflow while adding drop-check rules for Wrapper
}

View file

@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::{int, i8, i16, i32, i64};
use std::{isize, i8, i16, i32, i64};
use std::thread;
fn main() {
assert!(thread::spawn(move|| { int::MIN / -1; }).join().is_err());
assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
//~^ ERROR attempted to divide with overflow in a constant expression
assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
//~^ ERROR attempted to divide with overflow in a constant expression
@ -32,7 +32,7 @@ fn main() {
//~^ ERROR attempted to divide by zero in a constant expression
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
//~^ ERROR attempted to divide by zero in a constant expression
assert!(thread::spawn(move|| { int::MIN % -1; }).join().is_err());
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow in a constant expression
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow in a constant expression

View file

@ -9,7 +9,7 @@
// except according to those terms.
fn main() {
pub use std::uint; //~ ERROR: visibility has no effect
pub use std::usize; //~ ERROR: visibility has no effect
pub struct A; //~ ERROR: visibility has no effect
pub enum B {} //~ ERROR: visibility has no effect
pub trait C { //~ ERROR: visibility has no effect

View file

@ -10,10 +10,10 @@
// error-pattern:index out of bounds: the len is 3 but the index is
use std::uint;
use std::usize;
use std::mem::size_of;
fn main() {
let xs = [1, 2, 3];
xs[uint::MAX / size_of::<int>() + 1];
xs[usize::MAX / size_of::<isize>() + 1];
}

View file

@ -11,11 +11,11 @@
// error-pattern:capacity overflow
use std::collections::hash_map::HashMap;
use std::uint;
use std::usize;
use std::mem::size_of;
fn main() {
let threshold = uint::MAX / size_of::<(u64, u64, u64)>();
let threshold = usize::MAX / size_of::<(u64, u64, u64)>();
let mut h = HashMap::<u64, u64>::with_capacity(threshold + 100);
h.insert(0, 0);
}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// DON'T REENABLE THIS UNLESS YOU'VE ACTUALLY FIXED THE UNDERLYING ISSUE
// ignore-android seems to block forever
#![forbid(warnings)]

View file

@ -0,0 +1,55 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This test is reduced from libsyntax. It is just checking that we
// can successfully deal with a "deep" structure, which the drop-check
// was hitting a recursion limit on at one point.
#![allow(non_camel_case_types)]
pub fn noop_fold_impl_item() -> SmallVector<ImplItem> {
loop { }
}
pub struct SmallVector<T>(P<T>);
pub struct ImplItem(P<S01_Method>);
struct P<T>(Box<T>);
struct S01_Method(P<S02_Generics>);
struct S02_Generics(P<S03_TyParam>);
struct S03_TyParam(P<S04_TyParamBound>);
struct S04_TyParamBound(S05_PolyTraitRef);
struct S05_PolyTraitRef(S06_TraitRef);
struct S06_TraitRef(S07_Path);
struct S07_Path(Vec<S08_PathSegment>);
struct S08_PathSegment(S09_PathParameters);
struct S09_PathParameters(P<S10_ParenthesizedParameterData>);
struct S10_ParenthesizedParameterData(Option<P<S11_Ty>>);
struct S11_Ty(P<S12_Expr>);
struct S12_Expr(P<S13_Block>);
struct S13_Block(Vec<P<S14_Stmt>>);
struct S14_Stmt(P<S15_Decl>);
struct S15_Decl(P<S16_Local>);
struct S16_Local(P<S17_Pat>);
struct S17_Pat(P<S18_Mac>);
struct S18_Mac(Vec<P<S19_TokenTree>>);
struct S19_TokenTree(P<S20_Token>);
struct S20_Token(P<S21_Nonterminal>);
struct S21_Nonterminal(P<S22_Item>);
struct S22_Item(P<S23_EnumDef>);
struct S23_EnumDef(Vec<P<S24_Variant>>);
struct S24_Variant(P<S25_VariantKind>);
struct S25_VariantKind(P<S26_StructDef>);
struct S26_StructDef(Vec<P<S27_StructField>>);
struct S27_StructField(P<S28_StructFieldKind>);
struct S28_StructFieldKind;
pub fn main() {}

View file

@ -10,6 +10,8 @@
// ignore-pretty - token trees can't pretty print
#![feature(custom_attribute)]
macro_rules! compiles_fine {
(#[$at:meta]) => {
// test that the different types of attributes work