diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 54fd19dbe3058..2bb311cc5ae90 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -781,6 +781,130 @@ impl Vec { } } + /// Removes consecutive elements in the vector that resolve to the same key. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(dedup_by)] + /// + /// let mut vec = vec![10, 20, 21, 30, 20]; + /// + /// vec.dedup_by_key(|i| *i / 10); + /// + /// assert_eq!(vec, [10, 20, 30, 20]); + /// ``` + #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")] + #[inline] + pub fn dedup_by_key(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq { + self.dedup_by(|a, b| key(a) == key(b)) + } + + /// Removes consecutive elements in the vector that resolve to the same key. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(dedup_by)] + /// use std::ascii::AsciiExt; + /// + /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; + /// + /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + /// + /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); + /// ``` + #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")] + pub fn dedup_by(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool { + unsafe { + // Although we have a mutable reference to `self`, we cannot make + // *arbitrary* changes. The `PartialEq` comparisons could panic, so we + // must ensure that the vector is in a valid state at all time. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then truncate the + // vector. This operation is still O(n). + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write`. + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, so + // we swap self[r] and self[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, + // so swap self[r] and self[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of vec. Truncate to w. + + let ln = self.len(); + if ln <= 1 { + return; + } + + // Avoid bounds checks by using raw pointers. + let p = self.as_mut_ptr(); + let mut r: usize = 1; + let mut w: usize = 1; + + while r < ln { + let p_r = p.offset(r as isize); + let p_wm1 = p.offset((w - 1) as isize); + if !same_bucket(&mut *p_r, &mut *p_wm1) { + if r != w { + let p_w = p_wm1.offset(1); + mem::swap(&mut *p_r, &mut *p_w); + } + w += 1; + } + r += 1; + } + + self.truncate(w); + } + } + /// Appends an element to the back of a collection. /// /// # Panics @@ -1155,90 +1279,9 @@ impl Vec { /// assert_eq!(vec, [1, 2, 3, 2]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn dedup(&mut self) { - unsafe { - // Although we have a mutable reference to `self`, we cannot make - // *arbitrary* changes. The `PartialEq` comparisons could panic, so we - // must ensure that the vector is in a valid state at all time. - // - // The way that we handle this is by using swaps; we iterate - // over all the elements, swapping as we go so that at the end - // the elements we wish to keep are in the front, and those we - // wish to reject are at the back. We can then truncate the - // vector. This operation is still O(n). - // - // Example: We start in this state, where `r` represents "next - // read" and `w` represents "next_write`. - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this is not a duplicate, so - // we swap self[r] and self[w] (no effect as r==w) and then increment both - // r and w, leaving us with: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this value is a duplicate, - // so we increment `r` but leave everything else unchanged: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this is not a duplicate, - // so swap self[r] and self[w] and advance r and w: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 2 | 1 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Not a duplicate, repeat: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 2 | 3 | 1 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Duplicate, advance r. End of vec. Truncate to w. - - let ln = self.len(); - if ln <= 1 { - return; - } - - // Avoid bounds checks by using raw pointers. - let p = self.as_mut_ptr(); - let mut r: usize = 1; - let mut w: usize = 1; - - while r < ln { - let p_r = p.offset(r as isize); - let p_wm1 = p.offset((w - 1) as isize); - if *p_r != *p_wm1 { - if r != w { - let p_w = p_wm1.offset(1); - mem::swap(&mut *p_r, &mut *p_w); - } - w += 1; - } - r += 1; - } - - self.truncate(w); - } + self.dedup_by(|a, b| a == b) } } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index c2b34647c3279..88fb6540a9af4 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -16,6 +16,7 @@ #![feature(collections)] #![feature(collections_bound)] #![feature(const_fn)] +#![feature(dedup_by)] #![feature(enumset)] #![feature(pattern)] #![feature(rand)] diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 9580714075ad7..130c16d7c150e 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -315,47 +315,6 @@ fn test_clear() { // If the unsafe block didn't drop things properly, we blow up here. } -#[test] -fn test_dedup() { - fn case(a: Vec, b: Vec) { - let mut v = a; - v.dedup(); - assert_eq!(v, b); - } - case(vec![], vec![]); - case(vec![1], vec![1]); - case(vec![1, 1], vec![1]); - case(vec![1, 2, 3], vec![1, 2, 3]); - case(vec![1, 1, 2, 3], vec![1, 2, 3]); - case(vec![1, 2, 2, 3], vec![1, 2, 3]); - case(vec![1, 2, 3, 3], vec![1, 2, 3]); - case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]); -} - -#[test] -fn test_dedup_unique() { - let mut v0: Vec> = vec![box 1, box 1, box 2, box 3]; - v0.dedup(); - let mut v1: Vec> = vec![box 1, box 2, box 2, box 3]; - v1.dedup(); - let mut v2: Vec> = vec![box 1, box 2, box 3, box 3]; - v2.dedup(); - // If the boxed pointers were leaked or otherwise misused, valgrind - // and/or rt should raise errors. -} - -#[test] -fn test_dedup_shared() { - let mut v0: Vec> = vec![box 1, box 1, box 2, box 3]; - v0.dedup(); - let mut v1: Vec> = vec![box 1, box 2, box 2, box 3]; - v1.dedup(); - let mut v2: Vec> = vec![box 1, box 2, box 3, box 3]; - v2.dedup(); - // If the pointers were leaked or otherwise misused, valgrind and/or - // rt should raise errors. -} - #[test] fn test_retain() { let mut v = vec![1, 2, 3, 4, 5]; diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index ee2b898d5c2c2..8417be289eb9e 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::ascii::AsciiExt; use std::borrow::Cow; use std::iter::{FromIterator, repeat}; use std::mem::size_of; @@ -213,6 +214,60 @@ fn test_retain() { assert_eq!(vec, [2, 4]); } +#[test] +fn test_dedup() { + fn case(a: Vec, b: Vec) { + let mut v = a; + v.dedup(); + assert_eq!(v, b); + } + case(vec![], vec![]); + case(vec![1], vec![1]); + case(vec![1, 1], vec![1]); + case(vec![1, 2, 3], vec![1, 2, 3]); + case(vec![1, 1, 2, 3], vec![1, 2, 3]); + case(vec![1, 2, 2, 3], vec![1, 2, 3]); + case(vec![1, 2, 3, 3], vec![1, 2, 3]); + case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]); +} + +#[test] +fn test_dedup_by_key() { + fn case(a: Vec, b: Vec) { + let mut v = a; + v.dedup_by_key(|i| *i / 10); + assert_eq!(v, b); + } + case(vec![], vec![]); + case(vec![10], vec![10]); + case(vec![10, 11], vec![10]); + case(vec![10, 20, 30], vec![10, 20, 30]); + case(vec![10, 11, 20, 30], vec![10, 20, 30]); + case(vec![10, 20, 21, 30], vec![10, 20, 30]); + case(vec![10, 20, 30, 31], vec![10, 20, 30]); + case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]); +} + +#[test] +fn test_dedup_by() { + let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; + vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + + assert_eq!(vec, ["foo", "bar", "baz", "bar"]); +} + +#[test] +fn test_dedup_unique() { + let mut v0: Vec> = vec![box 1, box 1, box 2, box 3]; + v0.dedup(); + let mut v1: Vec> = vec![box 1, box 2, box 2, box 3]; + v1.dedup(); + let mut v2: Vec> = vec![box 1, box 2, box 3, box 3]; + v2.dedup(); + // If the boxed pointers were leaked or otherwise misused, valgrind + // and/or rt should raise errors. +} + #[test] fn zero_sized_values() { let mut v = Vec::new(); diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 91be50d11f952..f6260527039d0 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -12,6 +12,8 @@ use syntax::ast::NodeId; use rustc::mir::repr::{BasicBlock, Mir}; +use rustc_data_structures::bitslice::bits_to_string; +use rustc_data_structures::indexed_set::{IdxSet}; use rustc_data_structures::indexed_vec::Idx; use dot; @@ -27,8 +29,6 @@ use std::path::Path; use super::super::MoveDataParamEnv; use super::super::MirBorrowckCtxtPreDataflow; -use bitslice::bits_to_string; -use indexed_set::{IdxSet}; use super::{BitDenotation, DataflowState}; impl DataflowState { diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 55dda8eda3a4a..dce167975cf34 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -10,6 +10,9 @@ use rustc::ty::TyCtxt; use rustc::mir::repr::{self, Mir, Location}; +use rustc_data_structures::bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. +use rustc_data_structures::bitslice::{BitwiseOperator}; +use rustc_data_structures::indexed_set::{IdxSet}; use rustc_data_structures::indexed_vec::Idx; use super::super::gather_moves::{MoveOutIndex, MovePathIndex}; @@ -21,10 +24,6 @@ use super::super::on_lookup_result_bits; use super::{BitDenotation, BlockSets, DataflowOperator}; -use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. -use bitslice::{BitwiseOperator}; -use indexed_set::{IdxSet}; - // Dataflow analyses are built upon some interpretation of the // bitvectors attached to each basic block, represented via a // zero-sized structure. diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index a9b4de450967c..0c510e95b67fe 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::bitslice::{bitwise, BitwiseOperator}; use rustc::ty::TyCtxt; use rustc::mir::repr::{self, Mir}; @@ -22,9 +24,6 @@ use std::usize; use super::MirBorrowckCtxtPreDataflow; use super::MoveDataParamEnv; -use bitslice::{bitwise, BitwiseOperator}; -use indexed_set::{IdxSet, IdxSetBuf}; - pub use self::sanity_check::sanity_check_via_rustc_peek; pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals}; pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements}; diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 188fce467be52..25986b85f7b3a 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use indexed_set::IdxSetBuf; use super::gather_moves::{MoveData, MovePathIndex, LookupResult}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; @@ -23,6 +22,7 @@ use rustc::mir::transform::{Pass, MirPass, MirSource}; use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::util::nodemap::FnvHashMap; +use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 22b590592fe16..905acb79a9963 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -50,8 +50,6 @@ pub use borrowck::{AnalysisData, BorrowckCtxt, ElaborateDrops}; pub mod diagnostics; mod borrowck; -mod bitslice; -mod indexed_set; pub mod graphviz; diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index d876b4b6fec2e..81dd642de5d27 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -732,6 +732,10 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir::BiBitOr => a | b, hir::BiEq => a == b, hir::BiNe => a != b, + hir::BiLt => a < b, + hir::BiLe => a <= b, + hir::BiGe => a >= b, + hir::BiGt => a > b, _ => signal!(e, InvalidOpForBools(op.node)), }) } diff --git a/src/librustc_borrowck/bitslice.rs b/src/librustc_data_structures/bitslice.rs similarity index 98% rename from src/librustc_borrowck/bitslice.rs rename to src/librustc_data_structures/bitslice.rs index 80fa86a007ed3..ba53578e57918 100644 --- a/src/librustc_borrowck/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: move this to `rustc_data_structures` and potentially merge -// with `bitvec` there. +// FIXME: merge with `bitvec` use std::mem; diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs similarity index 98% rename from src/librustc_borrowck/indexed_set.rs rename to src/librustc_data_structures/indexed_set.rs index 671aff97d20aa..2e9e054e97eaf 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -8,16 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: move this to `rustc_data_structures` - use std::fmt; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut, Range}; use bitslice::{BitSlice, Word}; use bitslice::{bitwise, Union, Subtract}; - -use rustc_data_structures::indexed_vec::Idx; +use indexed_vec::Idx; /// Represents a set (or packed family of sets), of some element type /// E, where each E is identified by some unique index type `T`. diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index e7da18cef10f9..c8f4d766153cf 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -41,9 +41,11 @@ extern crate serialize as rustc_serialize; // used by deriving #[cfg(unix)] extern crate libc; +pub mod bitslice; pub mod bitvec; pub mod graph; pub mod ivar; +pub mod indexed_set; pub mod indexed_vec; pub mod obligation_forest; pub mod snapshot_map; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 492165e2f2a8e..31e960ccda242 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1110,7 +1110,7 @@ pub fn monitor(f: F) { errors::Level::Note); } - println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap()); + writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap(); } exit_on_err(); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 579a97138f250..bdb4d383cee7d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -32,6 +32,7 @@ use rustc_const_math::ConstInt; use rustc::mir::repr::Mir; +use std::borrow::Cow; use std::cell::Ref; use std::io; use std::mem; @@ -202,7 +203,7 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { read_f64 -> f64; read_f32 -> f32; read_char -> char; - read_str -> String; + read_str -> Cow; } fn error(&mut self, err: &str) -> Self::Error { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4689c4ded5c0a..e33668b6fe940 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -197,7 +197,8 @@ impl<'a> Resolver<'a> { // If the resolution doesn't depend on glob definability, check privacy and return. if let Some(result) = self.try_result(&resolution, ns) { return result.and_then(|binding| { - if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) { + if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) || + binding.is_extern_crate() { // c.f. issue #37020 Success(binding) } else { Failed(None) diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 2ecb071fcc2a4..d78f00497ca55 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -11,64 +11,79 @@ use std::fs::File; use std::io::prelude::*; use std::io; -use std::path::{PathBuf, Path}; +use std::path::Path; use std::str; #[derive(Clone)] pub struct ExternalHtml{ + /// Content that will be included inline in the section of a + /// rendered Markdown file or generated documentation pub in_header: String, + /// Content that will be included inline between and the content of + /// a rendered Markdown file or generated documentation pub before_content: String, + /// Content that will be included inline between the content and of + /// a rendered Markdown file or generated documentation pub after_content: String } impl ExternalHtml { pub fn load(in_header: &[String], before_content: &[String], after_content: &[String]) -> Option { - match (load_external_files(in_header), - load_external_files(before_content), - load_external_files(after_content)) { - (Some(ih), Some(bc), Some(ac)) => Some(ExternalHtml { - in_header: ih, - before_content: bc, - after_content: ac - }), - _ => None - } + load_external_files(in_header) + .and_then(|ih| + load_external_files(before_content) + .map(|bc| (ih, bc)) + ) + .and_then(|(ih, bc)| + load_external_files(after_content) + .map(|ac| (ih, bc, ac)) + ) + .map(|(ih, bc, ac)| + ExternalHtml { + in_header: ih, + before_content: bc, + after_content: ac, + } + ) } } -pub fn load_string(input: &Path) -> io::Result> { - let mut f = File::open(input)?; - let mut d = Vec::new(); - f.read_to_end(&mut d)?; - Ok(str::from_utf8(&d).map(|s| s.to_string()).ok()) +pub enum LoadStringError { + ReadFail, + BadUtf8, } -macro_rules! load_or_return { - ($input: expr, $cant_read: expr, $not_utf8: expr) => { - { - let input = PathBuf::from(&$input[..]); - match ::externalfiles::load_string(&input) { - Err(e) => { - let _ = writeln!(&mut io::stderr(), - "error reading `{}`: {}", input.display(), e); - return $cant_read; - } - Ok(None) => { - let _ = writeln!(&mut io::stderr(), - "error reading `{}`: not UTF-8", input.display()); - return $not_utf8; - } - Ok(Some(s)) => s - } +pub fn load_string>(file_path: P) -> Result { + let file_path = file_path.as_ref(); + let mut contents = vec![]; + let result = File::open(file_path) + .and_then(|mut f| f.read_to_end(&mut contents)); + if let Err(e) = result { + let _ = writeln!(&mut io::stderr(), + "error reading `{}`: {}", + file_path.display(), e); + return Err(LoadStringError::ReadFail); + } + match str::from_utf8(&contents) { + Ok(s) => Ok(s.to_string()), + Err(_) => { + let _ = writeln!(&mut io::stderr(), + "error reading `{}`: not UTF-8", + file_path.display()); + Err(LoadStringError::BadUtf8) } } } -pub fn load_external_files(names: &[String]) -> Option { +fn load_external_files(names: &[String]) -> Option { let mut out = String::new(); for name in names { - out.push_str(&*load_or_return!(&name, None, None)); + let s = match load_string(name) { + Ok(s) => s, + Err(_) => return None, + }; + out.push_str(&s); out.push('\n'); } Some(out) diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 1421a3c78fc5a..f708aa5461999 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -19,7 +19,7 @@ use testing; use rustc::session::search_paths::SearchPaths; use rustc::session::config::Externs; -use externalfiles::ExternalHtml; +use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; @@ -58,7 +58,11 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, css.push_str(&s) } - let input_str = load_or_return!(input, 1, 2); + let input_str = match load_string(input) { + Ok(s) => s, + Err(LoadStringError::ReadFail) => return 1, + Err(LoadStringError::BadUtf8) => return 2, + }; let playground = matches.opt_str("markdown-playground-url"); if playground.is_some() { markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = Some(None); }); @@ -144,7 +148,11 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, /// Run any tests/code examples in the markdown file `input`. pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, mut test_args: Vec) -> isize { - let input_str = load_or_return!(input, 1, 2); + let input_str = match load_string(input) { + Ok(s) => s, + Err(LoadStringError::ReadFail) => return 1, + Err(LoadStringError::BadUtf8) => return 2, + }; let mut opts = TestOptions::default(); opts.no_crate_inject = true; diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 5e25c61bae995..3e976c9062830 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -199,6 +199,7 @@ use self::DecoderError::*; use self::ParserState::*; use self::InternalStackElement::*; +use std::borrow::Cow; use std::collections::{HashMap, BTreeMap}; use std::io::prelude::*; use std::io; @@ -2081,9 +2082,7 @@ impl Decoder { pub fn new(json: Json) -> Decoder { Decoder { stack: vec![json] } } -} -impl Decoder { fn pop(&mut self) -> Json { self.stack.pop().unwrap() } @@ -2182,8 +2181,8 @@ impl ::Decoder for Decoder { Err(ExpectedError("single character string".to_owned(), format!("{}", s))) } - fn read_str(&mut self) -> DecodeResult { - expect!(self.pop(), String) + fn read_str(&mut self) -> DecodeResult> { + expect!(self.pop(), String).map(Cow::Owned) } fn read_enum(&mut self, _name: &str, f: F) -> DecodeResult where diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs index e97834f63cee4..a2c0ca954472c 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -9,6 +9,7 @@ // except according to those terms. use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128}; +use std::borrow::Cow; use std::io::{self, Write}; use serialize; @@ -246,11 +247,11 @@ impl<'a> serialize::Decoder for Decoder<'a> { Ok(::std::char::from_u32(bits).unwrap()) } - fn read_str(&mut self) -> Result { + fn read_str(&mut self) -> Result, Self::Error> { let len = self.read_usize()?; let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); self.position += len; - Ok(s.to_string()) + Ok(Cow::Borrowed(s)) } fn error(&mut self, err: &str) -> Self::Error { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 6650a981884d8..c4613c661a84b 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -14,6 +14,7 @@ Core encoding and decoding interfaces. */ +use std::borrow::Cow; use std::intrinsics; use std::path; use std::rc::Rc; @@ -156,7 +157,7 @@ pub trait Decoder { fn read_f64(&mut self) -> Result; fn read_f32(&mut self) -> Result; fn read_char(&mut self) -> Result; - fn read_str(&mut self) -> Result; + fn read_str(&mut self) -> Result, Self::Error>; // Compound types: fn read_enum(&mut self, _name: &str, f: F) -> Result @@ -401,7 +402,7 @@ impl Encodable for String { impl Decodable for String { fn decode(d: &mut D) -> Result { - d.read_str() + Ok(d.read_str()?.into_owned()) } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index b12f132a3a97f..24b5eddc9f8a0 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -24,10 +24,10 @@ use self::BucketState::*; const EMPTY_BUCKET: u64 = 0; /// The raw hashtable, providing safe-ish access to the unzipped and highly -/// optimized arrays of hashes, keys, and values. +/// optimized arrays of hashes, and key-value pairs. /// -/// This design uses less memory and is a lot faster than the naive -/// `Vec>`, because we don't pay for the overhead of an +/// This design is a lot faster than the naive +/// `Vec>`, because we don't pay for the overhead of an /// option on every element, and we get a generally more cache-aware design. /// /// Essential invariants of this structure: @@ -48,17 +48,19 @@ const EMPTY_BUCKET: u64 = 0; /// which will likely map to the same bucket, while not being confused /// with "empty". /// -/// - All three "arrays represented by pointers" are the same length: +/// - Both "arrays represented by pointers" are the same length: /// `capacity`. This is set at creation and never changes. The arrays -/// are unzipped to save space (we don't have to pay for the padding -/// between odd sized elements, such as in a map from u64 to u8), and -/// be more cache aware (scanning through 8 hashes brings in at most -/// 2 cache lines, since they're all right beside each other). +/// are unzipped and are more cache aware (scanning through 8 hashes +/// brings in at most 2 cache lines, since they're all right beside each +/// other). This layout may waste space in padding such as in a map from +/// u64 to u8, but is a more cache conscious layout as the key-value pairs +/// are only very shortly probed and the desired value will be in the same +/// or next cache line. /// /// You can kind of think of this module/data structure as a safe wrapper /// around just the "table" part of the hashtable. It enforces some /// invariants at the type level and employs some performance trickery, -/// but in general is just a tricked out `Vec>`. +/// but in general is just a tricked out `Vec>`. pub struct RawTable { capacity: usize, size: usize, @@ -74,10 +76,8 @@ unsafe impl Sync for RawTable {} struct RawBucket { hash: *mut u64, - // We use *const to ensure covariance with respect to K and V - key: *const K, - val: *const V, + pair: *const (K, V), _marker: marker::PhantomData<(K, V)>, } @@ -181,8 +181,7 @@ impl RawBucket { unsafe fn offset(self, count: isize) -> RawBucket { RawBucket { hash: self.hash.offset(count), - key: self.key.offset(count), - val: self.val.offset(count), + pair: self.pair.offset(count), _marker: marker::PhantomData, } } @@ -370,8 +369,7 @@ impl EmptyBucket pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket { unsafe { *self.raw.hash = hash.inspect(); - ptr::write(self.raw.key as *mut K, key); - ptr::write(self.raw.val as *mut V, value); + ptr::write(self.raw.pair as *mut (K, V), (key, value)); self.table.borrow_table_mut().size += 1; } @@ -430,7 +428,7 @@ impl>> FullBucket { /// Gets references to the key and value at a given index. pub fn read(&self) -> (&K, &V) { - unsafe { (&*self.raw.key, &*self.raw.val) } + unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } } } @@ -447,13 +445,14 @@ impl<'t, K, V> FullBucket> { unsafe { *self.raw.hash = EMPTY_BUCKET; + let (k, v) = ptr::read(self.raw.pair); (EmptyBucket { raw: self.raw, idx: self.idx, table: self.table, }, - ptr::read(self.raw.key), - ptr::read(self.raw.val)) + k, + v) } } } @@ -466,8 +465,7 @@ impl FullBucket pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unsafe { let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h); - let old_key = ptr::replace(self.raw.key as *mut K, k); - let old_val = ptr::replace(self.raw.val as *mut V, v); + let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v)); (old_hash, old_key, old_val) } @@ -479,7 +477,8 @@ impl FullBucket { /// Gets mutable references to the key and value at a given index. pub fn read_mut(&mut self) -> (&mut K, &mut V) { - unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) } + let pair_mut = self.raw.pair as *mut (K, V); + unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } } } @@ -492,7 +491,7 @@ impl<'t, K, V, M> FullBucket /// in exchange for this, the returned references have a longer lifetime /// than the references returned by `read()`. pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { (&*self.raw.key, &*self.raw.val) } + unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } } } @@ -502,7 +501,8 @@ impl<'t, K, V, M> FullBucket /// This works similarly to `into_refs`, exchanging a bucket state /// for mutable references into the table. pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) } + let pair_mut = self.raw.pair as *mut (K, V); + unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } } } @@ -517,8 +517,7 @@ impl GapThenFull pub fn shift(mut self) -> Option> { unsafe { *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(self.full.raw.key, self.gap.raw.key as *mut K, 1); - ptr::copy_nonoverlapping(self.full.raw.val, self.gap.raw.val as *mut V, 1); + ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1); } let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full; @@ -560,49 +559,42 @@ fn test_rounding() { assert_eq!(round_up_to_next(5, 4), 8); } -// Returns a tuple of (key_offset, val_offset), +// Returns a tuple of (pairs_offset, end_of_pairs_offset), // from the start of a mallocated array. #[inline] fn calculate_offsets(hashes_size: usize, - keys_size: usize, - keys_align: usize, - vals_align: usize) + pairs_size: usize, + pairs_align: usize) -> (usize, usize, bool) { - let keys_offset = round_up_to_next(hashes_size, keys_align); - let (end_of_keys, oflo) = keys_offset.overflowing_add(keys_size); - - let vals_offset = round_up_to_next(end_of_keys, vals_align); + let pairs_offset = round_up_to_next(hashes_size, pairs_align); + let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size); - (keys_offset, vals_offset, oflo) + (pairs_offset, end_of_pairs, oflo) } // Returns a tuple of (minimum required malloc alignment, hash_offset, // array_size), from the start of a mallocated array. fn calculate_allocation(hash_size: usize, hash_align: usize, - keys_size: usize, - keys_align: usize, - vals_size: usize, - vals_align: usize) + pairs_size: usize, + pairs_align: usize) -> (usize, usize, usize, bool) { let hash_offset = 0; - let (_, vals_offset, oflo) = calculate_offsets(hash_size, keys_size, keys_align, vals_align); - let (end_of_vals, oflo2) = vals_offset.overflowing_add(vals_size); + let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); - let align = cmp::max(hash_align, cmp::max(keys_align, vals_align)); + let align = cmp::max(hash_align, pairs_align); - (align, hash_offset, end_of_vals, oflo || oflo2) + (align, hash_offset, end_of_pairs, oflo) } #[test] fn test_offset_calculation() { - assert_eq!(calculate_allocation(128, 8, 15, 1, 4, 4), - (8, 0, 148, false)); - assert_eq!(calculate_allocation(3, 1, 2, 1, 1, 1), (1, 0, 6, false)); - assert_eq!(calculate_allocation(6, 2, 12, 4, 24, 8), (8, 0, 48, false)); - assert_eq!(calculate_offsets(128, 15, 1, 4), (128, 144, false)); - assert_eq!(calculate_offsets(3, 2, 1, 1), (3, 5, false)); - assert_eq!(calculate_offsets(6, 12, 4, 8), (8, 24, false)); + assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false)); + assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false)); + assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false)); + assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); + assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); + assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); } impl RawTable { @@ -621,8 +613,7 @@ impl RawTable { // No need for `checked_mul` before a more restrictive check performed // later in this method. let hashes_size = capacity * size_of::(); - let keys_size = capacity * size_of::(); - let vals_size = capacity * size_of::(); + let pairs_size = capacity * size_of::<(K, V)>(); // Allocating hashmaps is a little tricky. We need to allocate three // arrays, but since we know their sizes and alignments up front, @@ -634,19 +625,13 @@ impl RawTable { // factored out into a different function. let (malloc_alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size, align_of::(), - keys_size, - align_of::(), - vals_size, - align_of::()); - + pairs_size, + align_of::<(K, + V)>()); assert!(!oflo, "capacity overflow"); // One check for overflow that covers calculation and rounding of size. - let size_of_bucket = size_of::() - .checked_add(size_of::()) - .unwrap() - .checked_add(size_of::()) - .unwrap(); + let size_of_bucket = size_of::().checked_add(size_of::<(K, V)>()).unwrap(); assert!(size >= capacity.checked_mul(size_of_bucket) .expect("capacity overflow"), @@ -669,17 +654,16 @@ impl RawTable { fn first_bucket_raw(&self) -> RawBucket { let hashes_size = self.capacity * size_of::(); - let keys_size = self.capacity * size_of::(); + let pairs_size = self.capacity * size_of::<(K, V)>(); - let buffer = *self.hashes as *const u8; - let (keys_offset, vals_offset, oflo) = - calculate_offsets(hashes_size, keys_size, align_of::(), align_of::()); + let buffer = *self.hashes as *mut u8; + let (pairs_offset, _, oflo) = + calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); debug_assert!(!oflo, "capacity overflow"); unsafe { RawBucket { hash: *self.hashes, - key: buffer.offset(keys_offset as isize) as *const K, - val: buffer.offset(vals_offset as isize) as *const V, + pair: buffer.offset(pairs_offset as isize) as *const _, _marker: marker::PhantomData, } } @@ -844,7 +828,7 @@ impl<'a, K, V> Iterator for RevMoveBuckets<'a, K, V> { if *self.raw.hash != EMPTY_BUCKET { self.elems_left -= 1; - return Some((ptr::read(self.raw.key), ptr::read(self.raw.val))); + return Some(ptr::read(self.raw.pair)); } } } @@ -909,7 +893,7 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { fn next(&mut self) -> Option<(&'a K, &'a V)> { self.iter.next().map(|bucket| { self.elems_left -= 1; - unsafe { (&*bucket.key, &*bucket.val) } + unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) } }) } @@ -929,7 +913,8 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.iter.next().map(|bucket| { self.elems_left -= 1; - unsafe { (&*bucket.key, &mut *(bucket.val as *mut V)) } + let pair_mut = bucket.pair as *mut (K, V); + unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) } }) } @@ -950,7 +935,8 @@ impl Iterator for IntoIter { self.iter.next().map(|bucket| { self.table.size -= 1; unsafe { - (SafeHash { hash: *bucket.hash }, ptr::read(bucket.key), ptr::read(bucket.val)) + let (k, v) = ptr::read(bucket.pair); + (SafeHash { hash: *bucket.hash }, k, v) } }) } @@ -974,9 +960,8 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { self.iter.next().map(|bucket| { unsafe { (**self.table).size -= 1; - (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, - ptr::read(bucket.key), - ptr::read(bucket.val)) + let (k, v) = ptr::read(bucket.pair); + (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v) } }) } @@ -1015,8 +1000,7 @@ impl Clone for RawTable { (full.hash(), k.clone(), v.clone()) }; *new_buckets.raw.hash = h.inspect(); - ptr::write(new_buckets.raw.key as *mut K, k); - ptr::write(new_buckets.raw.val as *mut V, v); + ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v)); } Empty(..) => { *new_buckets.raw.hash = EMPTY_BUCKET; @@ -1054,14 +1038,11 @@ impl Drop for RawTable { } let hashes_size = self.capacity * size_of::(); - let keys_size = self.capacity * size_of::(); - let vals_size = self.capacity * size_of::(); + let pairs_size = self.capacity * size_of::<(K, V)>(); let (align, _, size, oflo) = calculate_allocation(hashes_size, align_of::(), - keys_size, - align_of::(), - vals_size, - align_of::()); + pairs_size, + align_of::<(K, V)>()); debug_assert!(!oflo, "should be impossible"); diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 58daa7dbf8dc4..20dc5b3801ba4 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -93,6 +93,26 @@ impl SocketAddr { SocketAddr::V6(ref mut a) => a.set_port(new_port), } } + + /// Returns true if the IP in this `SocketAddr` is a valid IPv4 address, + /// false if it's a valid IPv6 address. + #[unstable(feature = "sockaddr_checker", issue = "36949")] + pub fn is_ipv4(&self) -> bool { + match *self { + SocketAddr::V4(_) => true, + SocketAddr::V6(_) => false, + } + } + + /// Returns true if the IP in this `SocketAddr` is a valid IPv6 address, + /// false if it's a valid IPv4 address. + #[unstable(feature = "sockaddr_checker", issue = "36949")] + pub fn is_ipv6(&self) -> bool { + match *self { + SocketAddr::V4(_) => false, + SocketAddr::V6(_) => true, + } + } } impl SocketAddrV4 { @@ -631,4 +651,19 @@ mod tests { v6.set_scope_id(20); assert_eq!(v6.scope_id(), 20); } + + #[test] + fn is_v4() { + let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); + assert!(v4.is_ipv4()); + assert!(!v4.is_ipv6()); + } + + #[test] + fn is_v6() { + let v6 = SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0)); + assert!(!v6.is_ipv4()); + assert!(v6.is_ipv6()); + } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fcf2d32ded960..30fc4c3dd8045 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -71,7 +71,7 @@ impl Encodable for Name { impl Decodable for Name { fn decode(d: &mut D) -> Result { - Ok(token::intern(&d.read_str()?[..])) + Ok(token::intern(&d.read_str()?)) } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 09bc5607946de..73d9695a9906b 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -566,7 +566,7 @@ impl PartialEq for str { impl Decodable for InternedString { fn decode(d: &mut D) -> Result { - Ok(intern(d.read_str()?.as_ref()).as_str()) + Ok(intern(&d.read_str()?).as_str()) } } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index fdb10a2beb230..9f99919c89505 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,6 +11,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; +use syntax::attr::HasAttrs; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::feature_gate; @@ -104,13 +105,37 @@ pub fn expand_derive(cx: &mut ExtCtxt, } }; - if mitem.value_str().is_some() { - cx.span_err(mitem.span, "unexpected value in `derive`"); + let mut derive_attrs = Vec::new(); + item = item.map_attrs(|attrs| { + let partition = attrs.into_iter().partition(|attr| &attr.name() == "derive"); + derive_attrs = partition.0; + partition.1 + }); + + // Expand `#[derive]`s after other attribute macro invocations. + if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() { + return vec![Annotatable::Item(item.map_attrs(|mut attrs| { + attrs.push(cx.attribute(span, P(mitem.clone()))); + attrs.extend(derive_attrs); + attrs + }))]; } - let mut traits = mitem.meta_item_list().unwrap_or(&[]).to_owned(); - if traits.is_empty() { - cx.span_warn(mitem.span, "empty trait list in `derive`"); + let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| { + if mitem.value_str().is_some() { + cx.span_err(mitem.span, "unexpected value in `derive`"); + } + + let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned(); + if traits.is_empty() { + cx.span_warn(mitem.span, "empty trait list in `derive`"); + } + traits + }; + + let mut traits = get_traits(mitem, cx); + for derive_attr in derive_attrs { + traits.extend(get_traits(&derive_attr.node.value, cx)); } // First, weed out malformed #[derive] diff --git a/src/test/run-pass-fulldeps/macro-crate.rs b/src/test/run-pass-fulldeps/macro-crate.rs index fe2317aabea68..9b2e36c8cea15 100644 --- a/src/test/run-pass-fulldeps/macro-crate.rs +++ b/src/test/run-pass-fulldeps/macro-crate.rs @@ -17,8 +17,8 @@ #[macro_use] #[no_link] extern crate macro_crate_test; -#[into_multi_foo] #[derive(PartialEq, Clone, Debug)] +#[into_multi_foo] fn foo() -> AnotherFakeTypeThatHadBetterGoAway {} // Check that the `#[into_multi_foo]`-generated `foo2` is configured away diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs index b9e31fc332959..a942adc4c8020 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs @@ -21,6 +21,6 @@ use proc_macro::TokenStream; #[proc_macro_derive(AToB)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert_eq!(input, "struct A;\n"); + assert_eq!(input, "#[derive(Copy, Clone)]\nstruct A;\n"); "struct B;".parse().unwrap() } diff --git a/src/test/run-pass-fulldeps/proc-macro/load-two.rs b/src/test/run-pass-fulldeps/proc-macro/load-two.rs index 56f9768764c17..431c8c5902749 100644 --- a/src/test/run-pass-fulldeps/proc-macro/load-two.rs +++ b/src/test/run-pass-fulldeps/proc-macro/load-two.rs @@ -18,6 +18,7 @@ extern crate derive_atob; #[macro_use] extern crate derive_ctod; +#[derive(Copy, Clone)] #[derive(AToB)] struct A; diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs index 9f4ae1ad927d7..a1c9ff8a21edb 100644 --- a/src/test/run-pass/const-err.rs +++ b/src/test/run-pass/const-err.rs @@ -17,4 +17,8 @@ const X: *const u8 = b"" as _; fn main() { let _ = ((-1 as i8) << 8 - 1) as f32; let _ = 0u8 as char; + let _ = true > false; + let _ = true >= false; + let _ = true < false; + let _ = true >= false; } diff --git a/src/test/run-pass/issue-37020.rs b/src/test/run-pass/issue-37020.rs new file mode 100644 index 0000000000000..7d0d20269aba7 --- /dev/null +++ b/src/test/run-pass/issue-37020.rs @@ -0,0 +1,25 @@ +// 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. + +#![allow(private_in_public)] + +mod foo { + pub mod bar { + extern crate core; + } +} + +mod baz { + pub use foo::bar::core; +} + +fn main() { + baz::core::cell::Cell::new(0u32); +}