diff --git a/src/doc/book/error-handling.md b/src/doc/book/error-handling.md index d94eeaebf4021..544f837d69b26 100644 --- a/src/doc/book/error-handling.md +++ b/src/doc/book/error-handling.md @@ -1829,7 +1829,7 @@ use std::error::Error; fn search> (file_path: P, city: &str) - -> Result, Box> { + -> Result, Box> { let mut found = vec![]; let file = try!(File::open(file_path)); let mut rdr = csv::Reader::from_reader(file); @@ -1858,20 +1858,17 @@ Instead of `x.unwrap()`, we now have `try!(x)`. Since our function returns a `Result`, the `try!` macro will return early from the function if an error occurs. -There is one big gotcha in this code: we used `Box` -instead of `Box`. We did this so we could convert a plain string to an -error type. We need these extra bounds so that we can use the -[corresponding `From` -impls](../std/convert/trait.From.html): +At the end of `search` we also convert a plain string to an error type +by using the [corresponding `From` impls](../std/convert/trait.From.html): ```rust,ignore // We are making use of this impl in the code above, since we call `From::from` // on a `&'static str`. -impl<'a, 'b> From<&'b str> for Box +impl<'a> From<&'a str> for Box // But this is also useful when you need to allocate a new string for an // error message, usually with `format!`. -impl From for Box +impl From for Box ``` Since `search` now returns a `Result`, `main` should use case analysis @@ -1964,7 +1961,7 @@ use std::io; fn search> (file_path: &Option

, city: &str) - -> Result, Box> { + -> Result, Box> { let mut found = vec![]; let input: Box = match *file_path { None => Box::new(io::stdin()), @@ -2175,9 +2172,8 @@ heuristics! `unwrap`. Be warned: if it winds up in someone else's hands, don't be surprised if they are agitated by poor error messages! * If you're writing a quick 'n' dirty program and feel ashamed about panicking - anyway, then use either a `String` or a `Box` for your - error type (the `Box` type is because of the - [available `From` impls](../std/convert/trait.From.html)). + anyway, then use either a `String` or a `Box` for your + error type. * Otherwise, in a program, define your own error types with appropriate [`From`](../std/convert/trait.From.html) and diff --git a/src/doc/nomicon/safe-unsafe-meaning.md b/src/doc/nomicon/safe-unsafe-meaning.md index 5fd61eb51dd1c..c4f939a608b79 100644 --- a/src/doc/nomicon/safe-unsafe-meaning.md +++ b/src/doc/nomicon/safe-unsafe-meaning.md @@ -1,150 +1,127 @@ % How Safe and Unsafe Interact -So what's the relationship between Safe and Unsafe Rust? How do they interact? - -Rust models the separation between Safe and Unsafe Rust with the `unsafe` -keyword, which can be thought as a sort of *foreign function interface* (FFI) -between Safe and Unsafe Rust. This is the magic behind why we can say Safe Rust -is a safe language: all the scary unsafe bits are relegated exclusively to FFI -*just like every other safe language*. - -However because one language is a subset of the other, the two can be cleanly -intermixed as long as the boundary between Safe and Unsafe Rust is denoted with -the `unsafe` keyword. No need to write headers, initialize runtimes, or any of -that other FFI boiler-plate. - -There are several places `unsafe` can appear in Rust today, which can largely be -grouped into two categories: - -* There are unchecked contracts here. To declare you understand this, I require -you to write `unsafe` elsewhere: - * On functions, `unsafe` is declaring the function to be unsafe to call. - Users of the function must check the documentation to determine what this - means, and then have to write `unsafe` somewhere to identify that they're - aware of the danger. - * On trait declarations, `unsafe` is declaring that *implementing* the trait - is an unsafe operation, as it has contracts that other unsafe code is free - to trust blindly. (More on this below.) - -* I am declaring that I have, to the best of my knowledge, adhered to the -unchecked contracts: - * On trait implementations, `unsafe` is declaring that the contract of the - `unsafe` trait has been upheld. - * On blocks, `unsafe` is declaring any unsafety from an unsafe - operation within to be handled, and therefore the parent function is safe. - -There is also `#[unsafe_no_drop_flag]`, which is a special case that exists for -historical reasons and is in the process of being phased out. See the section on -[drop flags] for details. - -Some examples of unsafe functions: - -* `slice::get_unchecked` will perform unchecked indexing, allowing memory - safety to be freely violated. -* every raw pointer to sized type has intrinsic `offset` method that invokes - Undefined Behavior if it is not "in bounds" as defined by LLVM. -* `mem::transmute` reinterprets some value as having the given type, - bypassing type safety in arbitrary ways. (see [conversions] for details) -* All FFI functions are `unsafe` because they can do arbitrary things. - C being an obvious culprit, but generally any language can do something - that Rust isn't happy about. +What's the relationship between Safe Rust and Unsafe Rust? How do they +interact? + +The separation between Safe Rust and Unsafe Rust is controlled with the +`unsafe` keyword, which acts as an interface from one to the other. This is +why we can say Safe Rust is a safe language: all the unsafe parts are kept +exclusively behind the boundary. + +The `unsafe` keyword has two uses: to declare the existence of contracts the +compiler can't check, and to declare that the adherence of some code to +those contracts has been checked by the programmer. + +You can use `unsafe` to indicate the existence of unchecked contracts on +_functions_ and on _trait declarations_. On functions, `unsafe` means that +users of the function must check that function's documentation to ensure +they are using it in a way that maintains the contracts the function +requires. On trait declarations, `unsafe` means that implementors of the +trait must check the trait documentation to ensure their implementation +maintains the contracts the trait requires. + +You can use `unsafe` on a block to declare that all constraints required +by an unsafe function within the block have been adhered to, and the code +can therefore be trusted. You can use `unsafe` on a trait implementation +to declare that the implementation of that trait has adhered to whatever +contracts the trait's documentation requires. + +There is also the `#[unsafe_no_drop_flag]` attribute, which exists for +historic reasons and is being phased out. See the section on [drop flags] +for details. + +The standard library has a number of unsafe functions, including: + +* `slice::get_unchecked`, which performs unchecked indexing, allowing + memory safety to be freely violated. +* `mem::transmute` reinterprets some value as having a given type, bypassing + type safety in arbitrary ways (see [conversions] for details). +* Every raw pointer to a sized type has an intrinstic `offset` method that + invokes Undefined Behavior if the passed offset is not "in bounds" as + defined by LLVM. +* All FFI functions are `unsafe` because the other language can do arbitrary + operations that the Rust compiler can't check. As of Rust 1.0 there are exactly two unsafe traits: -* `Send` is a marker trait (it has no actual API) that promises implementors - are safe to send (move) to another thread. -* `Sync` is a marker trait that promises that threads can safely share - implementors through a shared reference. - -The need for unsafe traits boils down to the fundamental property of safe code: - -**No matter how completely awful Safe code is, it can't cause Undefined -Behavior.** - -This means that Unsafe Rust, **the royal vanguard of Undefined Behavior**, has to be -*super paranoid* about generic safe code. To be clear, Unsafe Rust is totally free to trust -specific safe code. Anything else would degenerate into infinite spirals of -paranoid despair. In particular it's generally regarded as ok to trust the standard library -to be correct. `std` is effectively an extension of the language, and you -really just have to trust the language. If `std` fails to uphold the -guarantees it declares, then it's basically a language bug. - -That said, it would be best to minimize *needlessly* relying on properties of -concrete safe code. Bugs happen! Of course, I must reinforce that this is only -a concern for Unsafe code. Safe code can blindly trust anyone and everyone -as far as basic memory-safety is concerned. - -On the other hand, safe traits are free to declare arbitrary contracts, but because -implementing them is safe, unsafe code can't trust those contracts to actually -be upheld. This is different from the concrete case because *anyone* can -randomly implement the interface. There is something fundamentally different -about trusting a particular piece of code to be correct, and trusting *all the -code that will ever be written* to be correct. - -For instance Rust has `PartialOrd` and `Ord` traits to try to differentiate -between types which can "just" be compared, and those that actually implement a -total ordering. Pretty much every API that wants to work with data that can be -compared wants Ord data. For instance, a sorted map like BTreeMap -*doesn't even make sense* for partially ordered types. If you claim to implement -Ord for a type, but don't actually provide a proper total ordering, BTreeMap will -get *really confused* and start making a total mess of itself. Data that is -inserted may be impossible to find! - -But that's okay. BTreeMap is safe, so it guarantees that even if you give it a -completely garbage Ord implementation, it will still do something *safe*. You -won't start reading uninitialized or unallocated memory. In fact, BTreeMap -manages to not actually lose any of your data. When the map is dropped, all the -destructors will be successfully called! Hooray! - -However BTreeMap is implemented using a modest spoonful of Unsafe Rust (most collections -are). That means that it's not necessarily *trivially true* that a bad Ord -implementation will make BTreeMap behave safely. BTreeMap must be sure not to rely -on Ord *where safety is at stake*. Ord is provided by safe code, and safety is not -safe code's responsibility to uphold. - -But wouldn't it be grand if there was some way for Unsafe to trust some trait -contracts *somewhere*? This is the problem that unsafe traits tackle: by marking -*the trait itself* as unsafe to implement, unsafe code can trust the implementation -to uphold the trait's contract. Although the trait implementation may be -incorrect in arbitrary other ways. - -For instance, given a hypothetical UnsafeOrd trait, this is technically a valid -implementation: +* `Send` is a marker trait (a trait with no API) that promises implementors are + safe to send (move) to another thread. +* `Sync` is a marker trait that promises threads can safely share implementors + through a shared reference. + +Much of the Rust standard library also uses Unsafe Rust internally, although +these implementations are rigorously manually checked, and the Safe Rust +interfaces provided on top of these implementations can be assumed to be safe. + +The need for all of this separation boils down a single fundamental property +of Safe Rust: + +**No matter what, Safe Rust can't cause Undefined Behavior.** + +The design of the safe/unsafe split means that Safe Rust inherently has to +trust that any Unsafe Rust it touches has been written correctly (meaning +the Unsafe Rust actually maintains whatever contracts it is supposed to +maintain). On the other hand, Unsafe Rust has to be very careful about +trusting Safe Rust. + +As an example, Rust has the `PartialOrd` and `Ord` traits to differentiate +between types which can "just" be compared, and those that provide a total +ordering (where every value of the type is either equal to, greater than, +or less than any other value of the same type). The sorted map type +`BTreeMap` doesn't make sense for partially-ordered types, and so it +requires that any key type for it implements the `Ord` trait. However, +`BTreeMap` has Unsafe Rust code inside of its implementation, and this +Unsafe Rust code cannot assume that any `Ord` implementation it gets makes +sense. The unsafe portions of `BTreeMap`'s internals have to be careful to +maintain all necessary contracts, even if a key type's `Ord` implementation +does not implement a total ordering. + +Unsafe Rust cannot automatically trust Safe Rust. When writing Unsafe Rust, +you must be careful to only rely on specific Safe Rust code, and not make +assumptions about potential future Safe Rust code providing the same +guarantees. + +This is the problem that `unsafe` traits exist to resolve. The `BTreeMap` +type could theoretically require that keys implement a new trait called +`UnsafeOrd`, rather than `Ord`, that might look like this: ```rust -# use std::cmp::Ordering; -# struct MyType; -# unsafe trait UnsafeOrd { fn cmp(&self, other: &Self) -> Ordering; } -unsafe impl UnsafeOrd for MyType { - fn cmp(&self, other: &Self) -> Ordering { - Ordering::Equal - } +use std::cmp::Ordering; + +unsafe trait UnsafeOrd { + fn cmp(&self, other: &Self) -> Ordering; } ``` -But it's probably not the implementation you want. - -Rust has traditionally avoided making traits unsafe because it makes Unsafe -pervasive, which is not desirable. The reason Send and Sync are unsafe is because thread -safety is a *fundamental property* that unsafe code cannot possibly hope to defend -against in the same way it would defend against a bad Ord implementation. The -only way to possibly defend against thread-unsafety would be to *not use -threading at all*. Making every load and store atomic isn't even sufficient, -because it's possible for complex invariants to exist between disjoint locations -in memory. For instance, the pointer and capacity of a Vec must be in sync. - -Even concurrent paradigms that are traditionally regarded as Totally Safe like -message passing implicitly rely on some notion of thread safety -- are you -really message-passing if you pass a pointer? Send and Sync therefore require -some fundamental level of trust that Safe code can't provide, so they must be -unsafe to implement. To help obviate the pervasive unsafety that this would -introduce, Send (resp. Sync) is automatically derived for all types composed only -of Send (resp. Sync) values. 99% of types are Send and Sync, and 99% of those -never actually say it (the remaining 1% is overwhelmingly synchronization -primitives). - - - +Then, a type would use `unsafe` to implement `UnsafeOrd`, indicating that +they've ensured their implementation maintains whatever contracts the +trait expects. In this situation, the Unsafe Rust in the internals of +`BTreeMap` could trust that the key type's `UnsafeOrd` implementation is +correct. If it isn't, it's the fault of the unsafe trait implementation +code, which is consistent with Rust's safety guarantees. + +The decision of whether to mark a trait `unsafe` is an API design choice. +Rust has traditionally avoided marking traits unsafe because it makes Unsafe +Rust pervasive, which is not desirable. `Send` and `Sync` are marked unsafe +because thread safety is a *fundamental property* that unsafe code can't +possibly hope to defend against in the way it could defend against a bad +`Ord` implementation. The decision of whether to mark your own traits `unsafe` +depends on the same sort of consideration. If `unsafe` code cannot reasonably +expect to defend against a bad implementation of the trait, then marking the +trait `unsafe` is a reasonable choice. + +As an aside, while `Send` and `Sync` are `unsafe` traits, they are +automatically implemented for types when such derivations are provably safe +to do. `Send` is automatically derived for all types composed only of values +whose types also implement `Send`. `Sync` is automatically derived for all +types composed only of values whose types also implement `Sync`. + +This is the dance of Safe Rust and Unsafe Rust. It is designed to make using +Safe Rust as ergonomic as possible, but requires extra effort and care when +writing Unsafe Rust. The rest of the book is largely a discussion of the sort +of care that must be taken, and what contracts it is expected of Unsafe Rust +to uphold. [drop flags]: drop-flags.html [conversions]: conversions.html + diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 29f3e4b1b6159..248240a7de884 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -17,9 +17,9 @@ use core::ops::Index; use core::{fmt, intrinsics, mem, ptr}; use borrow::Borrow; -use Bound::{self, Included, Excluded, Unbounded}; +use Bound::{self, Excluded, Included, Unbounded}; -use super::node::{self, NodeRef, Handle, marker}; +use super::node::{self, Handle, NodeRef, marker}; use super::search; use super::node::InsertResult::*; @@ -129,35 +129,38 @@ use self::Entry::*; #[stable(feature = "rust1", since = "1.0.0")] pub struct BTreeMap { root: node::Root, - length: usize + length: usize, } impl Drop for BTreeMap { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { unsafe { - for _ in ptr::read(self).into_iter() { } + for _ in ptr::read(self).into_iter() { + } } } } impl Clone for BTreeMap { fn clone(&self) -> BTreeMap { - fn clone_subtree( - node: node::NodeRef) - -> BTreeMap { + fn clone_subtree(node: node::NodeRef) + -> BTreeMap { match node.force() { Leaf(leaf) => { let mut out_tree = BTreeMap { root: node::Root::new_leaf(), - length: 0 + length: 0, }; { let mut out_node = match out_tree.root.as_mut().force() { Leaf(leaf) => leaf, - Internal(_) => unreachable!() + Internal(_) => unreachable!(), }; let mut in_edge = leaf.first_edge(); @@ -171,7 +174,7 @@ impl Clone for BTreeMap { } out_tree - }, + } Internal(internal) => { let mut out_tree = clone_subtree(internal.first_edge().descend()); @@ -218,7 +221,7 @@ impl super::Recover for BTreeMap fn get(&self, key: &Q) -> Option<&K> { match search::search_tree(self.root.as_ref(), key) { Found(handle) => Some(handle.into_kv().0), - GoDown(_) => None + GoDown(_) => None, } } @@ -226,12 +229,14 @@ impl super::Recover for BTreeMap match search::search_tree(self.root.as_mut(), key) { Found(handle) => { Some(OccupiedEntry { - handle: handle, - length: &mut self.length, - _marker: PhantomData, - }.remove_kv().0) - }, - GoDown(_) => None + handle: handle, + length: &mut self.length, + _marker: PhantomData, + } + .remove_kv() + .0) + } + GoDown(_) => None, } } @@ -244,7 +249,8 @@ impl super::Recover for BTreeMap handle: handle, length: &mut self.length, _marker: PhantomData, - }.insert(()); + } + .insert(()); None } } @@ -255,14 +261,14 @@ impl super::Recover for BTreeMap #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { range: Range<'a, K, V>, - length: usize + length: usize, } /// A mutable iterator over a BTreeMap's entries. #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { range: RangeMut<'a, K, V>, - length: usize + length: usize, } /// An owning iterator over a BTreeMap's entries. @@ -270,7 +276,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { pub struct IntoIter { front: Handle, marker::Edge>, back: Handle, marker::Edge>, - length: usize + length: usize, } /// An iterator over a BTreeMap's keys. @@ -294,7 +300,7 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// An iterator over a sub-range of BTreeMap's entries. pub struct Range<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, - back: Handle, K, V, marker::Leaf>, marker::Edge> + back: Handle, K, V, marker::Leaf>, marker::Edge>, } /// A mutable iterator over a sub-range of BTreeMap's entries. @@ -311,15 +317,13 @@ pub struct RangeMut<'a, K: 'a, V: 'a> { pub enum Entry<'a, K: 'a, V: 'a> { /// A vacant Entry #[stable(feature = "rust1", since = "1.0.0")] - Vacant( - #[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V> - ), + Vacant(#[stable(feature = "rust1", since = "1.0.0")] + VacantEntry<'a, K, V>), /// An occupied Entry #[stable(feature = "rust1", since = "1.0.0")] - Occupied( - #[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V> - ), + Occupied(#[stable(feature = "rust1", since = "1.0.0")] + OccupiedEntry<'a, K, V>), } /// A vacant Entry. @@ -336,11 +340,7 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> { /// An occupied Entry. #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - handle: Handle, - K, V, - marker::LeafOrInternal - >, marker::KV>, + handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, length: &'a mut usize, @@ -349,7 +349,7 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { } // An iterator for merging two sorted sequences into one -struct MergeIter> { +struct MergeIter> { left: Peekable, right: Peekable, } @@ -373,7 +373,7 @@ impl BTreeMap { pub fn new() -> BTreeMap { BTreeMap { root: node::Root::new_leaf(), - length: 0 + length: 0, } } @@ -415,10 +415,13 @@ impl BTreeMap { /// assert_eq!(map.get(&2), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self, key: &Q) -> Option<&V> where K: Borrow, Q: Ord { + pub fn get(&self, key: &Q) -> Option<&V> + where K: Borrow, + Q: Ord + { match search::search_tree(self.root.as_ref(), key) { Found(handle) => Some(handle.into_kv().1), - GoDown(_) => None + GoDown(_) => None, } } @@ -440,7 +443,10 @@ impl BTreeMap { /// assert_eq!(map.contains_key(&2), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains_key(&self, key: &Q) -> bool where K: Borrow, Q: Ord { + pub fn contains_key(&self, key: &Q) -> bool + where K: Borrow, + Q: Ord + { self.get(key).is_some() } @@ -465,10 +471,13 @@ impl BTreeMap { /// ``` // See `get` for implementation notes, this is basically a copy-paste with mut's added #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where K: Borrow, Q: Ord { + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + where K: Borrow, + Q: Ord + { match search::search_tree(self.root.as_mut(), key) { Found(handle) => Some(handle.into_kv_mut().1), - GoDown(_) => None + GoDown(_) => None, } } @@ -528,16 +537,20 @@ impl BTreeMap { /// assert_eq!(map.remove(&1), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, key: &Q) -> Option where K: Borrow, Q: Ord { + pub fn remove(&mut self, key: &Q) -> Option + where K: Borrow, + Q: Ord + { match search::search_tree(self.root.as_mut(), key) { Found(handle) => { Some(OccupiedEntry { - handle: handle, - length: &mut self.length, - _marker: PhantomData, - }.remove()) - }, - GoDown(_) => None + handle: handle, + length: &mut self.length, + _marker: PhantomData, + } + .remove()) + } + GoDown(_) => None, } } @@ -628,47 +641,63 @@ impl BTreeMap { min: Bound<&Min>, max: Bound<&Max>) -> Range - where K: Borrow + Borrow, + where K: Borrow + Borrow { let front = match min { - Included(key) => match search::search_tree(self.root.as_ref(), key) { - Found(kv_handle) => match kv_handle.left_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => last_leaf_edge(internal.descend()) - }, - GoDown(bottom) => bottom - }, - Excluded(key) => match search::search_tree(self.root.as_ref(), key) { - Found(kv_handle) => match kv_handle.right_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => first_leaf_edge(internal.descend()) - }, - GoDown(bottom) => bottom - }, - Unbounded => first_leaf_edge(self.root.as_ref()) + Included(key) => { + match search::search_tree(self.root.as_ref(), key) { + Found(kv_handle) => { + match kv_handle.left_edge().force() { + Leaf(bottom) => bottom, + Internal(internal) => last_leaf_edge(internal.descend()), + } + } + GoDown(bottom) => bottom, + } + } + Excluded(key) => { + match search::search_tree(self.root.as_ref(), key) { + Found(kv_handle) => { + match kv_handle.right_edge().force() { + Leaf(bottom) => bottom, + Internal(internal) => first_leaf_edge(internal.descend()), + } + } + GoDown(bottom) => bottom, + } + } + Unbounded => first_leaf_edge(self.root.as_ref()), }; let back = match max { - Included(key) => match search::search_tree(self.root.as_ref(), key) { - Found(kv_handle) => match kv_handle.right_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => first_leaf_edge(internal.descend()) - }, - GoDown(bottom) => bottom - }, - Excluded(key) => match search::search_tree(self.root.as_ref(), key) { - Found(kv_handle) => match kv_handle.left_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => last_leaf_edge(internal.descend()) - }, - GoDown(bottom) => bottom - }, - Unbounded => last_leaf_edge(self.root.as_ref()) + Included(key) => { + match search::search_tree(self.root.as_ref(), key) { + Found(kv_handle) => { + match kv_handle.right_edge().force() { + Leaf(bottom) => bottom, + Internal(internal) => first_leaf_edge(internal.descend()), + } + } + GoDown(bottom) => bottom, + } + } + Excluded(key) => { + match search::search_tree(self.root.as_ref(), key) { + Found(kv_handle) => { + match kv_handle.left_edge().force() { + Leaf(bottom) => bottom, + Internal(internal) => last_leaf_edge(internal.descend()), + } + } + GoDown(bottom) => bottom, + } + } + Unbounded => last_leaf_edge(self.root.as_ref()), }; Range { front: front, - back: back + back: back, } } @@ -704,51 +733,67 @@ impl BTreeMap { min: Bound<&Min>, max: Bound<&Max>) -> RangeMut - where K: Borrow + Borrow, + where K: Borrow + Borrow { let root1 = self.root.as_mut(); let root2 = unsafe { ptr::read(&root1) }; let front = match min { - Included(key) => match search::search_tree(root1, key) { - Found(kv_handle) => match kv_handle.left_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => last_leaf_edge(internal.descend()) - }, - GoDown(bottom) => bottom - }, - Excluded(key) => match search::search_tree(root1, key) { - Found(kv_handle) => match kv_handle.right_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => first_leaf_edge(internal.descend()) - }, - GoDown(bottom) => bottom - }, - Unbounded => first_leaf_edge(root1) + Included(key) => { + match search::search_tree(root1, key) { + Found(kv_handle) => { + match kv_handle.left_edge().force() { + Leaf(bottom) => bottom, + Internal(internal) => last_leaf_edge(internal.descend()), + } + } + GoDown(bottom) => bottom, + } + } + Excluded(key) => { + match search::search_tree(root1, key) { + Found(kv_handle) => { + match kv_handle.right_edge().force() { + Leaf(bottom) => bottom, + Internal(internal) => first_leaf_edge(internal.descend()), + } + } + GoDown(bottom) => bottom, + } + } + Unbounded => first_leaf_edge(root1), }; let back = match max { - Included(key) => match search::search_tree(root2, key) { - Found(kv_handle) => match kv_handle.right_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => first_leaf_edge(internal.descend()) - }, - GoDown(bottom) => bottom - }, - Excluded(key) => match search::search_tree(root2, key) { - Found(kv_handle) => match kv_handle.left_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => last_leaf_edge(internal.descend()) - }, - GoDown(bottom) => bottom - }, - Unbounded => last_leaf_edge(root2) + Included(key) => { + match search::search_tree(root2, key) { + Found(kv_handle) => { + match kv_handle.right_edge().force() { + Leaf(bottom) => bottom, + Internal(internal) => first_leaf_edge(internal.descend()), + } + } + GoDown(bottom) => bottom, + } + } + Excluded(key) => { + match search::search_tree(root2, key) { + Found(kv_handle) => { + match kv_handle.left_edge().force() { + Leaf(bottom) => bottom, + Internal(internal) => last_leaf_edge(internal.descend()), + } + } + GoDown(bottom) => bottom, + } + } + Unbounded => last_leaf_edge(root2), }; RangeMut { front: front, back: back, - _marker: PhantomData + _marker: PhantomData, } } @@ -773,21 +818,25 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry { match search::search_tree(self.root.as_mut(), &key) { - Found(handle) => Occupied(OccupiedEntry { - handle: handle, - length: &mut self.length, - _marker: PhantomData, - }), - GoDown(handle) => Vacant(VacantEntry { - key: key, - handle: handle, - length: &mut self.length, - _marker: PhantomData, - }) + Found(handle) => { + Occupied(OccupiedEntry { + handle: handle, + length: &mut self.length, + _marker: PhantomData, + }) + } + GoDown(handle) => { + Vacant(VacantEntry { + key: key, + handle: handle, + length: &mut self.length, + _marker: PhantomData, + }) + } } } - fn from_sorted_iter>(&mut self, iter: I) { + fn from_sorted_iter>(&mut self, iter: I) { let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node(); // Iterate through all key-value pairs, pushing them into nodes at the right level. for (key, value) in iter { @@ -810,12 +859,12 @@ impl BTreeMap { // Go up again. test_node = parent.forget_type(); } - }, + } Err(node) => { // We are at the top, create a new root node and push there. open_node = node.into_root_mut().push_level(); break; - }, + } } } @@ -890,7 +939,9 @@ impl BTreeMap { #[unstable(feature = "btree_split_off", reason = "recently added as part of collections reform 2", issue = "19986")] - pub fn split_off(&mut self, key: &Q) -> Self where K: Borrow { + pub fn split_off(&mut self, key: &Q) -> Self + where K: Borrow + { if self.is_empty() { return Self::new(); } @@ -910,7 +961,7 @@ impl BTreeMap { let mut split_edge = match search::search_node(left_node, key) { // key is going to the right tree Found(handle) => handle.left_edge(), - GoDown(handle) => handle + GoDown(handle) => handle, }; split_edge.move_suffix(&mut right_node); @@ -920,8 +971,12 @@ impl BTreeMap { left_node = edge.descend(); right_node = node.first_edge().descend(); } - (Leaf(_), Leaf(_)) => { break; }, - _ => { unreachable!(); } + (Leaf(_), Leaf(_)) => { + break; + } + _ => { + unreachable!(); + } } } } @@ -950,8 +1005,12 @@ impl BTreeMap { loop { res += dfs(edge.reborrow().descend()); match edge.right_kv() { - Ok(right_kv) => { edge = right_kv.right_edge(); }, - Err(_) => { break; } + Ok(right_kv) => { + edge = right_kv.right_edge(); + } + Err(_) => { + break; + } } } } @@ -1064,14 +1123,16 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> { } impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> { - fn len(&self) -> usize { self.length } + fn len(&self) -> usize { + self.length + } } impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { Iter { range: self.range.clone(), - length: self.length + length: self.length, } } } @@ -1114,7 +1175,9 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> { } impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { - fn len(&self) -> usize { self.length } + fn len(&self) -> usize { + self.length + } } impl IntoIterator for BTreeMap { @@ -1130,14 +1193,15 @@ impl IntoIterator for BTreeMap { IntoIter { front: first_leaf_edge(root1), back: last_leaf_edge(root2), - length: len + length: len, } } } impl Drop for IntoIter { fn drop(&mut self) { - for _ in &mut *self { } + for _ in &mut *self { + } unsafe { let leaf_node = ptr::read(&self.front).into_node(); if let Some(first_parent) = leaf_node.deallocate_and_ascend() { @@ -1168,10 +1232,10 @@ impl Iterator for IntoIter { let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; self.front = kv.right_edge(); return Some((k, v)); - }, + } Err(last_edge) => unsafe { unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()) - } + }, }; loop { @@ -1181,10 +1245,10 @@ impl Iterator for IntoIter { let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; self.front = first_leaf_edge(kv.right_edge().descend()); return Some((k, v)); - }, + } Err(last_edge) => unsafe { cur_handle = unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()); - } + }, } } } @@ -1210,10 +1274,10 @@ impl DoubleEndedIterator for IntoIter { let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; self.back = kv.left_edge(); return Some((k, v)); - }, + } Err(last_edge) => unsafe { unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()) - } + }, }; loop { @@ -1223,17 +1287,19 @@ impl DoubleEndedIterator for IntoIter { let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; self.back = last_leaf_edge(kv.left_edge().descend()); return Some((k, v)); - }, + } Err(last_edge) => unsafe { cur_handle = unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()); - } + }, } } } } impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { self.length } + fn len(&self) -> usize { + self.length + } } impl<'a, K, V> Iterator for Keys<'a, K, V> { @@ -1262,9 +1328,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { impl<'a, K, V> Clone for Keys<'a, K, V> { fn clone(&self) -> Keys<'a, K, V> { - Keys { - inner: self.inner.clone() - } + Keys { inner: self.inner.clone() } } } @@ -1294,9 +1358,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { impl<'a, K, V> Clone for Values<'a, K, V> { fn clone(&self) -> Values<'a, K, V> { - Values { - inner: self.inner.clone() - } + Values { inner: self.inner.clone() } } } @@ -1348,7 +1410,7 @@ impl<'a, K, V> Range<'a, K, V> { let ret = kv.into_kv(); self.front = kv.right_edge(); return ret; - }, + } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); unwrap_unchecked(next_level) @@ -1361,7 +1423,7 @@ impl<'a, K, V> Range<'a, K, V> { let ret = kv.into_kv(); self.front = first_leaf_edge(kv.right_edge().descend()); return ret; - }, + } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); cur_handle = unwrap_unchecked(next_level); @@ -1390,7 +1452,7 @@ impl<'a, K, V> Range<'a, K, V> { let ret = kv.into_kv(); self.back = kv.left_edge(); return ret; - }, + } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); unwrap_unchecked(next_level) @@ -1403,7 +1465,7 @@ impl<'a, K, V> Range<'a, K, V> { let ret = kv.into_kv(); self.back = last_leaf_edge(kv.left_edge().descend()); return ret; - }, + } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); cur_handle = unwrap_unchecked(next_level); @@ -1417,7 +1479,7 @@ impl<'a, K, V> Clone for Range<'a, K, V> { fn clone(&self) -> Range<'a, K, V> { Range { front: self.front, - back: self.back + back: self.back, } } } @@ -1429,7 +1491,7 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> { if self.front == self.back { None } else { - unsafe { Some (self.next_unchecked()) } + unsafe { Some(self.next_unchecked()) } } } } @@ -1443,7 +1505,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { let (k, v) = ptr::read(&kv).into_kv_mut(); self.front = kv.right_edge(); return (k, v); - }, + } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); unwrap_unchecked(next_level) @@ -1456,7 +1518,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { let (k, v) = ptr::read(&kv).into_kv_mut(); self.front = first_leaf_edge(kv.right_edge().descend()); return (k, v); - }, + } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); cur_handle = unwrap_unchecked(next_level); @@ -1485,7 +1547,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { let (k, v) = ptr::read(&kv).into_kv_mut(); self.back = kv.left_edge(); return (k, v); - }, + } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); unwrap_unchecked(next_level) @@ -1498,7 +1560,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { let (k, v) = ptr::read(&kv).into_kv_mut(); self.back = last_leaf_edge(kv.left_edge().descend()); return (k, v); - }, + } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); cur_handle = unwrap_unchecked(next_level); @@ -1509,7 +1571,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { } impl FromIterator<(K, V)> for BTreeMap { - fn from_iter>(iter: T) -> BTreeMap { + fn from_iter>(iter: T) -> BTreeMap { let mut map = BTreeMap::new(); map.extend(iter); map @@ -1518,7 +1580,7 @@ impl FromIterator<(K, V)> for BTreeMap { impl Extend<(K, V)> for BTreeMap { #[inline] - fn extend>(&mut self, iter: T) { + fn extend>(&mut self, iter: T) { for (k, v) in iter { self.insert(k, v); } @@ -1526,7 +1588,7 @@ impl Extend<(K, V)> for BTreeMap { } impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap { - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); } } @@ -1547,8 +1609,7 @@ impl Default for BTreeMap { impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { - self.len() == other.len() && - self.iter().zip(other).all(|(a, b)| a == b) + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) } } @@ -1575,7 +1636,8 @@ impl Debug for BTreeMap { } impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap - where K: Borrow, Q: Ord + where K: Borrow, + Q: Ord { type Output = V; @@ -1585,11 +1647,9 @@ impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap } } -fn first_leaf_edge( - mut node: NodeRef - ) -> Handle, marker::Edge> { +fn first_leaf_edge + (mut node: NodeRef) + -> Handle, marker::Edge> { loop { match node.force() { Leaf(leaf) => return leaf.first_edge(), @@ -1600,11 +1660,9 @@ fn first_leaf_edge( } } -fn last_leaf_edge( - mut node: NodeRef - ) -> Handle, marker::Edge> { +fn last_leaf_edge + (mut node: NodeRef) + -> Handle, marker::Edge> { loop { match node.force() { Leaf(leaf) => return leaf.last_edge(), @@ -1653,9 +1711,9 @@ impl BTreeMap { Iter { range: Range { front: first_leaf_edge(self.root.as_ref()), - back: last_leaf_edge(self.root.as_ref()) + back: last_leaf_edge(self.root.as_ref()), }, - length: self.length + length: self.length, } } @@ -1690,7 +1748,7 @@ impl BTreeMap { back: last_leaf_edge(root2), _marker: PhantomData, }, - length: self.length + length: self.length, } } @@ -1865,15 +1923,17 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { loop { match cur_parent { - Ok(parent) => match parent.insert(ins_k, ins_v, ins_edge) { - Fit(_) => return unsafe { &mut *out_ptr }, - Split(left, k, v, right) => { - ins_k = k; - ins_v = v; - ins_edge = right; - cur_parent = left.ascend().map_err(|n| n.into_root_mut()); + Ok(parent) => { + match parent.insert(ins_k, ins_v, ins_edge) { + Fit(_) => return unsafe { &mut *out_ptr }, + Split(left, k, v, right) => { + ins_k = k; + ins_v = v; + ins_edge = right; + cur_parent = left.ascend().map_err(|n| n.into_root_mut()); + } } - }, + } Err(root) => { root.push_level().push(ins_k, ins_v, ins_edge); return unsafe { &mut *out_ptr }; @@ -1928,7 +1988,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { Leaf(leaf) => { let (hole, old_key, old_val) = leaf.remove(); (hole.into_node(), old_key, old_val) - }, + } Internal(mut internal) => { let key_loc = internal.kv_mut().0 as *mut K; let val_loc = internal.kv_mut().1 as *mut V; @@ -1938,12 +1998,8 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { let (hole, key, val) = to_remove.remove(); - let old_key = unsafe { - mem::replace(&mut *key_loc, key) - }; - let old_val = unsafe { - mem::replace(&mut *val_loc, val) - }; + let old_key = unsafe { mem::replace(&mut *key_loc, key) }; + let old_val = unsafe { mem::replace(&mut *val_loc, val) }; (hole.into_node(), old_key, old_val) } @@ -1955,14 +2011,16 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { match handle_underfull_node(cur_node) { AtRoot => break, EmptyParent(_) => unreachable!(), - Merged(parent) => if parent.len() == 0 { - // We must be at the root - parent.into_root_mut().pop_level(); - break; - } else { - cur_node = parent.forget_type(); - }, - Stole(_) => break + Merged(parent) => { + if parent.len() == 0 { + // We must be at the root + parent.into_root_mut().pop_level(); + break; + } else { + cur_node = parent.forget_type(); + } + } + Stole(_) => break, } } @@ -1974,13 +2032,11 @@ enum UnderflowResult<'a, K, V> { AtRoot, EmptyParent(NodeRef, K, V, marker::Internal>), Merged(NodeRef, K, V, marker::Internal>), - Stole(NodeRef, K, V, marker::Internal>) + Stole(NodeRef, K, V, marker::Internal>), } -fn handle_underfull_node<'a, K, V>(node: NodeRef, - K, V, - marker::LeafOrInternal>) - -> UnderflowResult<'a, K, V> { +fn handle_underfull_node<'a, K, V>(node: NodeRef, K, V, marker::LeafOrInternal>) + -> UnderflowResult<'a, K, V> { let parent = if let Ok(parent) = node.ascend() { parent } else { @@ -1989,10 +2045,12 @@ fn handle_underfull_node<'a, K, V>(node: NodeRef, let (is_left, mut handle) = match parent.left_kv() { Ok(left) => (true, left), - Err(parent) => match parent.right_kv() { - Ok(right) => (false, right), - Err(parent) => { - return EmptyParent(parent.into_node()); + Err(parent) => { + match parent.right_kv() { + Ok(right) => (false, right), + Err(parent) => { + return EmptyParent(parent.into_node()); + } } } }; @@ -2009,7 +2067,7 @@ fn handle_underfull_node<'a, K, V>(node: NodeRef, } } -impl> Iterator for MergeIter { +impl> Iterator for MergeIter { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { @@ -2023,16 +2081,12 @@ impl> Iterator for MergeIter { // Check which elements comes first and only advance the corresponding iterator. // If two keys are equal, take the value from `right`. match res { - Ordering::Less => { - self.left.next() - }, - Ordering::Greater => { - self.right.next() - }, + Ordering::Less => self.left.next(), + Ordering::Greater => self.right.next(), Ordering::Equal => { self.left.next(); self.right.next() - }, + } } } } diff --git a/src/libcore/any.rs b/src/libcore/any.rs index dfd2ba9154d53..49304b1f3bfa1 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -85,7 +85,7 @@ use marker::{Reflect, Sized}; /// A type to emulate dynamic typing. /// -/// Every type with no non-`'static` references implements `Any`. +/// Most types implement `Any`. However, any type which contains a non-`'static` reference does not. /// See the [module-level documentation][mod] for more details. /// /// [mod]: index.html diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 658b1312c496d..47d9deb62ff65 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -289,7 +289,7 @@ impl AtomicBool { /// Stores a value into the `bool` if the current value is the same as the `current` value. /// /// The return value is a result indicating whether the new value was written and containing - /// the previous value. On success this value is guaranteed to be equal to `new`. + /// the previous value. On success this value is guaranteed to be equal to `current`. /// /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this /// operation. The first describes the required ordering if the operation succeeds while the @@ -633,7 +633,7 @@ impl AtomicPtr { /// Stores a value into the pointer if the current value is the same as the `current` value. /// /// The return value is a result indicating whether the new value was written and containing - /// the previous value. On success this value is guaranteed to be equal to `new`. + /// the previous value. On success this value is guaranteed to be equal to `current`. /// /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this /// operation. The first describes the required ordering if the operation succeeds while the @@ -886,7 +886,7 @@ macro_rules! atomic_int { /// /// The return value is a result indicating whether the new value was written and /// containing the previous value. On success this value is guaranteed to be equal to - /// `new`. + /// `current`. /// /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of /// this operation. The first describes the required ordering if the operation succeeds diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index e783420fa065c..2f09024dec778 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -198,31 +198,21 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } /// Returns whether this lvalue is tracked by drop elaboration. This - /// includes all lvalues, except these behind references or arrays. - /// - /// Lvalues behind references or arrays are not tracked by elaboration - /// and are always assumed to be initialized when accessible. As - /// references and indexes can be reseated, trying to track them - /// can only lead to trouble. + /// includes all lvalues, except these (1.) behind references or arrays, + /// or (2.) behind ADT's with a Drop impl. fn lvalue_is_tracked(&self, lv: &Lvalue<'tcx>) -> bool { + // `lvalue_contents_drop_state_cannot_differ` only compares + // the `lv` to its immediate contents, while this recursively + // follows parent chain formed by `base` of each projection. if let &Lvalue::Projection(ref data) = lv { - self.lvalue_contents_are_tracked(&data.base) + !super::lvalue_contents_drop_state_cannot_differ(self.tcx, self.mir, &data.base) && + self.lvalue_is_tracked(&data.base) } else { true } } - fn lvalue_contents_are_tracked(&self, lv: &Lvalue<'tcx>) -> bool { - let ty = self.mir.lvalue_ty(self.tcx, lv).to_ty(self.tcx); - match ty.sty { - ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => { - false - } - _ => self.lvalue_is_tracked(lv) - } - } - fn collect_drop_flags(&mut self) { for bb in self.mir.all_basic_blocks() { diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 007cde156f40f..32ffce6440bbc 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -235,6 +235,45 @@ fn move_path_children_matching<'tcx, F>(move_paths: &MovePathData<'tcx>, None } +/// When enumerating the child fragments of a path, don't recurse into +/// paths (1.) past arrays, slices, and pointers, nor (2.) into a type +/// that implements `Drop`. +/// +/// Lvalues behind references or arrays are not tracked by elaboration +/// and are always assumed to be initialized when accessible. As +/// references and indexes can be reseated, trying to track them can +/// only lead to trouble. +/// +/// Lvalues behind ADT's with a Drop impl are not tracked by +/// elaboration since they can never have a drop-flag state that +/// differs from that of the parent with the Drop impl. +/// +/// In both cases, the contents can only be accessed if and only if +/// their parents are initialized. This implies for example that there +/// is no need to maintain separate drop flags to track such state. +/// +/// FIXME: we have to do something for moving slice patterns. +fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + lv: &repr::Lvalue<'tcx>) -> bool { + let ty = mir.lvalue_ty(tcx, lv).to_ty(tcx); + match ty.sty { + ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => { + debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => false", + lv, ty); + true + } + ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { + debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", + lv, ty); + true + } + _ => { + false + } + } +} + fn on_all_children_bits<'a, 'tcx, F>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, @@ -251,17 +290,7 @@ fn on_all_children_bits<'a, 'tcx, F>( { match move_data.move_paths[path].content { MovePathContent::Lvalue(ref lvalue) => { - match mir.lvalue_ty(tcx, lvalue).to_ty(tcx).sty { - // don't trace paths past arrays, slices, and - // pointers. They can only be accessed while - // their parents are initialized. - // - // FIXME: we have to do something for moving - // slice patterns. - ty::TyArray(..) | ty::TySlice(..) | - ty::TyRef(..) | ty::TyRawPtr(..) => true, - _ => false - } + lvalue_contents_drop_state_cannot_differ(tcx, mir, lvalue) } _ => true } diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 0624d72dd5993..c6606cc3541b7 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -633,6 +633,62 @@ fn main() { ``` "##, +E0503: r##" +A value was used after it was mutably borrowed. + +Example of erroneous code: + +```compile_fail +fn main() { + let mut value = 3; + // Create a mutable borrow of `value`. This borrow + // lives until the end of this function. + let _borrow = &mut value; + let _sum = value + 1; // error: cannot use `value` because + // it was mutably borrowed +} +``` + +In this example, `value` is mutably borrowed by `borrow` and cannot be +used to calculate `sum`. This is not possible because this would violate +Rust's mutability rules. + +You can fix this error by limiting the scope of the borrow: + +``` +fn main() { + let mut value = 3; + // By creating a new block, you can limit the scope + // of the reference. + { + let _borrow = &mut value; // Use `_borrow` inside this block. + } + // The block has ended and with it the borrow. + // You can now use `value` again. + let _sum = value + 1; +} +``` + +Or by cloning `value` before borrowing it: + +``` +fn main() { + let mut value = 3; + // We clone `value`, creating a copy. + let value_cloned = value.cloned(); + // The mutable borrow is a reference to `value` and + // not to `value_cloned`... + let _borrow = &mut value; + // ... which means we can still use `value_cloned`, + let _sum = value_cloned + 1; + // even though the borrow only ends here. +} +``` + +You can find more information about borrowing in the rust-book: +http://doc.rust-lang.org/stable/book/references-and-borrowing.html +"##, + E0506: r##" This error occurs when an attempt is made to assign to a borrowed value. @@ -911,6 +967,50 @@ You can find more information about borrowing in the rust-book: http://doc.rust-lang.org/stable/book/references-and-borrowing.html "##, +E0508: r##" +A value was moved out of a non-copy fixed-size array. + +Example of erroneous code: + +```compile_fail +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`, + // a non-copy fixed-size array +} +``` + +The first element was moved out of the array, but this is not +possible because `NonCopy` does not implement the `Copy` trait. + +Consider borrowing the element instead of moving it: + +``` +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + let _value = &array[0]; // Borrowing is allowed, unlike moving. +} +``` + +Alternatively, if your type implements `Clone` and you need to own the value, +consider borrowing and then cloning: + +``` +#[derive(Clone)] +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + // Now you can clone the array element. + let _value = array[0].clone(); +} +``` +"##, + E0509: r##" This error occurs when an attempt is made to move out of a value whose type implements the `Drop` trait. @@ -1011,7 +1111,5 @@ fn main() { register_diagnostics! { E0385, // {} in an aliasable location E0388, // {} in a static location - E0503, // cannot use `..` because it was mutably borrowed - E0508, // cannot move out of type `..`, a non-copy fixed-size array E0524, // two closures require unique access to `..` at the same time } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b28d203ed8dc2..41afa43fe28d8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -601,7 +601,8 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session, })?; krate = time(time_passes, "crate injection", || { - syntax::std_inject::maybe_inject_crates_ref(krate, sess.opts.alt_std_name.clone()) + let alt_std_name = sess.opts.alt_std_name.clone(); + syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name) }); let macros = time(time_passes, @@ -720,10 +721,6 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session, sess.diagnostic()) }); - krate = time(time_passes, - "prelude injection", - || syntax::std_inject::maybe_inject_prelude(&sess.parse_sess, krate)); - time(time_passes, "checking for inline asm in case the target doesn't support it", || no_asm::check_crate(sess, &krate)); diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 4c4dea406ba9e..7502317d5fd90 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -10,8 +10,8 @@ use rustc::hir::def::Def; use rustc::ty; -use lint::{LateContext, LintContext, LintArray}; -use lint::{LintPass, LateLintPass}; +use lint::{LateContext, LintArray, LintContext}; +use lint::{LateLintPass, LintPass}; use syntax::ast; use syntax::attr::{self, AttrMetaMethods}; @@ -24,19 +24,21 @@ use rustc::hir::intravisit::FnKind; pub enum MethodLateContext { TraitDefaultImpl, TraitImpl, - PlainImpl + PlainImpl, } pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext { let def_id = cx.tcx.map.local_def_id(id); match cx.tcx.impl_or_trait_items.borrow().get(&def_id) { None => span_bug!(span, "missing method descriptor?!"), - Some(item) => match item.container() { - ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, - ty::ImplContainer(cid) => { - match cx.tcx.impl_trait_ref(cid) { - Some(_) => MethodLateContext::TraitImpl, - None => MethodLateContext::PlainImpl + Some(item) => { + match item.container() { + ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, + ty::ImplContainer(cid) => { + match cx.tcx.impl_trait_ref(cid) { + Some(_) => MethodLateContext::TraitImpl, + None => MethodLateContext::PlainImpl, + } } } } @@ -63,19 +65,22 @@ impl NonCamelCaseTypes { // start with a non-lowercase letter rather than non-uppercase // ones (some scripts don't have a concept of upper/lowercase) - !name.is_empty() && - !name.chars().next().unwrap().is_lowercase() && - !name.contains('_') + !name.is_empty() && !name.chars().next().unwrap().is_lowercase() && !name.contains('_') } fn to_camel_case(s: &str) -> String { - s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)| - if i == 0 { - c.to_uppercase().collect::() - } else { - c.to_lowercase().collect() - } - )).collect::>().concat() + s.split('_') + .flat_map(|word| { + word.chars().enumerate().map(|(i, c)| { + if i == 0 { + c.to_uppercase().collect::() + } else { + c.to_lowercase().collect() + } + }) + }) + .collect::>() + .concat() } let s = name.as_str(); @@ -83,9 +88,14 @@ impl NonCamelCaseTypes { if !is_camel_case(name) { let c = to_camel_case(&s); let m = if c.is_empty() { - format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s) + format!("{} `{}` should have a camel case name such as `CamelCase`", + sort, + s) } else { - format!("{} `{}` should have a camel case name such as `{}`", sort, s, c) + format!("{} `{}` should have a camel case name such as `{}`", + sort, + s, + c) }; cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]); } @@ -100,10 +110,14 @@ impl LintPass for NonCamelCaseTypes { impl LateLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { - let extern_repr_count = it.attrs.iter().filter(|attr| { - attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter() - .any(|r| r == &attr::ReprExtern) - }).count(); + let extern_repr_count = it.attrs + .iter() + .filter(|attr| { + attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr) + .iter() + .any(|r| r == &attr::ReprExtern) + }) + .count(); let has_extern_repr = extern_repr_count > 0; if has_extern_repr { @@ -111,12 +125,8 @@ impl LateLintPass for NonCamelCaseTypes { } match it.node { - hir::ItemTy(..) | hir::ItemStruct(..) => { - self.check_case(cx, "type", it.name, it.span) - } - hir::ItemTrait(..) => { - self.check_case(cx, "trait", it.name, it.span) - } + hir::ItemTy(..) | hir::ItemStruct(..) => self.check_case(cx, "type", it.name, it.span), + hir::ItemTrait(..) => self.check_case(cx, "trait", it.name, it.span), hir::ItemEnum(ref enum_definition, _) => { if has_extern_repr { return; @@ -126,7 +136,7 @@ impl LateLintPass for NonCamelCaseTypes { self.check_case(cx, "variant", variant.node.name, variant.span); } } - _ => () + _ => (), } } @@ -165,9 +175,7 @@ impl NonSnakeCase { continue; } for ch in s.chars() { - if !buf.is_empty() && buf != "'" - && ch.is_uppercase() - && !last_upper { + if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper { words.push(buf); buf = String::new(); } @@ -205,10 +213,11 @@ impl NonSnakeCase { let sc = NonSnakeCase::to_snake_case(name); let msg = if sc != name { format!("{} `{}` should have a snake case name such as `{}`", - sort, name, sc) + sort, + name, + sc) } else { - format!("{} `{}` should have a snake case name", - sort, name) + format!("{} `{}` should have a snake case name", sort, name) }; match span { Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg), @@ -226,8 +235,10 @@ impl LintPass for NonSnakeCase { impl LateLintPass for NonSnakeCase { fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) { - let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name")) - .and_then(|at| at.value_str().map(|s| (at, s))); + let attr_crate_name = cr.attrs + .iter() + .find(|at| at.check_name("crate_name")) + .and_then(|at| at.value_str().map(|s| (at, s))); if let Some(ref name) = cx.tcx.sess.opts.crate_name { self.check_snake_case(cx, "crate", name, None); } else if let Some((attr, ref name)) = attr_crate_name { @@ -235,22 +246,28 @@ impl LateLintPass for NonSnakeCase { } } - fn check_fn(&mut self, cx: &LateContext, - fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, span: Span, id: ast::NodeId) { + fn check_fn(&mut self, + cx: &LateContext, + fk: FnKind, + _: &hir::FnDecl, + _: &hir::Block, + span: Span, + id: ast::NodeId) { match fk { - FnKind::Method(name, _, _, _) => match method_context(cx, id, span) { - MethodLateContext::PlainImpl => { - self.check_snake_case(cx, "method", &name.as_str(), Some(span)) - }, - MethodLateContext::TraitDefaultImpl => { - self.check_snake_case(cx, "trait method", &name.as_str(), Some(span)) - }, - _ => (), - }, + FnKind::Method(name, _, _, _) => { + match method_context(cx, id, span) { + MethodLateContext::PlainImpl => { + self.check_snake_case(cx, "method", &name.as_str(), Some(span)) + } + MethodLateContext::TraitDefaultImpl => { + self.check_snake_case(cx, "trait method", &name.as_str(), Some(span)) + } + _ => (), + } + } FnKind::ItemFn(name, _, _, _, _, _, _) => { self.check_snake_case(cx, "function", &name.as_str(), Some(span)) - }, + } FnKind::Closure(_) => (), } } @@ -263,13 +280,17 @@ impl LateLintPass for NonSnakeCase { fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { if let hir::MethodTraitItem(_, None) = trait_item.node { - self.check_snake_case(cx, "trait method", &trait_item.name.as_str(), + self.check_snake_case(cx, + "trait method", + &trait_item.name.as_str(), Some(trait_item.span)); } } fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) { - self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(), + self.check_snake_case(cx, + "lifetime", + &t.lifetime.name.as_str(), Some(t.lifetime.span)); } @@ -282,8 +303,12 @@ impl LateLintPass for NonSnakeCase { } } - fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData, - _: ast::Name, _: &hir::Generics, _: ast::NodeId) { + fn check_struct_def(&mut self, + cx: &LateContext, + s: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + _: ast::NodeId) { for sf in s.fields() { self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span)); } @@ -306,13 +331,16 @@ impl NonUpperCaseGlobals { if s.chars().any(|c| c.is_lowercase()) { let uc = NonSnakeCase::to_snake_case(&s).to_uppercase(); if uc != &s[..] { - cx.span_lint(NON_UPPER_CASE_GLOBALS, span, - &format!("{} `{}` should have an upper case name such as `{}`", - sort, s, uc)); + cx.span_lint(NON_UPPER_CASE_GLOBALS, + span, + &format!("{} `{}` should have an upper case name such as `{}`", + sort, + s, + uc)); } else { - cx.span_lint(NON_UPPER_CASE_GLOBALS, span, - &format!("{} `{}` should have an upper case name", - sort, s)); + cx.span_lint(NON_UPPER_CASE_GLOBALS, + span, + &format!("{} `{}` should have an upper case name", sort, s)); } } } @@ -341,8 +369,7 @@ impl LateLintPass for NonUpperCaseGlobals { fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) { match ti.node { hir::ConstTraitItem(..) => { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", - ti.name, ti.span); + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span); } _ => {} } @@ -351,8 +378,7 @@ impl LateLintPass for NonUpperCaseGlobals { fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) { match ii.node { hir::ImplItemKind::Const(..) => { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", - ii.name, ii.span); + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span); } _ => {} } @@ -362,10 +388,15 @@ impl LateLintPass for NonUpperCaseGlobals { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(ref path) = p.node { if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { - if let Some(Def::Const(..)) = cx.tcx.def_map.borrow().get(&p.id) - .map(|d| d.full_def()) { - NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", - path.segments[0].name, path.span); + if let Some(Def::Const(..)) = cx.tcx + .def_map + .borrow() + .get(&p.id) + .map(|d| d.full_def()) { + NonUpperCaseGlobals::check_upper_case(cx, + "constant in pattern", + path.segments[0].name, + path.span); } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3005f564ff41a..6af99e2a95ede 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -37,13 +37,13 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::adjustment; use rustc::traits::{self, ProjectionMode}; use rustc::hir::map as hir_map; -use util::nodemap::{NodeSet}; -use lint::{Level, LateContext, LintContext, LintArray, Lint}; -use lint::{LintPass, LateLintPass}; +use util::nodemap::NodeSet; +use lint::{LateContext, Level, Lint, LintArray, LintContext}; +use lint::{LateLintPass, LintPass}; use std::collections::HashSet; -use syntax::{ast}; +use syntax::ast; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{self, Span}; @@ -75,7 +75,8 @@ impl LateLintPass for WhileTrue { if let hir::ExprWhile(ref cond, _, _) = e.node { if let hir::ExprLit(ref lit) = cond.node { if let ast::LitKind::Bool(true) = lit.node { - cx.span_lint(WHILE_TRUE, e.span, + cx.span_lint(WHILE_TRUE, + e.span, "denote infinite loops with loop { ... }"); } } @@ -93,8 +94,7 @@ declare_lint! { pub struct BoxPointers; impl BoxPointers { - fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, - span: Span, ty: Ty<'tcx>) { + fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) { for leaf_ty in ty.walk() { if let ty::TyBox(_) = leaf_ty.sty { let m = format!("type uses owned (Box type) pointers: {}", ty); @@ -116,21 +116,20 @@ impl LateLintPass for BoxPointers { hir::ItemFn(..) | hir::ItemTy(..) | hir::ItemEnum(..) | - hir::ItemStruct(..) => - self.check_heap_type(cx, it.span, - cx.tcx.node_id_to_type(it.id)), - _ => () + hir::ItemStruct(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)), + _ => (), } // If it's a struct, we also have to check the fields' types match it.node { hir::ItemStruct(ref struct_def, _) => { for struct_field in struct_def.fields() { - self.check_heap_type(cx, struct_field.span, + self.check_heap_type(cx, + struct_field.span, cx.tcx.node_id_to_type(struct_field.id)); } } - _ => () + _ => (), } } @@ -173,9 +172,11 @@ impl LateLintPass for NonShorthandFieldPatterns { for fieldpat in field_pats { if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node { if ident.node.unhygienize() == fieldpat.node.name { - cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, + cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, + fieldpat.span, &format!("the `{}:` in this pattern is redundant and can \ - be removed", ident.node)) + be removed", + ident.node)) } } } @@ -210,27 +211,35 @@ impl LateLintPass for UnsafeCode { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { - hir::ItemTrait(hir::Unsafety::Unsafe, _, _, _) => - cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"), + hir::ItemTrait(hir::Unsafety::Unsafe, _, _, _) => { + cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait") + } - hir::ItemImpl(hir::Unsafety::Unsafe, _, _, _, _, _) => - cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"), + hir::ItemImpl(hir::Unsafety::Unsafe, _, _, _, _, _) => { + cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait") + } _ => return, } } - fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, span: Span, _: ast::NodeId) { + fn check_fn(&mut self, + cx: &LateContext, + fk: FnKind, + _: &hir::FnDecl, + _: &hir::Block, + span: Span, + _: ast::NodeId) { match fk { - FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, _, _, _, _) => - cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"), + FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, _, _, _, _) => { + cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function") + } FnKind::Method(_, sig, _, _) => { if sig.unsafety == hir::Unsafety::Unsafe { cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method") } - }, + } _ => (), } @@ -239,7 +248,8 @@ impl LateLintPass for UnsafeCode { fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { if let hir::MethodTraitItem(ref sig, None) = trait_item.node { if sig.unsafety == hir::Unsafety::Unsafe { - cx.span_lint(UNSAFE_CODE, trait_item.span, + cx.span_lint(UNSAFE_CODE, + trait_item.span, "declaration of an `unsafe` method") } } @@ -270,9 +280,9 @@ pub struct MissingDoc { impl MissingDoc { pub fn new() -> MissingDoc { MissingDoc { - struct_def_stack: vec!(), + struct_def_stack: vec![], in_variant: false, - doc_hidden_stack: vec!(false), + doc_hidden_stack: vec![false], private_traits: HashSet::new(), } } @@ -282,11 +292,11 @@ impl MissingDoc { } fn check_missing_docs_attrs(&self, - cx: &LateContext, - id: Option, - attrs: &[ast::Attribute], - sp: Span, - desc: &'static str) { + cx: &LateContext, + id: Option, + attrs: &[ast::Attribute], + sp: Span, + 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 { @@ -310,11 +320,12 @@ impl MissingDoc { let has_doc = attrs.iter().any(|a| { match a.node.value.node { ast::MetaItemKind::NameValue(ref name, _) if *name == "doc" => true, - _ => false + _ => false, } }); if !has_doc { - cx.span_lint(MISSING_DOCS, sp, + cx.span_lint(MISSING_DOCS, + sp, &format!("missing documentation for {}", desc)); } } @@ -328,8 +339,10 @@ impl LintPass for MissingDoc { impl LateLintPass for MissingDoc { fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) { - let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { - attr.check_name("doc") && match attr.meta_item_list() { + let doc_hidden = self.doc_hidden() || + attrs.iter().any(|attr| { + attr.check_name("doc") && + match attr.meta_item_list() { None => false, Some(l) => attr::contains_name(&l[..], "hidden"), } @@ -341,13 +354,21 @@ impl LateLintPass for MissingDoc { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData, - _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) { + fn check_struct_def(&mut self, + _: &LateContext, + _: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + item_id: ast::NodeId) { self.struct_def_stack.push(item_id); } - fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData, - _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) { + fn check_struct_def_post(&mut self, + _: &LateContext, + _: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + item_id: ast::NodeId) { let popped = self.struct_def_stack.pop().expect("empty struct_def_stack"); assert!(popped == item_id); } @@ -369,10 +390,10 @@ impl LateLintPass for MissingDoc { for itm in items { self.private_traits.insert(itm.id); } - return + return; } "a trait" - }, + } hir::ItemTy(..) => "a type alias", hir::ItemImpl(_, _, _, Some(ref trait_ref), _, ref impl_items) => { // If the trait is private, add the impl items to private_traits so they don't get @@ -380,26 +401,30 @@ impl LateLintPass for MissingDoc { let real_trait = cx.tcx.trait_ref_to_def_id(trait_ref); if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) { match cx.tcx.map.find(node_id) { - Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited { - for itm in impl_items { - self.private_traits.insert(itm.id); + Some(hir_map::NodeItem(item)) => { + if item.vis == hir::Visibility::Inherited { + for itm in impl_items { + self.private_traits.insert(itm.id); + } } - }, - _ => { } + } + _ => {} } } - return - }, + return; + } hir::ItemConst(..) => "a constant", hir::ItemStatic(..) => "a static", - _ => return + _ => return, }; self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc); } fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { - if self.private_traits.contains(&trait_item.id) { return } + if self.private_traits.contains(&trait_item.id) { + return; + } let desc = match trait_item.node { hir::ConstTraitItem(..) => "an associated constant", @@ -407,9 +432,11 @@ impl LateLintPass for MissingDoc { hir::TypeTraitItem(..) => "an associated type", }; - self.check_missing_docs_attrs(cx, Some(trait_item.id), + self.check_missing_docs_attrs(cx, + Some(trait_item.id), &trait_item.attrs, - trait_item.span, desc); + trait_item.span, + desc); } fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { @@ -423,26 +450,34 @@ impl LateLintPass for MissingDoc { hir::ImplItemKind::Method(..) => "a method", hir::ImplItemKind::Type(_) => "an associated type", }; - self.check_missing_docs_attrs(cx, Some(impl_item.id), + self.check_missing_docs_attrs(cx, + Some(impl_item.id), &impl_item.attrs, - impl_item.span, desc); + impl_item.span, + desc); } fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) { if !sf.is_positional() { if sf.vis == hir::Public || self.in_variant { - let cur_struct_def = *self.struct_def_stack.last() - .expect("empty struct_def_stack"); - self.check_missing_docs_attrs(cx, Some(cur_struct_def), - &sf.attrs, sf.span, + let cur_struct_def = *self.struct_def_stack + .last() + .expect("empty struct_def_stack"); + self.check_missing_docs_attrs(cx, + Some(cur_struct_def), + &sf.attrs, + sf.span, "a struct field") } } } fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) { - self.check_missing_docs_attrs(cx, Some(v.node.data.id()), - &v.node.attrs, v.span, "a variant"); + self.check_missing_docs_attrs(cx, + Some(v.node.data.id()), + &v.node.attrs, + v.span, + "a variant"); assert!(!self.in_variant); self.in_variant = true; } @@ -479,20 +514,20 @@ impl LateLintPass for MissingCopyImplementations { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_struct(def, - cx.tcx.mk_substs(Substs::empty()))) + (def, cx.tcx.mk_struct(def, cx.tcx.mk_substs(Substs::empty()))) } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_enum(def, - cx.tcx.mk_substs(Substs::empty()))) + (def, cx.tcx.mk_enum(def, cx.tcx.mk_substs(Substs::empty()))) } _ => return, }; - if def.has_dtor() { return; } + if def.has_dtor() { + return; + } let parameter_environment = cx.tcx.empty_parameter_environment(); // FIXME (@jroesch) should probably inver this so that the parameter env still impls this // method @@ -520,9 +555,7 @@ pub struct MissingDebugImplementations { impl MissingDebugImplementations { pub fn new() -> MissingDebugImplementations { - MissingDebugImplementations { - impling_types: None, - } + MissingDebugImplementations { impling_types: None } } } @@ -539,7 +572,7 @@ impl LateLintPass for MissingDebugImplementations { } match item.node { - hir::ItemStruct(..) | hir::ItemEnum(..) => {}, + hir::ItemStruct(..) | hir::ItemEnum(..) => {} _ => return, } @@ -585,8 +618,12 @@ declare_lint! { pub struct Deprecated; impl Deprecated { - fn lint(&self, cx: &LateContext, _id: DefId, span: Span, - stability: &Option<&attr::Stability>, deprecation: &Option) { + fn lint(&self, + cx: &LateContext, + _id: DefId, + span: Span, + stability: &Option<&attr::Stability>, + deprecation: &Option) { // Deprecated attributes apply in-crate and cross-crate. if let Some(&attr::Stability{rustc_depr: Some(attr::RustcDeprecation{ref reason, ..}), ..}) = *stability { @@ -615,33 +652,37 @@ impl LintPass for Deprecated { impl LateLintPass for Deprecated { fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { - stability::check_item(cx.tcx, item, false, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_item(cx.tcx, + item, + false, + &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { - stability::check_expr(cx.tcx, e, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_expr(cx.tcx, + e, + &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) { - stability::check_path(cx.tcx, path, id, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_path(cx.tcx, + path, + id, + &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) { - stability::check_path_list_item(cx.tcx, item, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_path_list_item(cx.tcx, + item, + &mut |id, sp, stab, depr| { + self.lint(cx, id, sp, &stab, &depr) + }); } fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { - stability::check_pat(cx.tcx, pat, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_pat(cx.tcx, + pat, + &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } } @@ -662,15 +703,20 @@ impl LintPass for UnconditionalRecursion { } impl LateLintPass for UnconditionalRecursion { - fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl, - blk: &hir::Block, sp: Span, id: ast::NodeId) { + fn check_fn(&mut self, + cx: &LateContext, + fn_kind: FnKind, + _: &hir::FnDecl, + blk: &hir::Block, + sp: Span, + id: ast::NodeId) { let method = match fn_kind { FnKind::ItemFn(..) => None, FnKind::Method(..) => { cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method() } // closures can't recur, so they don't matter. - FnKind::Closure(_) => return + FnKind::Closure(_) => return, }; // Walk through this function (say `f`) looking to see if @@ -725,10 +771,8 @@ impl LateLintPass for UnconditionalRecursion { // is this a recursive call? let self_recursive = if node_id != ast::DUMMY_NODE_ID { match method { - Some(ref method) => { - expr_refers_to_this_method(cx.tcx, method, node_id) - } - None => expr_refers_to_this_fn(cx.tcx, id, node_id) + Some(ref method) => expr_refers_to_this_method(cx.tcx, method, node_id), + None => expr_refers_to_this_fn(cx.tcx, id, node_id), } } else { false @@ -754,7 +798,8 @@ impl LateLintPass for UnconditionalRecursion { // no break */ }`) shouldn't be linted unless it actually // recurs. if !reached_exit_without_self_call && !self_call_spans.is_empty() { - let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp, + let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, + sp, "function cannot return without recurring"); // FIXME #19668: these could be span_lint_note's instead of this manual guard. @@ -775,25 +820,23 @@ impl LateLintPass for UnconditionalRecursion { // Functions for identifying if the given Expr NodeId `id` // represents a call to the function `fn_id`/method `method`. - fn expr_refers_to_this_fn(tcx: TyCtxt, - fn_id: ast::NodeId, - id: ast::NodeId) -> bool { + fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool { match tcx.map.get(id) { hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => { tcx.def_map .borrow() .get(&callee.id) - .map_or(false, - |def| def.def_id() == tcx.map.local_def_id(fn_id)) + .map_or(false, |def| def.def_id() == tcx.map.local_def_id(fn_id)) } - _ => false + _ => false, } } // Check if the expression `id` performs a call to `method`. fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, method: &ty::Method, - id: ast::NodeId) -> bool { + id: ast::NodeId) + -> bool { // Check for method calls and overloaded operators. let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned(); if let Some(m) = opt_m { @@ -807,9 +850,11 @@ impl LateLintPass for UnconditionalRecursion { if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj { for i in 0..adj.autoderefs { let method_call = ty::MethodCall::autoderef(id, i as u32); - if let Some(m) = tcx.tables.borrow().method_map - .get(&method_call) - .cloned() { + if let Some(m) = tcx.tables + .borrow() + .method_map + .get(&method_call) + .cloned() { if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { return true; } @@ -823,13 +868,16 @@ impl LateLintPass for UnconditionalRecursion { match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) { Some(Def::Method(def_id)) => { let item_substs = tcx.node_id_item_substs(callee.id); - method_call_refers_to_method( - tcx, method, def_id, &item_substs.substs, id) + method_call_refers_to_method(tcx, + method, + def_id, + &item_substs.substs, + id) } - _ => false + _ => false, } } - _ => false + _ => false, } } @@ -839,15 +887,14 @@ impl LateLintPass for UnconditionalRecursion { method: &ty::Method, callee_id: DefId, callee_substs: &Substs<'tcx>, - expr_id: ast::NodeId) -> bool { + expr_id: ast::NodeId) + -> bool { let callee_item = tcx.impl_or_trait_item(callee_id); match callee_item.container() { // This is an inherent method, so the `def_id` refers // directly to the method definition. - ty::ImplContainer(_) => { - callee_id == method.def_id - } + ty::ImplContainer(_) => callee_id == method.def_id, // A trait method, from any number of possible sources. // Attempt to select a concrete impl before checking. @@ -886,13 +933,12 @@ impl LateLintPass for UnconditionalRecursion { let container = ty::ImplContainer(vtable_impl.impl_def_id); // It matches if it comes from the same impl, // and has the same method name. - container == method.container - && callee_item.name() == method.name + container == method.container && callee_item.name() == method.name } // There's no way to know if this call is // recursive, so we assume it's not. - _ => false + _ => false, } }) } @@ -939,7 +985,8 @@ impl LateLintPass for PluginAsLibrary { }; if prfn.is_some() { - cx.span_lint(PLUGIN_AS_LIBRARY, it.span, + cx.span_lint(PLUGIN_AS_LIBRARY, + it.span, "compiler plugin used as an ordinary library"); } } @@ -997,15 +1044,15 @@ impl LateLintPass for InvalidNoMangleItems { "generic functions must be mangled"); } } - }, + } hir::ItemStatic(..) => { if attr::contains_name(&it.attrs, "no_mangle") && - !cx.access_levels.is_reachable(it.id) { + !cx.access_levels.is_reachable(it.id) { let msg = format!("static {} is marked #[no_mangle], but not exported", it.name); cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg); } - }, + } hir::ItemConst(..) => { if attr::contains_name(&it.attrs, "no_mangle") { // Const items do not refer to a particular location in memory, and therefore @@ -1015,7 +1062,7 @@ impl LateLintPass for InvalidNoMangleItems { cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg); } } - _ => {}, + _ => {} } } } @@ -1043,19 +1090,21 @@ impl LateLintPass for MutableTransmutes { consider instead using an UnsafeCell"; match get_transmute_from_to(cx, expr) { Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => { - if to_mt.mutbl == hir::Mutability::MutMutable - && from_mt.mutbl == hir::Mutability::MutImmutable { + if to_mt.mutbl == hir::Mutability::MutMutable && + from_mt.mutbl == hir::Mutability::MutImmutable { cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg); } } - _ => () + _ => (), } - fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) - -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> { + fn get_transmute_from_to<'a, 'tcx> + (cx: &LateContext<'a, 'tcx>, + expr: &hir::Expr) + -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> { match expr.node { hir::ExprPath(..) => (), - _ => return None + _ => return None, } if let Def::Fn(did) = cx.tcx.resolve_expr(expr) { if !def_id_is_transmute(cx, did) { @@ -1068,8 +1117,8 @@ impl LateLintPass for MutableTransmutes { let from = bare_fn.sig.0.inputs[0]; return Some((&from.sty, &to.sty)); } - }, - _ => () + } + _ => (), } } None @@ -1078,7 +1127,7 @@ impl LateLintPass for MutableTransmutes { fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { match cx.tcx.lookup_item_type(def_id).ty.sty { ty::TyFnDef(_, _, ref bfty) if bfty.abi == RustIntrinsic => (), - _ => return false + _ => return false, } cx.tcx.item_name(def_id).as_str() == "transmute" } @@ -1133,7 +1182,8 @@ impl LintPass for DropWithReprExtern { impl LateLintPass for DropWithReprExtern { fn check_crate(&mut self, ctx: &LateContext, _: &hir::Crate) { let drop_trait = match ctx.tcx.lang_items.drop_trait() { - Some(id) => ctx.tcx.lookup_trait_def(id), None => { return } + Some(id) => ctx.tcx.lookup_trait_def(id), + None => return, }; drop_trait.for_each_impl(ctx.tcx, |drop_impl_did| { if !drop_impl_did.is_local() { @@ -1147,17 +1197,19 @@ impl LateLintPass for DropWithReprExtern { let self_type_did = self_type_def.did; let hints = ctx.tcx.lookup_repr_hints(self_type_did); if hints.iter().any(|attr| *attr == attr::ReprExtern) && - self_type_def.dtor_kind().has_drop_flag() { - let drop_impl_span = ctx.tcx.map.def_id_span(drop_impl_did, - codemap::DUMMY_SP); - let self_defn_span = ctx.tcx.map.def_id_span(self_type_did, - codemap::DUMMY_SP); + self_type_def.dtor_kind().has_drop_flag() { + let drop_impl_span = ctx.tcx + .map + .def_id_span(drop_impl_did, codemap::DUMMY_SP); + let self_defn_span = ctx.tcx + .map + .def_id_span(self_type_did, codemap::DUMMY_SP); ctx.span_lint_note(DROP_WITH_REPR_EXTERN, drop_impl_span, "implementing Drop adds hidden state to types, \ possibly conflicting with `#[repr(C)]`", - self_defn_span, - "the `#[repr(C)]` attribute is attached here"); + self_defn_span, + "the `#[repr(C)]` attribute is attached here"); } } _ => {} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index ed12d0d9f3c11..839176c21a474 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -46,10 +46,10 @@ extern crate log; extern crate rustc_back; extern crate rustc_const_eval; -pub use rustc::lint as lint; -pub use rustc::middle as middle; -pub use rustc::session as session; -pub use rustc::util as util; +pub use rustc::lint; +pub use rustc::middle; +pub use rustc::session; +pub use rustc::util; use session::Session; use lint::LintId; @@ -136,13 +136,24 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { MissingDebugImplementations, ); - add_lint_group!(sess, "bad_style", - NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS); - - add_lint_group!(sess, "unused", - UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE, - UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE, - UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES); + add_lint_group!(sess, + "bad_style", + NON_CAMEL_CASE_TYPES, + NON_SNAKE_CASE, + NON_UPPER_CASE_GLOBALS); + + add_lint_group!(sess, + "unused", + UNUSED_IMPORTS, + UNUSED_VARIABLES, + UNUSED_ASSIGNMENTS, + DEAD_CODE, + UNUSED_MUT, + UNREACHABLE_CODE, + UNUSED_MUST_USE, + UNUSED_UNSAFE, + PATH_STATEMENTS, + UNUSED_ATTRIBUTES); // Guidelines for creating a future incompatibility lint: // @@ -152,7 +163,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { // and include the full URL. // - Later, change lint to error // - Eventually, remove lint - store.register_future_incompatible(sess, vec![ + store.register_future_incompatible(sess, + vec![ FutureIncompatibleInfo { id: LintId::of(PRIVATE_IN_PUBLIC), reference: "the explanation for E0446 (`--explain E0446`)", @@ -213,10 +225,12 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { // Register renamed and removed lints store.register_renamed("unknown_features", "unused_features"); - store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); + store.register_removed("unsigned_negation", + "replaced by negate_unsigned feature gate"); store.register_removed("negate_unsigned", "cast a signed value instead"); store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok"); // This was renamed to raw_pointer_derive, which was then removed, // so it is also considered removed - store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok"); + store.register_removed("raw_pointer_deriving", + "using derive with raw pointers is ok"); } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 892924db6fad8..51362e2e494e9 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -16,12 +16,12 @@ use rustc::ty::{self, Ty, TyCtxt}; use middle::const_val::ConstVal; use rustc_const_eval::eval_const_expr_partial; use rustc_const_eval::EvalHint::ExprTypeChecked; -use util::nodemap::{FnvHashSet}; -use lint::{LateContext, LintContext, LintArray}; -use lint::{LintPass, LateLintPass}; +use util::nodemap::FnvHashSet; +use lint::{LateContext, LintArray, LintContext}; +use lint::{LateLintPass, LintPass}; use std::cmp; -use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; +use std::{f32, f64, i16, i32, i64, i8, u16, u32, u64, u8}; use syntax::ast; use syntax::abi::Abi; @@ -83,15 +83,15 @@ pub struct TypeLimits { impl TypeLimits { pub fn new() -> TypeLimits { - TypeLimits { - negated_expr_id: !0, - } + TypeLimits { negated_expr_id: !0 } } } impl LintPass for TypeLimits { fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS) + lint_array!(UNUSED_COMPARISONS, + OVERFLOWING_LITERALS, + EXCEEDING_BITSHIFTS) } } @@ -103,13 +103,13 @@ impl LateLintPass for TypeLimits { match lit.node { ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => { forbid_unsigned_negation(cx, e.span); - }, + } ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty { forbid_unsigned_negation(cx, e.span); } - }, - _ => () + } + _ => (), } } else { let t = cx.tcx.node_id_to_type(expr.id); @@ -121,10 +121,11 @@ impl LateLintPass for TypeLimits { if self.negated_expr_id != e.id { self.negated_expr_id = expr.id; } - }, + } hir::ExprBinary(binop, ref l, ref r) => { if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) { - cx.span_lint(UNUSED_COMPARISONS, e.span, + cx.span_lint(UNUSED_COMPARISONS, + e.span, "comparison is useless due to type limits"); } @@ -132,30 +133,35 @@ impl LateLintPass for TypeLimits { let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty { ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)), ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)), - _ => None + _ => None, }; if let Some(bits) = opt_ty_bits { let exceeding = if let hir::ExprLit(ref lit) = r.node { - if let ast::LitKind::Int(shift, _) = lit.node { shift >= bits } - else { false } + if let ast::LitKind::Int(shift, _) = lit.node { + shift >= bits + } else { + false + } } else { match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) { Ok(ConstVal::Integral(i)) => { - i.is_negative() || i.to_u64() - .map(|i| i >= bits) - .unwrap_or(true) - }, - _ => { false } + i.is_negative() || + i.to_u64() + .map(|i| i >= bits) + .unwrap_or(true) + } + _ => false, } }; if exceeding { - cx.span_lint(EXCEEDING_BITSHIFTS, e.span, + cx.span_lint(EXCEEDING_BITSHIFTS, + e.span, "bitshift exceeds the type's number of bits"); } }; } - }, + } hir::ExprLit(ref lit) => { match cx.tcx.node_id_to_type(e.id).sty { ty::TyInt(t) => { @@ -174,14 +180,15 @@ impl LateLintPass for TypeLimits { // avoiding use of -min to prevent overflow/panic if (negative && v > max as u64 + 1) || (!negative && v > max as u64) { - cx.span_lint(OVERFLOWING_LITERALS, e.span, + cx.span_lint(OVERFLOWING_LITERALS, + e.span, &format!("literal out of range for {:?}", t)); return; } } - _ => bug!() + _ => bug!(), }; - }, + } ty::TyUint(t) => { let uint_type = if let ast::UintTy::Us = t { cx.sess().target.uint_type @@ -193,13 +200,14 @@ impl LateLintPass for TypeLimits { // _v is u8, within range by definition ast::LitKind::Byte(_v) => return, ast::LitKind::Int(v, _) => v, - _ => bug!() + _ => bug!(), }; if lit_val < min || lit_val > max { - cx.span_lint(OVERFLOWING_LITERALS, e.span, + cx.span_lint(OVERFLOWING_LITERALS, + e.span, &format!("literal out of range for {:?}", t)); } - }, + } ty::TyFloat(t) => { let (min, max) = float_ty_range(t); let lit_val: f64 = match lit.node { @@ -207,70 +215,71 @@ impl LateLintPass for TypeLimits { ast::LitKind::FloatUnsuffixed(ref v) => { match v.parse() { Ok(f) => f, - Err(_) => return + Err(_) => return, } } - _ => bug!() + _ => bug!(), }; if lit_val < min || lit_val > max { - cx.span_lint(OVERFLOWING_LITERALS, e.span, + cx.span_lint(OVERFLOWING_LITERALS, + e.span, &format!("literal out of range for {:?}", t)); } - }, - _ => () + } + _ => (), }; - }, - _ => () + } + _ => (), }; - fn is_valid(binop: hir::BinOp, v: T, - min: T, max: T) -> bool { + fn is_valid(binop: hir::BinOp, v: T, min: T, max: T) -> bool { match binop.node { - hir::BiLt => v > min && v <= max, - hir::BiLe => v >= min && v < max, - hir::BiGt => v >= min && v < max, - hir::BiGe => v > min && v <= max, + hir::BiLt => v > min && v <= max, + hir::BiLe => v >= min && v < max, + hir::BiGt => v >= min && v < max, + hir::BiGe => v > min && v <= max, hir::BiEq | hir::BiNe => v >= min && v <= max, - _ => bug!() + _ => bug!(), } } fn rev_binop(binop: hir::BinOp) -> hir::BinOp { - codemap::respan(binop.span, match binop.node { - hir::BiLt => hir::BiGt, - hir::BiLe => hir::BiGe, - hir::BiGt => hir::BiLt, - hir::BiGe => hir::BiLe, - _ => return binop - }) + codemap::respan(binop.span, + match binop.node { + hir::BiLt => hir::BiGt, + hir::BiLe => hir::BiGe, + hir::BiGt => hir::BiLt, + hir::BiGe => hir::BiLe, + _ => return binop, + }) } // 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::IntTy::Is => (i64::MIN, i64::MAX), - ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64), - ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64), - ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64), - ast::IntTy::I64 => (i64::MIN, i64::MAX) + ast::IntTy::Is => (i64::MIN, i64::MAX), + ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64), + ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64), + ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64), + ast::IntTy::I64 => (i64::MIN, i64::MAX), } } fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) { match uint_ty { - ast::UintTy::Us => (u64::MIN, u64::MAX), - ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64), - ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64), - ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64), - ast::UintTy::U64 => (u64::MIN, u64::MAX) + ast::UintTy::Us => (u64::MIN, u64::MAX), + ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64), + ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64), + ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64), + ast::UintTy::U64 => (u64::MIN, u64::MAX), } } fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) { match float_ty { ast::FloatTy::F32 => (f32::MIN as f64, f32::MAX as f64), - ast::FloatTy::F64 => (f64::MIN, f64::MAX) + ast::FloatTy::F64 => (f64::MIN, f64::MAX), } } @@ -297,11 +306,12 @@ impl LateLintPass for TypeLimits { fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, binop: hir::BinOp, l: &hir::Expr, - r: &hir::Expr) -> bool { + r: &hir::Expr) + -> bool { let (lit, expr, swap) = match (&l.node, &r.node) { (&hir::ExprLit(_), _) => (l, r, true), (_, &hir::ExprLit(_)) => (r, l, false), - _ => return true + _ => return true, }; // Normalize the binop so that the literal is always on the RHS in // the comparison @@ -314,35 +324,43 @@ impl LateLintPass for TypeLimits { ty::TyInt(int_ty) => { let (min, max) = int_ty_range(int_ty); let lit_val: i64 = match lit.node { - hir::ExprLit(ref li) => match li.node { - ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | - ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64, - _ => return true - }, - _ => bug!() + hir::ExprLit(ref li) => { + match li.node { + ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | + ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64, + _ => return true, + } + } + _ => bug!(), }; is_valid(norm_binop, lit_val, min, max) } ty::TyUint(uint_ty) => { let (min, max): (u64, u64) = uint_ty_range(uint_ty); let lit_val: u64 = match lit.node { - hir::ExprLit(ref li) => match li.node { - ast::LitKind::Int(v, _) => v, - _ => return true - }, - _ => bug!() + hir::ExprLit(ref li) => { + match li.node { + ast::LitKind::Int(v, _) => v, + _ => return true, + } + } + _ => bug!(), }; is_valid(norm_binop, lit_val, min, max) } - _ => true + _ => true, } } fn is_comparison(binop: hir::BinOp) -> bool { match binop.node { - hir::BiEq | hir::BiLt | hir::BiLe | - hir::BiNe | hir::BiGe | hir::BiGt => true, - _ => false + hir::BiEq | + hir::BiLt | + hir::BiLe | + hir::BiNe | + hir::BiGe | + hir::BiGt => true, + _ => false, } } @@ -362,14 +380,14 @@ declare_lint! { } struct ImproperCTypesVisitor<'a, 'tcx: 'a> { - cx: &'a LateContext<'a, 'tcx> + cx: &'a LateContext<'a, 'tcx>, } enum FfiResult { FfiSafe, FfiUnsafe(&'static str), FfiBadStruct(DefId, &'static str), - FfiBadEnum(DefId, &'static str) + FfiBadEnum(DefId, &'static str), } /// Check if this enum can be safely exported based on the @@ -394,9 +412,13 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if def.variants[data_idx].fields.len() == 1 { match def.variants[data_idx].fields[0].ty(tcx, substs).sty { - ty::TyFnPtr(_) => { return true; } - ty::TyRef(..) => { return true; } - _ => { } + ty::TyFnPtr(_) => { + return true; + } + ty::TyRef(..) => { + return true; + } + _ => {} } } } @@ -406,10 +428,7 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). - fn check_type_for_ffi(&self, - cache: &mut FnvHashSet>, - ty: Ty<'tcx>) - -> FfiResult { + fn check_type_for_ffi(&self, cache: &mut FnvHashSet>, ty: Ty<'tcx>) -> FfiResult { use self::FfiResult::*; let cx = self.cx.tcx; @@ -424,8 +443,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match ty.sty { ty::TyStruct(def, substs) => { if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found struct without foreign-function-safe \ + return FfiUnsafe("found struct without foreign-function-safe \ representation annotation in foreign module, \ consider adding a #[repr(C)] attribute to \ the type"); @@ -434,8 +452,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // We can't completely trust repr(C) markings; make sure the // fields are actually safe. if def.struct_variant().fields.is_empty() { - return FfiUnsafe( - "found zero-size struct in foreign module, consider \ + return FfiUnsafe("found zero-size struct in foreign module, consider \ adding a member to this struct"); } @@ -444,8 +461,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => {} - FfiBadStruct(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } + FfiBadStruct(..) | FfiBadEnum(..) => { + return r; + } + FfiUnsafe(s) => { + return FfiBadStruct(def.did, s); + } } } FfiSafe @@ -453,7 +474,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyEnum(def, substs) => { if def.variants.is_empty() { // Empty enums are okay... although sort of useless. - return FfiSafe + return FfiSafe; } // Check for a repr() attribute to specify the size of the @@ -463,19 +484,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { [] => { // Special-case types like `Option`. if !is_repr_nullable_ptr(cx, def, substs) { - return FfiUnsafe( - "found enum without foreign-function-safe \ + return FfiUnsafe("found enum without foreign-function-safe \ representation annotation in foreign module, \ consider adding a #[repr(...)] attribute to \ - the type") + the type"); } } [ref hint] => { if !hint.is_ffi_safe() { // FIXME: This shouldn't be reachable: we should check // this earlier. - return FfiUnsafe( - "enum has unexpected #[repr(...)] attribute") + return FfiUnsafe("enum has unexpected #[repr(...)] attribute"); } // Enum with an explicitly sized discriminant; either @@ -487,8 +506,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { _ => { // FIXME: This shouldn't be reachable: we should check // this earlier. - return FfiUnsafe( - "enum has too many #[repr(...)] attributes"); + return FfiUnsafe("enum has too many #[repr(...)] attributes"); } } @@ -499,8 +517,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, arg); match r { FfiSafe => {} - FfiBadStruct(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + FfiBadStruct(..) | FfiBadEnum(..) => { + return r; + } + FfiUnsafe(s) => { + return FfiBadEnum(def.did, s); + } } } } @@ -513,7 +535,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } // Primitive types with a stable representation. - ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | + ty::TyBool | + ty::TyInt(..) | + ty::TyUint(..) | ty::TyFloat(..) => FfiSafe, ty::TyBox(..) => { @@ -541,13 +565,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { consider using a struct instead`") } - ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => { - self.check_type_for_ffi(cache, m.ty) - } + ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty), - ty::TyArray(ty, _) => { - self.check_type_for_ffi(cache, ty) - } + ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty), ty::TyFnPtr(bare_fn) => { match bare_fn.abi { @@ -555,8 +575,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => { - return FfiUnsafe( - "found function pointer with Rust calling \ + return FfiUnsafe("found function pointer with Rust calling \ convention in foreign module; consider using an \ `extern` function pointer") } @@ -571,7 +590,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, output); match r { FfiSafe => {} - _ => { return r; } + _ => { + return r; + } } } } @@ -580,17 +601,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, arg); match r { FfiSafe => {} - _ => { return r; } + _ => { + return r; + } } } FfiSafe } - ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | - ty::TyClosure(..) | ty::TyProjection(..) | - ty::TyFnDef(..) => { - bug!("Unexpected type in foreign function") - } + ty::TyParam(..) | + ty::TyInfer(..) | + ty::TyError | + ty::TyClosure(..) | + ty::TyProjection(..) | + ty::TyFnDef(..) => bug!("Unexpected type in foreign function"), } } @@ -607,16 +631,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiResult::FfiBadStruct(_, s) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant field. - self.cx.span_lint(IMPROPER_CTYPES, sp, - &format!("found non-foreign-function-safe member in \ - struct marked #[repr(C)]: {}", s)); + self.cx.span_lint(IMPROPER_CTYPES, + sp, + &format!("found non-foreign-function-safe member in \ + struct marked #[repr(C)]: {}", + s)); } FfiResult::FfiBadEnum(_, s) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant variant. - self.cx.span_lint(IMPROPER_CTYPES, sp, - &format!("found non-foreign-function-safe member in \ - enum: {}", s)); + self.cx.span_lint(IMPROPER_CTYPES, + sp, + &format!("found non-foreign-function-safe member in \ + enum: {}", + s)); } } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index b765043da8853..27960cac83cda 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -12,15 +12,15 @@ use rustc::hir::pat_util; use rustc::ty; use rustc::ty::adjustment; use util::nodemap::FnvHashMap; -use lint::{LateContext, EarlyContext, LintContext, LintArray}; -use lint::{LintPass, EarlyLintPass, LateLintPass}; +use lint::{EarlyContext, LateContext, LintArray, LintContext}; +use lint::{EarlyLintPass, LateLintPass, LintPass}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::Span; -use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; +use syntax::feature_gate::{AttributeType, KNOWN_ATTRIBUTES}; use syntax::ptr::P; use rustc_back::slice; @@ -48,8 +48,12 @@ impl UnusedMut { if let hir::BindByValue(hir::MutMutable) = mode { if !name.as_str().starts_with("_") { match mutables.entry(name.0 as usize) { - Vacant(entry) => { entry.insert(vec![id]); }, - Occupied(mut entry) => { entry.get_mut().push(id); }, + Vacant(entry) => { + entry.insert(vec![id]); + } + Occupied(mut entry) => { + entry.get_mut().push(id); + } } } } @@ -59,7 +63,8 @@ impl UnusedMut { let used_mutables = cx.tcx.used_mut_nodes.borrow(); for (_, v) in &mutables { if !v.iter().any(|e| used_mutables.contains(e)) { - cx.span_lint(UNUSED_MUT, cx.tcx.map.span(v[0]), + cx.span_lint(UNUSED_MUT, + cx.tcx.map.span(v[0]), "variable does not need to be mutable"); } } @@ -89,9 +94,13 @@ impl LateLintPass for UnusedMut { } } - fn check_fn(&mut self, cx: &LateContext, - _: FnKind, decl: &hir::FnDecl, - _: &hir::Block, _: Span, _: ast::NodeId) { + fn check_fn(&mut self, + cx: &LateContext, + _: FnKind, + decl: &hir::FnDecl, + _: &hir::Block, + _: Span, + _: ast::NodeId) { for a in &decl.inputs { self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat)); } @@ -123,7 +132,7 @@ impl LateLintPass for UnusedResults { fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { let expr = match s.node { hir::StmtSemi(ref expr, _) => &**expr, - _ => return + _ => return, }; if let hir::ExprRet(..) = expr.node { @@ -186,8 +195,8 @@ impl LateLintPass for UnusedUnsafe { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) && - !cx.tcx.used_unsafe.borrow().contains(&blk.id) { - cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block"); + !cx.tcx.used_unsafe.borrow().contains(&blk.id) { + cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block"); } } } @@ -212,8 +221,7 @@ impl LateLintPass for PathStatements { fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { if let hir::StmtSemi(ref expr, _) = s.node { if let hir::ExprPath(..) = expr.node { - cx.span_lint(PATH_STATEMENTS, s.span, - "path statement with no effect"); + cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect"); } } } @@ -241,8 +249,8 @@ impl LateLintPass for UnusedAttributes { match ty { AttributeType::Whitelisted if attr.check_name(name) => { break; - }, - _ => () + } + _ => (), } } @@ -256,24 +264,31 @@ impl LateLintPass for UnusedAttributes { if !attr::is_used(attr) { cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? - let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| { - attr.name() == name && - ty == AttributeType::CrateLevel - }).is_some(); + let known_crate = KNOWN_ATTRIBUTES.iter() + .find(|&&(name, ty, _)| { + attr.name() == name && + ty == AttributeType::CrateLevel + }) + .is_some(); // Has a plugin registered this attribute as one which must be used at // the crate level? let plugin_crate = plugin_attributes.iter() .find(|&&(ref x, t)| { - &*attr.name() == x && - AttributeType::CrateLevel == t - }).is_some(); - if known_crate || plugin_crate { + &*attr.name() == x && + AttributeType::CrateLevel == t + }) + .is_some(); + if known_crate || plugin_crate { let msg = match attr.node.style { - ast::AttrStyle::Outer => "crate-level attribute should be an inner \ - attribute: add an exclamation mark: #![foo]", - ast::AttrStyle::Inner => "crate-level attribute should be in the \ - root module", + ast::AttrStyle::Outer => { + "crate-level attribute should be an inner \ + attribute: add an exclamation mark: #![foo]" + } + ast::AttrStyle::Inner => { + "crate-level attribute should be in the \ + root module" + } }; cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg); } @@ -291,12 +306,16 @@ declare_lint! { pub struct UnusedParens; impl UnusedParens { - fn check_unused_parens_core(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str, + fn check_unused_parens_core(&self, + cx: &EarlyContext, + value: &ast::Expr, + msg: &str, struct_lit_needs_parens: bool) { if let ast::ExprKind::Paren(ref inner) = value.node { let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner); if !necessary { - cx.span_lint(UNUSED_PARENS, value.span, + cx.span_lint(UNUSED_PARENS, + value.span, &format!("unnecessary parentheses around {}", msg)) } } @@ -314,8 +333,7 @@ impl UnusedParens { ast::ExprKind::AssignOp(_, ref lhs, ref rhs) | ast::ExprKind::Binary(_, ref lhs, ref rhs) => { // X { y: 1 } + X { y: 2 } - contains_exterior_struct_lit(&lhs) || - contains_exterior_struct_lit(&rhs) + contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs) } ast::ExprKind::Unary(_, ref x) | ast::ExprKind::Cast(ref x, _) | @@ -332,7 +350,7 @@ impl UnusedParens { contains_exterior_struct_lit(&exprs[0]) } - _ => false + _ => false, } } } @@ -358,21 +376,25 @@ impl EarlyLintPass for UnusedParens { Assign(_, ref value) => (value, "assigned value", false), AssignOp(_, _, ref value) => (value, "assigned value", false), InPlace(_, ref value) => (value, "emplacement value", false), - _ => return + _ => return, }; self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens); } fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) { let (value, msg) = match s.node { - ast::StmtKind::Decl(ref decl, _) => match decl.node { - ast::DeclKind::Local(ref local) => match local.init { - Some(ref value) => (value, "assigned value"), - None => return - }, - _ => return - }, - _ => return + ast::StmtKind::Decl(ref decl, _) => { + match decl.node { + ast::DeclKind::Local(ref local) => { + match local.init { + Some(ref value) => (value, "assigned value"), + None => return, + } + } + _ => return, + } + } + _ => return, }; self.check_unused_parens_core(cx, &value, msg, false); } @@ -398,11 +420,9 @@ impl LateLintPass for UnusedImportBraces { if let hir::ItemUse(ref view_path) = item.node { if let hir::ViewPathList(_, ref items) = view_path.node { if items.len() == 1 { - if let hir::PathListIdent {ref name, ..} = items[0].node { - let m = format!("braces around {} is unnecessary", - name); - cx.span_lint(UNUSED_IMPORT_BRACES, item.span, - &m[..]); + if let hir::PathListIdent { ref name, .. } = items[0].node { + let m = format!("braces around {} is unnecessary", name); + cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &m[..]); } } } @@ -429,23 +449,24 @@ impl LateLintPass for UnusedAllocation { fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { match e.node { hir::ExprBox(_) => {} - _ => return + _ => return, } if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) { - if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { - ref autoref, .. - }) = *adjustment { + if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) = + *adjustment { match autoref { &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => { - cx.span_lint(UNUSED_ALLOCATION, e.span, + cx.span_lint(UNUSED_ALLOCATION, + e.span, "unnecessary allocation, use & instead"); } &Some(adjustment::AutoPtr(_, hir::MutMutable)) => { - cx.span_lint(UNUSED_ALLOCATION, e.span, + cx.span_lint(UNUSED_ALLOCATION, + e.span, "unnecessary allocation, use &mut instead"); } - _ => () + _ => (), } } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c7b113689fde9..775c24b6d4a67 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -27,7 +27,7 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::ty::{self, VariantKind}; use syntax::ast::Name; -use syntax::attr::AttrMetaMethods; +use syntax::attr; use syntax::parse::token; use syntax::codemap::{Span, DUMMY_SP}; @@ -57,6 +57,9 @@ impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) { impl<'b> Resolver<'b> { /// Constructs the reduced graph for the entire crate. pub fn build_reduced_graph(&mut self, krate: &Crate) { + let no_implicit_prelude = attr::contains_name(&krate.attrs, "no_implicit_prelude"); + self.graph_root.no_implicit_prelude.set(no_implicit_prelude); + let mut visitor = BuildReducedGraphVisitor { parent: self.graph_root, resolver: self, @@ -128,7 +131,7 @@ impl<'b> Resolver<'b> { }; // Build up the import directives. - let is_prelude = item.attrs.iter().any(|attr| attr.name() == "prelude_import"); + let is_prelude = attr::contains_name(&item.attrs, "prelude_import"); match view_path.node { ViewPathSimple(binding, ref full_path) => { @@ -221,6 +224,10 @@ impl<'b> Resolver<'b> { let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(self.definitions.local_def_id(item.id)); let module = self.new_module(parent_link, Some(def), false); + module.no_implicit_prelude.set({ + parent.no_implicit_prelude.get() || + attr::contains_name(&item.attrs, "no_implicit_prelude") + }); self.define(parent, name, TypeNS, (module, sp, vis)); self.module_map.insert(item.id, module); *parent_ref = module; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4941f867f0657..0fab12c230c0f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -126,7 +126,7 @@ enum ResolutionError<'a> { /// error E0413: cannot be named the same as an enum variant or unit-like struct in scope DeclarationShadowsEnumVariantOrUnitLikeStruct(Name), /// error E0414: only irrefutable patterns allowed here - ConstantForIrrefutableBinding(Name), + ConstantForIrrefutableBinding(Name, &'a NameBinding<'a>), /// error E0415: identifier is bound more than once in this parameter list IdentifierBoundMoreThanOnceInParameterList(&'a str), /// error E0416: identifier is bound more than once in the same pattern @@ -317,19 +317,15 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, &format!("has same name as enum variant or unit-like struct")); err } - ResolutionError::ConstantForIrrefutableBinding(name) => { + ResolutionError::ConstantForIrrefutableBinding(name, binding) => { let mut err = struct_span_err!(resolver.session, span, E0414, "let variables cannot be named the same as const variables"); err.span_label(span, &format!("cannot be named the same as a const variable")); - if let Some(binding) = resolver.current_module - .resolve_name_in_lexical_scope(name, ValueNS) { - let participle = if binding.is_import() { "imported" } else { "defined" }; - err.span_label(binding.span, &format!("a constant `{}` is {} here", - name, participle)); - } + let participle = if binding.is_import() { "imported" } else { "defined" }; + err.span_label(binding.span, &format!("a constant `{}` is {} here", name, participle)); err } ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => { @@ -714,9 +710,9 @@ enum AssocItemResolveResult { } #[derive(Copy, Clone)] -enum BareIdentifierPatternResolution { +enum BareIdentifierPatternResolution<'a> { FoundStructOrEnumVariant(Def), - FoundConst(Def, Name), + FoundConst(&'a NameBinding<'a>, Name), BareIdentifierPatternUnresolved, } @@ -792,7 +788,7 @@ pub struct ModuleS<'a> { resolutions: RefCell>>>, unresolved_imports: RefCell>>, - prelude: RefCell>>, + no_implicit_prelude: Cell, glob_importers: RefCell, &'a ImportDirective<'a>)>>, globs: RefCell>>, @@ -821,7 +817,7 @@ impl<'a> ModuleS<'a> { extern_crate_id: None, resolutions: RefCell::new(HashMap::new()), unresolved_imports: RefCell::new(Vec::new()), - prelude: RefCell::new(None), + no_implicit_prelude: Cell::new(false), glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), traits: RefCell::new(None), @@ -985,6 +981,8 @@ pub struct Resolver<'a> { graph_root: Module<'a>, + prelude: Option>, + trait_item_map: FnvHashMap<(Name, DefId), bool /* is static method? */>, structs: FnvHashMap>, @@ -1174,6 +1172,7 @@ impl<'a> Resolver<'a> { // The outermost module has def ID 0; this is not reflected in the // AST. graph_root: graph_root, + prelude: None, trait_item_map: FnvHashMap(), structs: FnvHashMap(), @@ -1456,7 +1455,15 @@ impl<'a> Resolver<'a> { } // We can only see through anonymous modules - if module.def.is_some() { return None; } + if module.def.is_some() { + return match self.prelude { + Some(prelude) if !module.no_implicit_prelude.get() => { + prelude.resolve_name(name, ns, false).success() + .map(LexicalScopeBinding::Item) + } + _ => None, + }; + } } } @@ -1543,11 +1550,7 @@ impl<'a> Resolver<'a> { debug!("(resolving name in module) resolving `{}` in `{}`", name, module_to_string(module)); self.populate_module_if_necessary(module); - match use_lexical_scope { - true => module.resolve_name_in_lexical_scope(name, namespace) - .map(Success).unwrap_or(Failed(None)), - false => module.resolve_name(name, namespace, false), - }.and_then(|binding| { + module.resolve_name(name, namespace, use_lexical_scope).and_then(|binding| { if record_used { if let NameBindingKind::Import { directive, .. } = binding.kind { self.used_imports.insert((directive.id, namespace)); @@ -2289,21 +2292,21 @@ impl<'a> Resolver<'a> { ); self.record_def(pattern.id, err_path_resolution()); } - FoundConst(def, _) if const_ok => { + FoundConst(binding, _) if const_ok => { debug!("(resolving pattern) resolving `{}` to constant", renamed); self.enforce_default_binding_mode(pattern, binding_mode, "a constant"); self.record_def(pattern.id, PathResolution { - base_def: def, + base_def: binding.def().unwrap(), depth: 0, }); } - FoundConst(_, name) => { + FoundConst(binding, name) => { resolve_error( self, pattern.span, - ResolutionError::ConstantForIrrefutableBinding(name) + ResolutionError::ConstantForIrrefutableBinding(name, binding) ); self.record_def(pattern.id, err_path_resolution()); } @@ -2526,7 +2529,7 @@ impl<'a> Resolver<'a> { } fn resolve_bare_identifier_pattern(&mut self, ident: ast::Ident, span: Span) - -> BareIdentifierPatternResolution { + -> BareIdentifierPatternResolution<'a> { let binding = match self.resolve_ident_in_lexical_scope(ident, ValueNS, true) { Some(LexicalScopeBinding::Item(binding)) => binding, _ => return BareIdentifierPatternUnresolved, @@ -2535,7 +2538,7 @@ impl<'a> Resolver<'a> { match def { Def::Variant(..) | Def::Struct(..) => FoundStructOrEnumVariant(def), - Def::Const(..) | Def::AssociatedConst(..) => FoundConst(def, ident.name), + Def::Const(..) | Def::AssociatedConst(..) => FoundConst(binding, ident.name), Def::Static(..) => { let error = ResolutionError::StaticVariableReference(binding); resolve_error(self, span, error); @@ -3264,7 +3267,7 @@ impl<'a> Resolver<'a> { let mut search_module = self.current_module; loop { // Look for trait children. - let mut search_in_module = |module: Module<'a>| { + let mut search_in_module = |this: &mut Self, module: Module<'a>| { let mut traits = module.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); @@ -3279,23 +3282,25 @@ impl<'a> Resolver<'a> { for &(trait_name, binding) in traits.as_ref().unwrap().iter() { let trait_def_id = binding.def().unwrap().def_id(); - if self.trait_item_map.contains_key(&(name, trait_def_id)) { + if this.trait_item_map.contains_key(&(name, trait_def_id)) { let mut import_id = None; if let NameBindingKind::Import { directive, .. } = binding.kind { let id = directive.id; - self.maybe_unused_trait_imports.insert(id); + this.maybe_unused_trait_imports.insert(id); import_id = Some(id); } add_trait_info(&mut found_traits, trait_def_id, import_id, name); - self.record_use(trait_name, binding); + this.record_use(trait_name, binding); } } }; - search_in_module(search_module); + search_in_module(self, search_module); match search_module.parent_link { NoParentLink | ModuleParentLink(..) => { - search_module.prelude.borrow().map(search_in_module); + if !search_module.no_implicit_prelude.get() { + self.prelude.map(|prelude| search_in_module(self, prelude)); + } break; } BlockParentLink(parent_module, _) => { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 9bd16117f9a8e..629b687d8f72a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -257,15 +257,6 @@ impl<'a> ::ModuleS<'a> { Failed(None) } - // Invariant: this may not be called until import resolution is complete. - pub fn resolve_name_in_lexical_scope(&self, name: Name, ns: Namespace) - -> Option<&'a NameBinding<'a>> { - self.resolution(name, ns).borrow().binding - .or_else(|| self.prelude.borrow().and_then(|prelude| { - prelude.resolve_name(name, ns, false).success() - })) - } - // Define the name or return the existing binding if there is a collision. pub fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>) -> Result<(), &'a NameBinding<'a>> { @@ -633,7 +624,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.resolver.populate_module_if_necessary(target_module); if let GlobImport { is_prelude: true } = directive.subclass { - *module_.prelude.borrow_mut() = Some(target_module); + self.resolver.prelude = Some(target_module); return Success(()); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 34f56c95ecf28..dc1ef5d94a4ae 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1820,7 +1820,10 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, } } - write!(w, "") + if curty.is_some() { + write!(w, "")?; + } + Ok(()) } fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec { diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 84a7b14484828..8834c026067c8 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -12,12 +12,9 @@ use ast; use attr; use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute}; use codemap; -use fold::Folder; -use fold; use parse::token::{intern, InternedString, keywords}; use parse::{token, ParseSess}; use ptr::P; -use util::small_vector::SmallVector; /// Craft a span that will be ignored by the stability lint's /// call to codemap's is_internal check. @@ -37,33 +34,6 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span { return sp; } -pub fn maybe_inject_crates_ref(krate: ast::Crate, alt_std_name: Option) - -> ast::Crate { - if no_core(&krate) { - krate - } else { - let name = if no_std(&krate) {"core"} else {"std"}; - let mut fold = CrateInjector { - item_name: token::str_to_ident(name), - crate_name: token::intern(&alt_std_name.unwrap_or(name.to_string())), - }; - fold.fold_crate(krate) - } -} - -pub fn maybe_inject_prelude(sess: &ParseSess, krate: ast::Crate) -> ast::Crate { - if no_core(&krate) { - krate - } else { - let name = if no_std(&krate) {"core"} else {"std"}; - let mut fold = PreludeInjector { - span: ignored_span(sess, DUMMY_SP), - crate_identifier: token::str_to_ident(name), - }; - fold.fold_crate(krate) - } -} - pub fn no_core(krate: &ast::Crate) -> bool { attr::contains_name(&krate.attrs, "no_core") } @@ -72,102 +42,54 @@ pub fn no_std(krate: &ast::Crate) -> bool { attr::contains_name(&krate.attrs, "no_std") || no_core(krate) } -fn no_prelude(attrs: &[ast::Attribute]) -> bool { - attr::contains_name(attrs, "no_implicit_prelude") -} - -struct CrateInjector { - item_name: ast::Ident, - crate_name: ast::Name, -} - -impl fold::Folder for CrateInjector { - fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { - krate.module.items.insert(0, P(ast::Item { - id: ast::DUMMY_NODE_ID, - ident: self.item_name, - attrs: vec!( - attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item( - InternedString::new("macro_use")))), - node: ast::ItemKind::ExternCrate(Some(self.crate_name)), - vis: ast::Visibility::Inherited, - span: DUMMY_SP - })); - - krate - } -} - -struct PreludeInjector { - span: Span, - crate_identifier: ast::Ident, -} - -impl fold::Folder for PreludeInjector { - fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { - // only add `use std::prelude::*;` if there wasn't a - // `#![no_implicit_prelude]` at the crate level. - // fold_mod() will insert glob path. - if !no_prelude(&krate.attrs) { - krate.module = self.fold_mod(krate.module); - } - krate - } - - fn fold_item(&mut self, item: P) -> SmallVector> { - if !no_prelude(&item.attrs) { - // only recur if there wasn't `#![no_implicit_prelude]` - // on this item, i.e. this means that the prelude is not - // implicitly imported though the whole subtree - fold::noop_fold_item(item, self) - } else { - SmallVector::one(item) - } +pub fn maybe_inject_crates_ref(sess: &ParseSess, + mut krate: ast::Crate, + alt_std_name: Option) + -> ast::Crate { + if no_core(&krate) { + return krate; } - fn fold_mod(&mut self, mut mod_: ast::Mod) -> ast::Mod { - let prelude_path = ast::Path { - span: self.span, + let name = if no_std(&krate) { "core" } else { "std" }; + let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string())); + + krate.module.items.insert(0, P(ast::Item { + attrs: vec![attr::mk_attr_outer(attr::mk_attr_id(), + attr::mk_word_item(InternedString::new("macro_use")))], + vis: ast::Visibility::Inherited, + node: ast::ItemKind::ExternCrate(Some(crate_name)), + ident: token::str_to_ident(name), + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + })); + + let span = ignored_span(sess, DUMMY_SP); + krate.module.items.insert(0, P(ast::Item { + attrs: vec![ast::Attribute { + node: ast::Attribute_ { + style: ast::AttrStyle::Outer, + value: P(ast::MetaItem { + node: ast::MetaItemKind::Word(token::intern_and_get_ident("prelude_import")), + span: span, + }), + id: attr::mk_attr_id(), + is_sugared_doc: false, + }, + span: span, + }], + vis: ast::Visibility::Inherited, + node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path { global: false, - segments: vec![ - ast::PathSegment { - identifier: self.crate_identifier, - parameters: ast::PathParameters::none(), - }, - ast::PathSegment { - identifier: token::str_to_ident("prelude"), - parameters: ast::PathParameters::none(), - }, - ast::PathSegment { - identifier: token::str_to_ident("v1"), - parameters: ast::PathParameters::none(), - }, - ], - }; - - let vp = P(codemap::dummy_spanned(ast::ViewPathGlob(prelude_path))); - mod_.items.insert(0, P(ast::Item { - id: ast::DUMMY_NODE_ID, - ident: keywords::Invalid.ident(), - node: ast::ItemKind::Use(vp), - attrs: vec![ast::Attribute { - span: self.span, - node: ast::Attribute_ { - id: attr::mk_attr_id(), - style: ast::AttrStyle::Outer, - value: P(ast::MetaItem { - span: self.span, - node: ast::MetaItemKind::Word( - token::intern_and_get_ident("prelude_import") - ), - }), - is_sugared_doc: false, - }, - }], - vis: ast::Visibility::Inherited, - span: self.span, - })); - - fold::noop_fold_mod(mod_, self) - } + segments: vec![name, "prelude", "v1"].into_iter().map(|name| ast::PathSegment { + identifier: token::str_to_ident(name), + parameters: ast::PathParameters::none(), + }).collect(), + span: span, + })))), + id: ast::DUMMY_NODE_ID, + ident: keywords::Invalid.ident(), + span: span, + })); + + krate } diff --git a/src/test/compile-fail/issue-25579.rs b/src/test/compile-fail/issue-25579.rs new file mode 100644 index 0000000000000..849c9aa18c905 --- /dev/null +++ b/src/test/compile-fail/issue-25579.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Sexpression { + Num(()), + Cons(&'static mut Sexpression) +} + +fn causes_ice(mut l: &mut Sexpression) { + loop { match l { + &mut Sexpression::Num(ref mut n) => {}, + &mut Sexpression::Cons(ref mut expr) => { //~ ERROR cannot borrow `l.0` + //~| ERROR cannot borrow `l.0` + l = &mut **expr; //~ ERROR cannot assign to `l` + } + }} +} + +fn main() { +} diff --git a/src/test/compile-fail/no-warn-on-field-replace-issue-34101.rs b/src/test/compile-fail/no-warn-on-field-replace-issue-34101.rs new file mode 100644 index 0000000000000..2940b891534d3 --- /dev/null +++ b/src/test/compile-fail/no-warn-on-field-replace-issue-34101.rs @@ -0,0 +1,56 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue 34101: Circa 2016-06-05, `fn inline` below issued an +// erroneous warning from the elaborate_drops pass about moving out of +// a field in `Foo`, which has a destructor (and thus cannot have +// content moved out of it). The reason that the warning is erroneous +// in this case is that we are doing a *replace*, not a move, of the +// content in question, and it is okay to replace fields within `Foo`. +// +// Another more subtle problem was that the elaborate_drops was +// creating a separate drop flag for that internally replaced content, +// even though the compiler should enforce an invariant that any drop +// flag for such subcontent of `Foo` will always have the same value +// as the drop flag for `Foo` itself. +// +// This test is structured in a funny way; we cannot test for emission +// of the warning in question via the lint system, and therefore +// `#![deny(warnings)]` does nothing to detect it. +// +// So instead we use `#[rustc_error]` and put the test into +// `compile_fail`, where the emitted warning *will* be caught. + +#![feature(rustc_attrs)] + +struct Foo(String); + +impl Drop for Foo { + fn drop(&mut self) {} +} + +fn inline() { + // (dummy variable so `f` gets assigned `var1` in MIR for both fn's) + let _s = (); + let mut f = Foo(String::from("foo")); + f.0 = String::from("bar"); +} + +fn outline() { + let _s = String::from("foo"); + let mut f = Foo(_s); + f.0 = String::from("bar"); +} + +#[rustc_error] +fn main() { //~ ERROR compilation successful + inline(); + outline(); +}