From f19baf0977b176ba26277af479a19b71b7ee1fdb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 18:58:39 +0100 Subject: Rename std::ptr::Shared to NonNull `Shared` is now a deprecated `type` alias. CC https://github.com/rust-lang/rust/issues/27730#issuecomment-352800629 --- src/librustc_data_structures/array_vec.rs | 6 +++--- src/librustc_data_structures/lib.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 57fc78ef531..511c407d45a 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -12,7 +12,7 @@ use std::marker::Unsize; use std::iter::Extend; -use std::ptr::{self, drop_in_place, Shared}; +use std::ptr::{self, drop_in_place, NonNull}; use std::ops::{Deref, DerefMut, Range}; use std::hash::{Hash, Hasher}; use std::slice; @@ -146,7 +146,7 @@ impl ArrayVec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - array_vec: Shared::from(self), + array_vec: NonNull::from(self), } } } @@ -232,7 +232,7 @@ pub struct Drain<'a, A: Array> tail_start: usize, tail_len: usize, iter: slice::Iter<'a, ManuallyDrop>, - array_vec: Shared>, + array_vec: NonNull>, } impl<'a, A: Array> Iterator for Drain<'a, A> { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 24048e606df..1d53825ac37 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -21,8 +21,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![feature(shared)] #![feature(collections_range)] +#![feature(nonnull)] #![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] -- cgit 1.4.1-3-g733a5 From 55c50cd8ac5ed5a799bc9f5aa1fe8fcfbb956706 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 19:50:21 +0100 Subject: Stabilize std::ptr::NonNull --- src/liballoc/boxed.rs | 10 ++-------- src/liballoc/lib.rs | 1 - src/libcore/ptr.rs | 32 +++++++++++++++++--------------- src/libcore/tests/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/libstd/lib.rs | 1 - src/libstd/panic.rs | 2 +- src/test/run-pass/issue-23433.rs | 2 -- 8 files changed, 20 insertions(+), 30 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 994466e2249..e7bc10dfaa9 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -288,16 +288,13 @@ impl Box { /// # Examples /// /// ``` - /// #![feature(nonnull)] - /// /// fn main() { /// let x = Box::new(5); /// let ptr = Box::into_nonnull_raw(x); /// let x = unsafe { Box::from_nonnull_raw(ptr) }; /// } /// ``` - #[unstable(feature = "nonnull", reason = "needs an RFC to flesh out design", - issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] #[inline] pub unsafe fn from_nonnull_raw(u: NonNull) -> Self { Box(u.into()) @@ -352,15 +349,12 @@ impl Box { /// # Examples /// /// ``` - /// #![feature(nonnull)] - /// /// fn main() { /// let x = Box::new(5); /// let ptr = Box::into_nonnull_raw(x); /// } /// ``` - #[unstable(feature = "nonnull", reason = "needs an RFC to flesh out design", - issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] #[inline] pub fn into_nonnull_raw(b: Box) -> NonNull { Box::into_unique(b).into() diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 07e4ccc45a9..f25b455f915 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -103,7 +103,6 @@ #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(offset_to)] #![feature(optin_builtin_traits)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6cb84615d09..2e5f36ed71f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2481,13 +2481,12 @@ pub type Shared = NonNull; /// Usually this won't be necessary; covariance is correct for most safe abstractions, /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they /// provide a public API that follows the normal shared XOR mutable rules of Rust. -#[unstable(feature = "shared", reason = "needs an RFC to flesh out design", - issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] pub struct NonNull { pointer: NonZero<*const T>, } -#[unstable(feature = "shared", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:p}", self.as_ptr()) @@ -2496,20 +2495,20 @@ impl fmt::Debug for NonNull { /// `NonNull` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl !Send for NonNull { } /// `NonNull` pointers are not `Sync` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl !Sync for NonNull { } -#[unstable(feature = "nonnull", issue = "27730")] impl NonNull { /// Creates a new `NonNull` that is dangling, but well-aligned. /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn empty() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; @@ -2518,24 +2517,25 @@ impl NonNull { } } -#[unstable(feature = "nonnull", issue = "27730")] impl NonNull { /// Creates a new `NonNull`. /// /// # Safety /// /// `ptr` must be non-null. - #[unstable(feature = "nonnull", issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { NonNull { pointer: NonZero::new_unchecked(ptr) } } /// Creates a new `NonNull` if `ptr` is non-null. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn new(ptr: *mut T) -> Option { NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) } /// Acquires the underlying `*mut` pointer. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T } @@ -2545,6 +2545,7 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`. + #[stable(feature = "nonnull", since = "1.24.0")] pub unsafe fn as_ref(&self) -> &T { &*self.as_ptr() } @@ -2554,46 +2555,47 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr_mut()`. + #[stable(feature = "nonnull", since = "1.24.0")] pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl Clone for NonNull { fn clone(&self) -> Self { *self } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl Copy for NonNull { } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl CoerceUnsized> for NonNull where T: Unsize { } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl fmt::Pointer for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { NonNull { pointer: NonZero::from(reference) } } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { NonNull { pointer: NonZero::from(reference) } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bc7052d676d..1c32452f846 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,7 +27,6 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(pattern)] #![feature(raw)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1d53825ac37..a35ef2f7ce7 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -22,7 +22,6 @@ #![deny(warnings)] #![feature(collections_range)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9f65d61658c..91cc6d25cce 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -283,7 +283,6 @@ #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] -#![feature(nonnull)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 6f7d8ddb770..560876006d3 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -198,7 +198,7 @@ impl UnwindSafe for *const T {} impl UnwindSafe for *mut T {} #[unstable(feature = "ptr_internals", issue = "0")] impl UnwindSafe for Unique {} -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl UnwindSafe for NonNull {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Mutex {} diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index 37cc1b134c3..7af732f561d 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -10,8 +10,6 @@ // Don't fail if we encounter a NonZero<*T> where T is an unsized type -#![feature(nonnull)] - use std::ptr::NonNull; fn main() { -- cgit 1.4.1-3-g733a5 From da545cee6057eddc0cf64767870a1cdc087ade1f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 26 Jan 2018 02:14:54 -0300 Subject: Make region inference use a dirty list Fixes #47602 --- src/librustc_data_structures/bitvec.rs | 11 ++++ .../borrow_check/nll/region_infer/mod.rs | 72 ++++++++++++++-------- 2 files changed, 59 insertions(+), 24 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 94edaa746f9..80cdb0e4417 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -51,6 +51,17 @@ impl BitVector { new_value != value } + /// Returns true if the bit has changed. + #[inline] + pub fn remove(&mut self, bit: usize) -> bool { + let (word, mask) = word_mask(bit); + let data = &mut self.data[word]; + let value = *data; + let new_value = value & !mask; + *data = new_value; + new_value != value + } + #[inline] pub fn insert_all(&mut self, all: &BitVector) -> bool { assert!(self.data.len() == all.data.len()); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 9a2f98d4622..f316a8b480d 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::HashMap; + use super::universal_regions::UniversalRegions; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; @@ -22,6 +24,7 @@ use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegi use rustc::traits::ObligationCause; use rustc::ty::{self, RegionVid, Ty, TypeFoldable}; use rustc::util::common::ErrorReported; +use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::IndexVec; use rustc_errors::DiagnosticBuilder; use std::fmt; @@ -452,8 +455,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. fn propagate_constraints(&mut self, mir: &Mir<'tcx>) { - let mut changed = true; - debug!("propagate_constraints()"); debug!("propagate_constraints: constraints={:#?}", { let mut constraints: Vec<_> = self.constraints.iter().collect(); @@ -465,37 +466,60 @@ impl<'tcx> RegionInferenceContext<'tcx> { // constraints we have accumulated. let mut inferred_values = self.liveness_constraints.clone(); - while changed { - changed = false; - debug!("propagate_constraints: --------------------"); - for constraint in &self.constraints { - debug!("propagate_constraints: constraint={:?}", constraint); - - // Grow the value as needed to accommodate the - // outlives constraint. - let Ok(made_changes) = self.dfs( - mir, - CopyFromSourceToTarget { - source_region: constraint.sub, - target_region: constraint.sup, - inferred_values: &mut inferred_values, - constraint_point: constraint.point, - constraint_span: constraint.span, - }, - ); + let dependency_map = self.build_dependency_map(); + let mut dirty_list: Vec<_> = (0..self.constraints.len()).collect(); + let mut dirty_bit_vec = BitVector::new(dirty_list.len()); + + debug!("propagate_constraints: --------------------"); + while let Some(constraint_idx) = dirty_list.pop() { + dirty_bit_vec.remove(constraint_idx); + + let constraint = &self.constraints[constraint_idx]; + debug!("propagate_constraints: constraint={:?}", constraint); + + // Grow the value as needed to accommodate the + // outlives constraint. + let Ok(made_changes) = self.dfs( + mir, + CopyFromSourceToTarget { + source_region: constraint.sub, + target_region: constraint.sup, + inferred_values: &mut inferred_values, + constraint_point: constraint.point, + constraint_span: constraint.span, + }, + ); + + if made_changes { + debug!("propagate_constraints: sub={:?}", constraint.sub); + debug!("propagate_constraints: sup={:?}", constraint.sup); - if made_changes { - debug!("propagate_constraints: sub={:?}", constraint.sub); - debug!("propagate_constraints: sup={:?}", constraint.sup); - changed = true; + for &dep_idx in dependency_map.get(&constraint.sup).unwrap_or(&vec![]) { + if dirty_bit_vec.insert(dep_idx) { + dirty_list.push(dep_idx); + } } } + debug!("\n"); } self.inferred_values = Some(inferred_values); } + /// Builds up a map from each region variable X to a vector with the indices of constraints that + /// need to be re-evaluated when X changes. These are constraints like Y: X @ P -- so if X + /// changed, we may need to grow Y. + fn build_dependency_map(&self) -> HashMap> { + let mut map = HashMap::new(); + + for (idx, constraint) in self.constraints.iter().enumerate() { + map.entry(constraint.sub).or_insert(Vec::new()).push(idx); + } + + map + } + /// Once regions have been propagated, this method is used to see /// whether the "type tests" produced by typeck were satisfied; /// type tests encode type-outlives relationships like `T: -- cgit 1.4.1-3-g733a5 From 505ef7bc069d9def137c3c469ee8bdd487882730 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 21 Jan 2018 19:18:57 -0700 Subject: Remove unused blake2b implementation --- src/librustc_data_structures/blake2b.rs | 363 -------------------------------- src/librustc_data_structures/lib.rs | 1 - 2 files changed, 364 deletions(-) delete mode 100644 src/librustc_data_structures/blake2b.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs deleted file mode 100644 index 6b8bf8df0d3..00000000000 --- a/src/librustc_data_structures/blake2b.rs +++ /dev/null @@ -1,363 +0,0 @@ -// 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. - - -// An implementation of the Blake2b cryptographic hash function. -// The implementation closely follows: https://tools.ietf.org/html/rfc7693 -// -// "BLAKE2 is a cryptographic hash function faster than MD5, SHA-1, SHA-2, and -// SHA-3, yet is at least as secure as the latest standard SHA-3." -// according to their own website :) -// -// Indeed this implementation is two to three times as fast as our SHA-256 -// implementation. If you have the luxury of being able to use crates from -// crates.io, you can go there and find still faster implementations. - -use std::mem; -use std::slice; - -#[repr(C)] -struct Blake2bCtx { - b: [u8; 128], - h: [u64; 8], - t: [u64; 2], - c: usize, - outlen: u16, - finalized: bool, - - #[cfg(debug_assertions)] - fnv_hash: u64, -} - -#[cfg(debug_assertions)] -impl ::std::fmt::Debug for Blake2bCtx { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(fmt, "{:x}", self.fnv_hash) - } -} - -#[cfg(not(debug_assertions))] -impl ::std::fmt::Debug for Blake2bCtx { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(fmt, "Enable debug_assertions() for more info.") - } -} - -#[inline(always)] -fn b2b_g(v: &mut [u64; 16], - a: usize, - b: usize, - c: usize, - d: usize, - x: u64, - y: u64) -{ - v[a] = v[a].wrapping_add(v[b]).wrapping_add(x); - v[d] = (v[d] ^ v[a]).rotate_right(32); - v[c] = v[c].wrapping_add(v[d]); - v[b] = (v[b] ^ v[c]).rotate_right(24); - v[a] = v[a].wrapping_add(v[b]).wrapping_add(y); - v[d] = (v[d] ^ v[a]).rotate_right(16); - v[c] = v[c].wrapping_add(v[d]); - v[b] = (v[b] ^ v[c]).rotate_right(63); -} - -// Initialization vector -const BLAKE2B_IV: [u64; 8] = [ - 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, - 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, - 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, - 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 -]; - -fn blake2b_compress(ctx: &mut Blake2bCtx, last: bool) { - - const SIGMA: [[usize; 16]; 12] = [ - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], - [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ], - [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ], - [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ], - [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ], - [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ], - [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ], - [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ], - [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ], - [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], - [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] - ]; - - let mut v: [u64; 16] = [ - ctx.h[0], - ctx.h[1], - ctx.h[2], - ctx.h[3], - ctx.h[4], - ctx.h[5], - ctx.h[6], - ctx.h[7], - - BLAKE2B_IV[0], - BLAKE2B_IV[1], - BLAKE2B_IV[2], - BLAKE2B_IV[3], - BLAKE2B_IV[4], - BLAKE2B_IV[5], - BLAKE2B_IV[6], - BLAKE2B_IV[7], - ]; - - v[12] ^= ctx.t[0]; // low 64 bits of offset - v[13] ^= ctx.t[1]; // high 64 bits - if last { - v[14] = !v[14]; - } - - { - // Re-interpret the input buffer in the state as an array - // of little-endian u64s, converting them to machine - // endianness. It's OK to modify the buffer in place - // since this is the last time this data will be accessed - // before it's overwritten. - - let m: &mut [u64; 16] = unsafe { - let b: &mut [u8; 128] = &mut ctx.b; - ::std::mem::transmute(b) - }; - - if cfg!(target_endian = "big") { - for word in &mut m[..] { - *word = u64::from_le(*word); - } - } - - for i in 0 .. 12 { - b2b_g(&mut v, 0, 4, 8, 12, m[SIGMA[i][ 0]], m[SIGMA[i][ 1]]); - b2b_g(&mut v, 1, 5, 9, 13, m[SIGMA[i][ 2]], m[SIGMA[i][ 3]]); - b2b_g(&mut v, 2, 6, 10, 14, m[SIGMA[i][ 4]], m[SIGMA[i][ 5]]); - b2b_g(&mut v, 3, 7, 11, 15, m[SIGMA[i][ 6]], m[SIGMA[i][ 7]]); - b2b_g(&mut v, 0, 5, 10, 15, m[SIGMA[i][ 8]], m[SIGMA[i][ 9]]); - b2b_g(&mut v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]]); - b2b_g(&mut v, 2, 7, 8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]]); - b2b_g(&mut v, 3, 4, 9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]); - } - } - - for i in 0 .. 8 { - ctx.h[i] ^= v[i] ^ v[i + 8]; - } -} - -fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx { - assert!(outlen > 0 && outlen <= 64 && key.len() <= 64); - - let mut ctx = Blake2bCtx { - b: [0; 128], - h: BLAKE2B_IV, - t: [0; 2], - c: 0, - outlen: outlen as u16, - finalized: false, - - #[cfg(debug_assertions)] - fnv_hash: 0xcbf29ce484222325, - }; - - ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64); - - if key.len() > 0 { - blake2b_update(&mut ctx, key); - ctx.c = ctx.b.len(); - } - - ctx -} - -fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) { - assert!(!ctx.finalized, "Blake2bCtx already finalized"); - - let mut bytes_to_copy = data.len(); - let mut space_in_buffer = ctx.b.len() - ctx.c; - - while bytes_to_copy > space_in_buffer { - checked_mem_copy(data, &mut ctx.b[ctx.c .. ], space_in_buffer); - - ctx.t[0] = ctx.t[0].wrapping_add(ctx.b.len() as u64); - if ctx.t[0] < (ctx.b.len() as u64) { - ctx.t[1] += 1; - } - blake2b_compress(ctx, false); - ctx.c = 0; - - data = &data[space_in_buffer .. ]; - bytes_to_copy -= space_in_buffer; - space_in_buffer = ctx.b.len(); - } - - if bytes_to_copy > 0 { - checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy); - ctx.c += bytes_to_copy; - } - - #[cfg(debug_assertions)] - { - // compute additional FNV hash for simpler to read debug output - const MAGIC_PRIME: u64 = 0x00000100000001b3; - - for &byte in data { - ctx.fnv_hash = (ctx.fnv_hash ^ byte as u64).wrapping_mul(MAGIC_PRIME); - } - } -} - -fn blake2b_final(ctx: &mut Blake2bCtx) -{ - assert!(!ctx.finalized, "Blake2bCtx already finalized"); - - ctx.t[0] = ctx.t[0].wrapping_add(ctx.c as u64); - if ctx.t[0] < ctx.c as u64 { - ctx.t[1] += 1; - } - - while ctx.c < 128 { - ctx.b[ctx.c] = 0; - ctx.c += 1; - } - - blake2b_compress(ctx, true); - - // Modify our buffer to little-endian format as it will be read - // as a byte array. It's OK to modify the buffer in place since - // this is the last time this data will be accessed. - if cfg!(target_endian = "big") { - for word in &mut ctx.h { - *word = word.to_le(); - } - } - - ctx.finalized = true; -} - -#[inline(always)] -fn checked_mem_copy(from: &[T1], to: &mut [T2], byte_count: usize) { - let from_size = from.len() * mem::size_of::(); - let to_size = to.len() * mem::size_of::(); - assert!(from_size >= byte_count); - assert!(to_size >= byte_count); - let from_byte_ptr = from.as_ptr() as * const u8; - let to_byte_ptr = to.as_mut_ptr() as * mut u8; - unsafe { - ::std::ptr::copy_nonoverlapping(from_byte_ptr, to_byte_ptr, byte_count); - } -} - -pub fn blake2b(out: &mut [u8], key: &[u8], data: &[u8]) -{ - let mut ctx = blake2b_new(out.len(), key); - blake2b_update(&mut ctx, data); - blake2b_final(&mut ctx); - checked_mem_copy(&ctx.h, out, ctx.outlen as usize); -} - -pub struct Blake2bHasher(Blake2bCtx); - -impl ::std::hash::Hasher for Blake2bHasher { - fn write(&mut self, bytes: &[u8]) { - blake2b_update(&mut self.0, bytes); - } - - fn finish(&self) -> u64 { - assert!(self.0.outlen == 8, - "Hasher initialized with incompatible output length"); - u64::from_le(self.0.h[0]) - } -} - -impl Blake2bHasher { - pub fn new(outlen: usize, key: &[u8]) -> Blake2bHasher { - Blake2bHasher(blake2b_new(outlen, key)) - } - - pub fn finalize(&mut self) -> &[u8] { - if !self.0.finalized { - blake2b_final(&mut self.0); - } - debug_assert!(mem::size_of_val(&self.0.h) >= self.0.outlen as usize); - let raw_ptr = (&self.0.h[..]).as_ptr() as * const u8; - unsafe { - slice::from_raw_parts(raw_ptr, self.0.outlen as usize) - } - } -} - -impl ::std::fmt::Debug for Blake2bHasher { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - write!(fmt, "{:?}", self.0) - } -} - -#[cfg(test)] -fn selftest_seq(out: &mut [u8], seed: u32) -{ - let mut a: u32 = 0xDEAD4BADu32.wrapping_mul(seed); - let mut b: u32 = 1; - - for i in 0 .. out.len() { - let t: u32 = a.wrapping_add(b); - a = b; - b = t; - out[i] = ((t >> 24) & 0xFF) as u8; - } -} - -#[test] -fn blake2b_selftest() -{ - use std::hash::Hasher; - - // grand hash of hash results - const BLAKE2B_RES: [u8; 32] = [ - 0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD, - 0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56, - 0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73, - 0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75 - ]; - - // parameter sets - const B2B_MD_LEN: [usize; 4] = [20, 32, 48, 64]; - const B2B_IN_LEN: [usize; 6] = [0, 3, 128, 129, 255, 1024]; - - let mut data = [0u8; 1024]; - let mut md = [0u8; 64]; - let mut key = [0u8; 64]; - - let mut hasher = Blake2bHasher::new(32, &[]); - - for i in 0 .. 4 { - let outlen = B2B_MD_LEN[i]; - for j in 0 .. 6 { - let inlen = B2B_IN_LEN[j]; - - selftest_seq(&mut data[.. inlen], inlen as u32); // unkeyed hash - blake2b(&mut md[.. outlen], &[], &data[.. inlen]); - hasher.write(&md[.. outlen]); // hash the hash - - selftest_seq(&mut key[0 .. outlen], outlen as u32); // keyed hash - blake2b(&mut md[.. outlen], &key[.. outlen], &data[.. inlen]); - hasher.write(&md[.. outlen]); // hash the hash - } - } - - // compute and compare the hash of hashes - let md = hasher.finalize(); - for i in 0 .. 32 { - assert_eq!(md[i], BLAKE2B_RES[i]); - } -} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index a35ef2f7ce7..37afe1bb066 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -57,7 +57,6 @@ pub mod small_vec; pub mod base_n; pub mod bitslice; pub mod bitvec; -pub mod blake2b; pub mod graph; pub mod indexed_set; pub mod indexed_vec; -- cgit 1.4.1-3-g733a5 From caa42e11bb6b7aea210ced552a157fa7de100d68 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 21 Jan 2018 19:28:55 -0700 Subject: Remove VecCell --- src/librustc_data_structures/lib.rs | 1 - src/librustc_data_structures/veccell/mod.rs | 47 ----------------------------- 2 files changed, 48 deletions(-) delete mode 100644 src/librustc_data_structures/veccell/mod.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 37afe1bb066..33d760d0a14 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -69,7 +69,6 @@ pub mod transitive_relation; pub mod unify; pub mod fx; pub mod tuple_slice; -pub mod veccell; pub mod control_flow_graph; pub mod flock; pub mod sync; diff --git a/src/librustc_data_structures/veccell/mod.rs b/src/librustc_data_structures/veccell/mod.rs deleted file mode 100644 index 054eee8829a..00000000000 --- a/src/librustc_data_structures/veccell/mod.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cell::UnsafeCell; -use std::mem; - -pub struct VecCell { - data: UnsafeCell>, -} - -impl VecCell { - pub fn with_capacity(capacity: usize) -> VecCell { - VecCell { data: UnsafeCell::new(Vec::with_capacity(capacity)) } - } - - #[inline] - pub fn push(&self, data: T) -> usize { - // The logic here, and in `swap` below, is that the `push` - // method on the vector will not recursively access this - // `VecCell`. Therefore, we can temporarily obtain mutable - // access, secure in the knowledge that even if aliases exist - // -- indeed, even if aliases are reachable from within the - // vector -- they will not be used for the duration of this - // particular fn call. (Note that we also are relying on the - // fact that `VecCell` is not `Sync`.) - unsafe { - let v = self.data.get(); - (*v).push(data); - (*v).len() - } - } - - pub fn swap(&self, mut data: Vec) -> Vec { - unsafe { - let v = self.data.get(); - mem::swap(&mut *v, &mut data); - } - data - } -} -- cgit 1.4.1-3-g733a5 From 4452446292086d9c92ea709eea61a31cedb55e22 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Fri, 16 Feb 2018 15:56:50 +0100 Subject: fix more typos found by codespell. --- RELEASES.md | 2 +- config.toml.example | 4 ++-- src/bootstrap/test.rs | 2 +- src/librustc/diagnostics.rs | 2 +- src/librustc/hir/mod.rs | 2 +- src/librustc/infer/error_reporting/mod.rs | 4 ++-- src/librustc/infer/outlives/obligations.rs | 2 +- src/librustc/infer/region_constraints/README.md | 2 +- src/librustc/middle/region.rs | 2 +- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc/mir/mod.rs | 2 +- src/librustc/traits/coherence.rs | 2 +- src/librustc/traits/mod.rs | 2 +- src/librustc/ty/layout.rs | 4 ++-- src/librustc_apfloat/tests/ieee.rs | 4 ++-- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_const_eval/_match.rs | 2 +- src/librustc_data_structures/indexed_vec.rs | 2 +- src/librustc_mir/borrow_check/mod.rs | 8 ++++---- src/librustc_mir/borrow_check/nll/mod.rs | 2 +- src/librustc_mir/borrow_check/nll/region_infer/mod.rs | 2 +- .../borrow_check/nll/region_infer/values.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/dataflow/impls/borrows.rs | 4 ++-- src/librustc_mir/diagnostics.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/monomorphize/item.rs | 2 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_resolve/check_unused.rs | 2 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 2 +- src/librustc_trans/back/lto.rs | 4 ++-- src/librustc_trans/builder.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans_utils/trans_crate.rs | 2 +- src/libstd/io/buffered.rs | 2 +- src/libstd/sync/rwlock.rs | 4 ++-- src/libstd/sys_common/backtrace.rs | 2 +- src/libstd/sys_common/poison.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/config.rs | 2 +- src/libsyntax/parse/parser.rs | 4 ++-- src/test/compile-fail/coerce-to-bang.rs | 2 +- .../macro_expanded_mod_helper/foo/bar.rs | 2 +- .../macro_expanded_mod_helper/foo/mod.rs | 2 +- src/test/compile-fail/hr-subtype.rs | 4 ++-- src/test/compile-fail/issue-20616-1.rs | 2 +- src/test/compile-fail/issue-20616-2.rs | 2 +- src/test/compile-fail/issue-20616-3.rs | 2 +- src/test/compile-fail/issue-20616-4.rs | 2 +- src/test/compile-fail/issue-20616-5.rs | 2 +- src/test/compile-fail/issue-20616-6.rs | 2 +- src/test/compile-fail/issue-20616-7.rs | 2 +- src/test/compile-fail/issue-20616-8.rs | 2 +- src/test/compile-fail/issue-20616-9.rs | 2 +- src/test/compile-fail/no_crate_type.rs | 2 +- src/test/mir-opt/README.md | 2 +- src/test/pretty/stmt_expr_attributes.rs | 2 +- src/test/run-make/hotplug_codegen_backend/Makefile | 2 +- .../run-make/hotplug_codegen_backend/the_backend.rs | 2 +- .../proc-macro/auxiliary/derive-reexport.rs | 2 +- src/test/run-pass/issue-29746.rs | 2 +- src/test/run-pass/issue-32008.rs | 2 +- src/test/run-pass/rfc1857-drop-order.rs | 18 +++++++++--------- src/test/run-pass/simd-target-feature-mixup.rs | 2 +- src/test/rustdoc/impl-parts-crosscrate.rs | 2 +- src/test/ui/explain.stdout | 2 +- .../issue-43106-gating-of-builtin-attrs.rs | 2 +- .../lifetime-errors/liveness-assign-imm-local-notes.rs | 2 +- 69 files changed, 89 insertions(+), 89 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/RELEASES.md b/RELEASES.md index 7a9d256be28..64e2145e0f3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -29,7 +29,7 @@ Libraries - [Copied `AsciiExt` methods onto `char`][46077] - [Remove `T: Sized` requirement on `ptr::is_null()`][46094] - [impl `From` for `{TryRecvError, RecvTimeoutError}`][45506] -- [Optimised `f32::{min, max}` to generate more efficent x86 assembly][47080] +- [Optimised `f32::{min, max}` to generate more efficient x86 assembly][47080] - [`[u8]::contains` now uses memchr which provides a 3x speed improvement][46713] Stabilized APIs diff --git a/config.toml.example b/config.toml.example index f153562a538..8d1fa3eec5c 100644 --- a/config.toml.example +++ b/config.toml.example @@ -151,8 +151,8 @@ # default. #extended = false -# Installs choosen set of extended tools if enables. By default builds all. -# If choosen tool failed to build the installation fails. +# Installs chosen set of extended tools if enables. By default builds all. +# If chosen tool failed to build the installation fails. #tools = ["cargo", "rls", "rustfmt", "analysis", "src"] # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 64ede4f4ecc..7b485662760 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -935,7 +935,7 @@ impl Step for Compiletest { } } if suite == "run-make" && !build.config.llvm_enabled { - println!("Ignoring run-make test suite as they generally dont work without LLVM"); + println!("Ignoring run-make test suite as they generally don't work without LLVM"); return; } diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 4c256556191..287516474d4 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1891,7 +1891,7 @@ is a function pointer, which is not zero-sized. This pattern should be rewritten. There are a few possible ways to do this: - change the original fn declaration to match the expected signature, - and do the cast in the fn body (the prefered option) + and do the cast in the fn body (the preferred option) - cast the fn item fo a fn pointer before calling transmute, as shown here: ``` diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 2854b9da147..bc03f7ead81 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -543,7 +543,7 @@ impl Generics { } /// Synthetic Type Parameters are converted to an other form during lowering, this allows -/// to track the original form they had. Usefull for error messages. +/// to track the original form they had. Useful for error messages. #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum SyntheticTyParamKind { ImplTrait diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 03fc40b2e39..700d06acf11 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -734,7 +734,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - // When finding T != &T, hightlight only the borrow + // When finding T != &T, highlight only the borrow (&ty::TyRef(r1, ref tnm1), _) if equals(&tnm1.ty, &t2) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); push_ty_ref(&r1, tnm1, &mut values.0); @@ -946,7 +946,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let type_param = generics.type_param(param, self.tcx); let hir = &self.tcx.hir; hir.as_local_node_id(type_param.def_id).map(|id| { - // Get the `hir::TyParam` to verify wether it already has any bounds. + // Get the `hir::TyParam` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, // instead we suggest `T: 'a + 'b` in that case. let has_lifetimes = if let hir_map::NodeTyParam(ref p) = hir.get(id) { diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index eda2e1f7b4e..36e657f78b4 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -106,7 +106,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// done (or else an assert will fire). /// /// See the `region_obligations` field of `InferCtxt` for some - /// comments about how this funtion fits into the overall expected + /// comments about how this function fits into the overall expected /// flow of the the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- /// towards the end of regionck. This also ensures that the diff --git a/src/librustc/infer/region_constraints/README.md b/src/librustc/infer/region_constraints/README.md index 67ad08c7530..95f9c8c8353 100644 --- a/src/librustc/infer/region_constraints/README.md +++ b/src/librustc/infer/region_constraints/README.md @@ -19,7 +19,7 @@ The constraints are always of one of three possible forms: a subregion of Rj - `ConstrainRegSubVar(R, Ri)` states that the concrete region R (which must not be a variable) must be a subregion of the variable Ri -- `ConstrainVarSubReg(Ri, R)` states the variable Ri shoudl be less +- `ConstrainVarSubReg(Ri, R)` states the variable Ri should be less than the concrete region R. This is kind of deprecated and ought to be replaced with a verify (they essentially play the same role). diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index e5619f469e7..3ce4ab04777 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -886,7 +886,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk: // // Each of the statements within the block is a terminating // scope, and thus a temporary (e.g. the result of calling - // `bar()` in the initalizer expression for `let inner = ...;`) + // `bar()` in the initializer expression for `let inner = ...;`) // will be cleaned up immediately after its corresponding // statement (i.e. `let inner = ...;`) executes. // diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 8ffea62f6be..a80695ec9b9 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -56,7 +56,7 @@ pub struct GlobalId<'tcx> { //////////////////////////////////////////////////////////////////////////////// pub trait PointerArithmetic: layout::HasDataLayout { - // These are not supposed to be overriden. + // These are not supposed to be overridden. //// Trunace the given value to the pointer size; also return whether there was an overflow fn truncate_to_ptr(self, val: u128) -> (u64, bool) { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 439be667861..b88dea871ce 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1950,7 +1950,7 @@ pub struct GeneratorLayout<'tcx> { /// ``` /// /// here, there is one unique free region (`'a`) but it appears -/// twice. We would "renumber" each occurence to a unique vid, as follows: +/// twice. We would "renumber" each occurrence to a unique vid, as follows: /// /// ```text /// ClosureSubsts = [ diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 9de18612d81..7311b47974a 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -277,7 +277,7 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, /// is bad, because the only local type with `T` as a subtree is /// `LocalType`, and `Vec<->` is between it and the type parameter. /// - similarly, `FundamentalPair, T>` is bad, because -/// the second occurence of `T` is not a subtree of *any* local type. +/// the second occurrence of `T` is not a subtree of *any* local type. /// - however, `LocalType>` is OK, because `T` is a subtree of /// `LocalType>`, which is local and has no types between it and /// the type parameter. diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 80819a86b7c..41cc8ca601a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -621,7 +621,7 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // FIXME (@jroesch) ISSUE 26721 // I'm not sure if this is a bug or not, needs further investigation. // It appears that by reusing the fulfillment_cx here we incur more - // obligations and later trip an asssertion on regionck.rs line 337. + // obligations and later trip an assertion on regionck.rs line 337. // // The two possibilities I see is: // - normalization is not actually fully happening and we diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 63b91ff1101..c3cd65230bd 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2059,7 +2059,7 @@ impl<'a, 'tcx> LayoutOf> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // can however trigger recursive invocations of `layout_of`. // Therefore, we execute it *after* the main query has // completed, to avoid problems around recursive structures - // and the like. (Admitedly, I wasn't able to reproduce a problem + // and the like. (Admittedly, I wasn't able to reproduce a problem // here, but it seems like the right thing to do. -nmatsakis) self.record_layout_for_printing(layout); @@ -2085,7 +2085,7 @@ impl<'a, 'tcx> LayoutOf> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx // can however trigger recursive invocations of `layout_of`. // Therefore, we execute it *after* the main query has // completed, to avoid problems around recursive structures - // and the like. (Admitedly, I wasn't able to reproduce a problem + // and the like. (Admittedly, I wasn't able to reproduce a problem // here, but it seems like the right thing to do. -nmatsakis) let cx = LayoutCx { tcx: *self.tcx, diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index aff2076e038..ff46ee79c31 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -2201,12 +2201,12 @@ fn is_finite_non_zero() { assert!(!Single::ZERO.is_finite_non_zero()); assert!(!(-Single::ZERO).is_finite_non_zero()); - // Test +/- qNaN. +/- dont mean anything with qNaN but paranoia can't hurt in + // Test +/- qNaN. +/- don't mean anything with qNaN but paranoia can't hurt in // this instance. assert!(!Single::NAN.is_finite_non_zero()); assert!(!(-Single::NAN).is_finite_non_zero()); - // Test +/- sNaN. +/- dont mean anything with sNaN but paranoia can't hurt in + // Test +/- sNaN. +/- don't mean anything with sNaN but paranoia can't hurt in // this instance. assert!(!Single::snan(None).is_finite_non_zero()); assert!(!(-Single::snan(None)).is_finite_non_zero()); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 738c0d82ee1..58818d0ce80 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1111,7 +1111,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { /// Given a type, if it is an immutable reference, return a suggestion to make it mutable fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option { - // Check wether the argument is an immutable reference + // Check whether the argument is an immutable reference debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self); if let hir::TyRptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index a7c382eba50..e30f5cb4f12 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -607,7 +607,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, // be able to observe whether the types of the struct's fields are // inhabited. // - // If the field is truely inaccessible, then all the patterns + // If the field is truly inaccessible, then all the patterns // matching against it must be wildcard patterns, so its type // does not matter. // diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 753f12f400b..b11ca107af7 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -204,7 +204,7 @@ macro_rules! newtype_index { $($tokens)*); ); - // The case where no derives are added, but encodable is overriden. Don't + // The case where no derives are added, but encodable is overridden. Don't // derive serialization traits (@pub [$($pub:tt)*] @type [$type:ident] diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 650f99828ae..c6ed971f767 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -117,7 +117,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( for move_error in move_errors { let (span, kind): (Span, IllegalMoveOriginKind) = match move_error { MoveError::UnionMove { .. } => { - unimplemented!("dont know how to report union move errors yet.") + unimplemented!("don't know how to report union move errors yet.") } MoveError::IllegalMove { cannot_move_out_of: o, @@ -1424,7 +1424,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// tracked in the MoveData. /// /// An Err result includes a tag indicated why the search failed. - /// Currenly this can only occur if the place is built off of a + /// Currently this can only occur if the place is built off of a /// static variable, as we do not track those in the MoveData. fn move_path_closest_to( &mut self, @@ -1439,7 +1439,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } match *last_prefix { Place::Local(_) => panic!("should have move path for every Local"), - Place::Projection(_) => panic!("PrefixSet::All meant dont stop for Projection"), + Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"), Place::Static(_) => return Err(NoMovePathFound::ReachedStatic), } } @@ -1484,7 +1484,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { { } ProjectionElem::Subslice { .. } => { - panic!("we dont allow assignments to subslices, context: {:?}", + panic!("we don't allow assignments to subslices, context: {:?}", context); } diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 66ca74b0139..07e5091da9c 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -278,7 +278,7 @@ fn for_each_region_constraint( /// Right now, we piggy back on the `ReVar` to store our NLL inference /// regions. These are indexed with `RegionVid`. This method will -/// assert that the region is a `ReVar` and extract its interal index. +/// assert that the region is a `ReVar` and extract its internal index. /// This is reasonable because in our MIR we replace all universal regions /// with inference variables. pub trait ToRegionVid { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 9a338947f47..33c012dfad8 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -964,7 +964,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("check_universal_region: fr_minus={:?}", fr_minus); // Grow `shorter_fr` until we find a non-local - // regon. (We always will.) We'll call that + // region. (We always will.) We'll call that // `shorter_fr+` -- it's ever so slightly larger than // `fr`. let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index b2b2ca1182d..45236bbc4aa 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -150,7 +150,7 @@ pub(super) enum RegionElement { /// A point in the control-flow graph. Location(Location), - /// An in-scope, universally quantified region (e.g., a liftime parameter). + /// An in-scope, universally quantified region (e.g., a lifetime parameter). UniversalRegion(RegionVid), } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 8053a0a6948..58ce572ae8d 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Code related to match expresions. These are sufficiently complex +//! Code related to match expressions. These are sufficiently complex //! to warrant their own module and submodules. :) This main module //! includes the high-level algorithm, the submodules contain the //! details. diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index e798cc93cb0..8ab4035cf4a 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -80,14 +80,14 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> { /// tracking (phased) borrows. It computes where a borrow is reserved; /// i.e. where it can reach in the control flow starting from its /// initial `assigned = &'rgn borrowed` statement, and ending -/// whereever `'rgn` itself ends. +/// wherever `'rgn` itself ends. pub(crate) struct Reservations<'a, 'gcx: 'tcx, 'tcx: 'a>(pub(crate) Borrows<'a, 'gcx, 'tcx>); /// The `ActiveBorrows` analysis is the second of the two flow /// analyses tracking (phased) borrows. It computes where any given /// borrow `&assigned = &'rgn borrowed` is *active*, which starts at /// the first use of `assigned` after the reservation has started, and -/// ends whereever `'rgn` itself ends. +/// ends wherever `'rgn` itself ends. pub(crate) struct ActiveBorrows<'a, 'gcx: 'tcx, 'tcx: 'a>(pub(crate) Borrows<'a, 'gcx, 'tcx>); impl<'a, 'gcx, 'tcx> Reservations<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 619c0dc847e..3491faf9cda 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -365,7 +365,7 @@ with `#[derive(Clone)]`. Some types have no ownership semantics at all and are trivial to duplicate. An example is `i32` and the other number types. We don't have to call `.clone()` to clone them, because they are marked `Copy` in addition to `Clone`. Implicit -cloning is more convienient in this case. We can mark our own types `Copy` if +cloning is more convenient in this case. We can mark our own types `Copy` if all their members also are marked `Copy`. In the example below, we implement a `Point` type. Because it only stores two diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 52b87282180..3578164feb7 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -84,7 +84,7 @@ pub struct Frame<'tcx> { /// return). pub block: mir::BasicBlock, - /// The index of the currently evaluated statment. + /// The index of the currently evaluated statement. pub stmt: usize, } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 86a4dd4a31f..a5078187a57 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -68,7 +68,7 @@ pub enum InstantiationMode { /// however, our local copy may conflict with other crates also /// inlining the same function. /// - /// This flag indicates that this situation is occuring, and informs + /// This flag indicates that this situation is occurring, and informs /// symbol name calculation that some extra mangling is needed to /// avoid conflicts. Note that this may eventually go away entirely if /// ThinLTO enables us to *always* have a globally shared instance of a diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index b46882f054d..6ae04760953 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -781,7 +781,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // Additionally, until better reachability analysis for macros 2.0 is available, // we prohibit access to private statics from other crates, this allows to give // more code internal visibility at link time. (Access to private functions - // is already prohibited by type privacy for funciton types.) + // is already prohibited by type privacy for function types.) fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: ast::NodeId, span: Span) { let def = match *qpath { hir::QPath::Resolved(_, ref path) => match path.def { diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 5a321053b7a..a757ac92df5 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -17,7 +17,7 @@ // `use` directives. // // Unused trait imports can't be checked until the method resolution. We save -// candidates here, and do the acutal check in librustc_typeck/check_unused.rs. +// candidates here, and do the actual check in librustc_typeck/check_unused.rs. use std::ops::{Deref, DerefMut}; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2da4bfedd3a..d8e03552a6a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1440,7 +1440,7 @@ impl<'a> Resolver<'a> { /// Rustdoc uses this to resolve things in a recoverable way. ResolutionError<'a> /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, - /// just that an error occured. + /// just that an error occurred. pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) -> Result { use std::iter; diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a8070c553bd..438ab3a3513 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -186,7 +186,7 @@ impl<'a> Resolver<'a> { } let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { - // `extern crate` are always usable for backwards compatability, see issue #37020. + // `extern crate` are always usable for backwards compatibility, see issue #37020. let usable = this.is_accessible(binding.vis) || binding.is_extern_crate(); if usable { Ok(binding) } else { Err(Determined) } }; diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index a3327038019..ab354a30d41 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -84,7 +84,7 @@ impl LtoModuleTranslation { } } - /// A "guage" of how costly it is to optimize this module, used to sort + /// A "gauge" of how costly it is to optimize this module, used to sort /// biggest modules first. pub fn cost(&self) -> u64 { match *self { @@ -726,7 +726,7 @@ impl ThinModule { // which was basically a resurgence of #45511 after LLVM's bug 35212 was // fixed. // - // This function below is a huge hack around tihs problem. The function + // This function below is a huge hack around this problem. The function // below is defined in `PassWrapper.cpp` and will basically "merge" // all `DICompileUnit` instances in a module. Basically it'll take all // the objects, rewrite all pointers of `DISubprogram` to point to the diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 5ab8d03b8c7..d4e05a18e3a 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -1240,7 +1240,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// on), and `ptr` is nonzero-sized, then extracts the size of `ptr` /// and the intrinsic for `lt` and passes them to `emit`, which is in /// charge of generating code to call the passed intrinsic on whatever - /// block of generated code is targetted for the intrinsic. + /// block of generated code is targeted for the intrinsic. /// /// If LLVM lifetime intrinsic support is disabled (i.e. optimizations /// off) or `ptr` is zero-sized, then no-op (does not call `emit`). diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 2e876ec118d..34ac44cec02 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -844,7 +844,7 @@ fn cast_float_to_int(bx: &Builder, // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits. // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two. // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly - // representable. Note that this only works if float_ty's exponent range is sufficently large. + // representable. Note that this only works if float_ty's exponent range is sufficiently large. // f16 or 256 bit integers would break this property. Right now the smallest float type is f32 // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127. // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index e14abdff339..9943a9bd398 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -151,7 +151,7 @@ impl MetadataLoader for NoLlvmMetadataLoader { } } - Err("Couldnt find metadata section".to_string()) + Err("Couldn't find metadata section".to_string()) } fn get_dylib_metadata( diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 4e7db5f0826..9250c1c437b 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -293,7 +293,7 @@ impl Seek for BufReader { /// where `n` minus the internal buffer length overflows an `i64`, two /// seeks will be performed instead of one. If the second seek returns /// `Err`, the underlying reader will be left at the same position it would - /// have if you seeked to `SeekFrom::Current(0)`. + /// have if you called `seek` with `SeekFrom::Current(0)`. /// /// [`seek_relative`]: #method.seek_relative fn seek(&mut self, pos: SeekFrom) -> io::Result { diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 2edf02efc47..f7fdedc0d21 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -24,8 +24,8 @@ use sys_common::rwlock as sys; /// typically allows for read-only access (shared access). /// /// In comparison, a [`Mutex`] does not distinguish between readers or writers -/// that aquire the lock, therefore blocking any threads waiting for the lock to -/// become available. An `RwLock` will allow any number of readers to aquire the +/// that acquire the lock, therefore blocking any threads waiting for the lock to +/// become available. An `RwLock` will allow any number of readers to acquire the /// lock as long as a writer is not holding the lock. /// /// The priority policy of the lock is dependent on the underlying operating diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index a364a0392b3..1955f3ec9a2 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -136,7 +136,7 @@ pub fn __rust_begin_short_backtrace(f: F) -> T f() } -/// Controls how the backtrace should be formated. +/// Controls how the backtrace should be formatted. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrintFormat { /// Show all the frames with absolute path for files. diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs index 934ac3edbf1..e74c40ae04b 100644 --- a/src/libstd/sys_common/poison.rs +++ b/src/libstd/sys_common/poison.rs @@ -98,7 +98,7 @@ pub struct PoisonError { } /// An enumeration of possible errors associated with a [`TryLockResult`] which -/// can occur while trying to aquire a lock, from the [`try_lock`] method on a +/// can occur while trying to acquire a lock, from the [`try_lock`] method on a /// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`]. /// /// [`Mutex`]: struct.Mutex.html diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c7ab6158256..8c1e5cf7586 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -918,7 +918,7 @@ pub struct Expr { } impl Expr { - /// Wether this expression would be valid somewhere that expects a value, for example, an `if` + /// Whether this expression would be valid somewhere that expects a value, for example, an `if` /// condition. pub fn returns(&self) -> bool { if let ExprKind::Block(ref block) = self.node { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index fc82357455b..aa360ed1bf5 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -114,7 +114,7 @@ impl<'a> StripUnconfigured<'a> { } } - // Determine if a node with the given attributes should be included in this configuation. + // Determine if a node with the given attributes should be included in this configuration. pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { // When not compiling with --test we should not compile the #[test] functions diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ac582627f88..7915109ce3a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3912,7 +3912,7 @@ impl<'a> Parser<'a> { "use `=` if you meant to assign", "=".to_string()); err.emit(); - // As this was parsed successfuly, continue as if the code has been fixed for the + // As this was parsed successfully, continue as if the code has been fixed for the // rest of the file. It will still fail due to the emitted error, but we avoid // extra noise. init @@ -6571,7 +6571,7 @@ impl<'a> Parser<'a> { return Ok(Some(macro_def)); } - // Verify wether we have encountered a struct or method definition where the user forgot to + // Verify whether we have encountered a struct or method definition where the user forgot to // add the `struct` or `fn` keyword after writing `pub`: `pub S {}` if visibility == Visibility::Public && self.check_ident() && diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 2cf568777d4..b804bb2981b 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -14,7 +14,7 @@ fn foo(x: usize, y: !, z: usize) { } fn call_foo_a() { - // FIXME(#40800) -- accepted beacuse divergence happens **before** + // FIXME(#40800) -- accepted because divergence happens **before** // the coercion to `!`, but within same expression. Not clear that // these are the rules we want. foo(return, 22, 44); diff --git a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs index 9177dcba0d7..4ef92981314 100644 --- a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs +++ b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test not a test, auxillary +// ignore-test not a test, auxiliary diff --git a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs index e29c985b983..41a8c288e7c 100644 --- a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs +++ b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test not a test, auxillary +// ignore-test not a test, auxiliary mod_decl!(bar); diff --git a/src/test/compile-fail/hr-subtype.rs b/src/test/compile-fail/hr-subtype.rs index c88d74d53ce..86df2382732 100644 --- a/src/test/compile-fail/hr-subtype.rs +++ b/src/test/compile-fail/hr-subtype.rs @@ -84,7 +84,7 @@ check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), fn(Inv<'y>)) } // Somewhat surprisingly, a fn taking two distinct bound lifetimes and -// a fn taking one bound lifetime can be interchangable, but only if +// a fn taking one bound lifetime can be interchangeable, but only if // we are co- or contra-variant with respect to both lifetimes. // // The reason is: @@ -100,7 +100,7 @@ check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b> check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>, for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } -// If we make those lifetimes invariant, then the two types are not interchangable. +// If we make those lifetimes invariant, then the two types are not interchangeable. check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), for<'a> fn(Inv<'a>, Inv<'a>)) } check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, diff --git a/src/test/compile-fail/issue-20616-1.rs b/src/test/compile-fail/issue-20616-1.rs index a1949df661a..3e29383d62c 100644 --- a/src/test/compile-fail/issue-20616-1.rs +++ b/src/test/compile-fail/issue-20616-1.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-2.rs b/src/test/compile-fail/issue-20616-2.rs index 87b836d6872..1ec7a74559a 100644 --- a/src/test/compile-fail/issue-20616-2.rs +++ b/src/test/compile-fail/issue-20616-2.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-3.rs b/src/test/compile-fail/issue-20616-3.rs index e5ed46d2cb3..885fd246547 100644 --- a/src/test/compile-fail/issue-20616-3.rs +++ b/src/test/compile-fail/issue-20616-3.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-4.rs b/src/test/compile-fail/issue-20616-4.rs index 9b731289e13..0dbe92fc1bc 100644 --- a/src/test/compile-fail/issue-20616-4.rs +++ b/src/test/compile-fail/issue-20616-4.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-5.rs b/src/test/compile-fail/issue-20616-5.rs index 5e3b024da9a..794e5178f4b 100644 --- a/src/test/compile-fail/issue-20616-5.rs +++ b/src/test/compile-fail/issue-20616-5.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-6.rs b/src/test/compile-fail/issue-20616-6.rs index b6ee26f9f62..fe91751a4a0 100644 --- a/src/test/compile-fail/issue-20616-6.rs +++ b/src/test/compile-fail/issue-20616-6.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-7.rs b/src/test/compile-fail/issue-20616-7.rs index fef3dd4e31d..184ad027102 100644 --- a/src/test/compile-fail/issue-20616-7.rs +++ b/src/test/compile-fail/issue-20616-7.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-8.rs b/src/test/compile-fail/issue-20616-8.rs index b7bef47c4f4..5cdec33e94b 100644 --- a/src/test/compile-fail/issue-20616-8.rs +++ b/src/test/compile-fail/issue-20616-8.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-9.rs b/src/test/compile-fail/issue-20616-9.rs index 5c16d24cef8..7995addb692 100644 --- a/src/test/compile-fail/issue-20616-9.rs +++ b/src/test/compile-fail/issue-20616-9.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/no_crate_type.rs b/src/test/compile-fail/no_crate_type.rs index bef909917d2..b2cc5cae697 100644 --- a/src/test/compile-fail/no_crate_type.rs +++ b/src/test/compile-fail/no_crate_type.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// regresion test for issue 11256 +// regression test for issue 11256 #![crate_type] //~ ERROR `crate_type` requires a value fn main() { diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md index b00b35aa29f..ad4932b9fb9 100644 --- a/src/test/mir-opt/README.md +++ b/src/test/mir-opt/README.md @@ -26,7 +26,7 @@ other non-matched lines before and after, but not between $expected_lines, should you want to skip lines, you must include an elision comment, of the form (as a regex) `//\s*...\s*`. The lines will be skipped lazily, that is, if there are two identical lines in the output that match the line after the elision -comment, the first one wil be matched. +comment, the first one will be matched. Examples: diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index 1c443020d2e..17e6119f968 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -255,7 +255,7 @@ fn _11() { while true { let _ = #[attr] break ; } || #[attr] return; let _ = #[attr] expr_mac!(); - /* FIXME: pp bug, loosing delimiter styles + /* FIXME: pp bug, losing delimiter styles let _ = #[attr] expr_mac![]; let _ = #[attr] expr_mac!{}; */ diff --git a/src/test/run-make/hotplug_codegen_backend/Makefile b/src/test/run-make/hotplug_codegen_backend/Makefile index 9a216d1d81f..2ddf3aa5439 100644 --- a/src/test/run-make/hotplug_codegen_backend/Makefile +++ b/src/test/run-make/hotplug_codegen_backend/Makefile @@ -6,4 +6,4 @@ all: -o $(TMPDIR)/the_backend.dylib $(RUSTC) some_crate.rs --crate-name some_crate --crate-type bin -o $(TMPDIR)/some_crate \ -Z codegen-backend=$(TMPDIR)/the_backend.dylib -Z unstable-options - grep -x "This has been \"compiled\" succesfully." $(TMPDIR)/some_crate + grep -x "This has been \"compiled\" successfully." $(TMPDIR)/some_crate diff --git a/src/test/run-make/hotplug_codegen_backend/the_backend.rs b/src/test/run-make/hotplug_codegen_backend/the_backend.rs index 5972149590c..9e87268e699 100644 --- a/src/test/run-make/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make/hotplug_codegen_backend/the_backend.rs @@ -69,7 +69,7 @@ impl TransCrate for TheBackend { let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str()); let mut out_file = ::std::fs::File::create(output_name).unwrap(); - write!(out_file, "This has been \"compiled\" succesfully.").unwrap(); + write!(out_file, "This has been \"compiled\" successfully.").unwrap(); } Ok(()) } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs index 24865ea2709..cfaf913216a 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test not a test, auxillary +// ignore-test not a test, auxiliary #![feature(macro_reexport)] diff --git a/src/test/run-pass/issue-29746.rs b/src/test/run-pass/issue-29746.rs index 61c601ac6a9..d4463fed1a6 100644 --- a/src/test/run-pass/issue-29746.rs +++ b/src/test/run-pass/issue-29746.rs @@ -17,7 +17,7 @@ macro_rules! zip { }; // Intermediate steps to build the zipped expression, the match pattern, and - // and the output tuple of the closure, using macro hygene to repeatedly + // and the output tuple of the closure, using macro hygiene to repeatedly // introduce new variables named 'x'. ([$a:expr, $($rest:expr),*], $zip:expr, $pat:pat, [$($flat:expr),*]) => { zip!([$($rest),*], $zip.zip($a), ($pat,x), [$($flat),*, x]) diff --git a/src/test/run-pass/issue-32008.rs b/src/test/run-pass/issue-32008.rs index cb489acf1d9..95890d2e1b4 100644 --- a/src/test/run-pass/issue-32008.rs +++ b/src/test/run-pass/issue-32008.rs @@ -9,7 +9,7 @@ // except according to those terms. // Tests that binary operators allow subtyping on both the LHS and RHS, -// and as such do not introduce unnecesarily strict lifetime constraints. +// and as such do not introduce unnecessarily strict lifetime constraints. use std::ops::Add; diff --git a/src/test/run-pass/rfc1857-drop-order.rs b/src/test/run-pass/rfc1857-drop-order.rs index b2e5ff62eb8..94b2a586ddf 100644 --- a/src/test/run-pass/rfc1857-drop-order.rs +++ b/src/test/run-pass/rfc1857-drop-order.rs @@ -67,7 +67,7 @@ fn test_drop_tuple() { panic::catch_unwind(|| { (PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D")); + panic!("this panic is caught :D")); }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); } @@ -99,7 +99,7 @@ fn test_drop_struct() { TestStruct { x: PushOnDrop::new(2, cloned.clone()), y: PushOnDrop::new(1, cloned.clone()), - z: panic!("this panic is catched :D") + z: panic!("this panic is caught :D") }; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -111,7 +111,7 @@ fn test_drop_struct() { TestStruct { y: PushOnDrop::new(2, cloned.clone()), x: PushOnDrop::new(1, cloned.clone()), - z: panic!("this panic is catched :D") + z: panic!("this panic is caught :D") }; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -122,7 +122,7 @@ fn test_drop_struct() { panic::catch_unwind(|| { TestTupleStruct(PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D")); + panic!("this panic is caught :D")); }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); } @@ -154,7 +154,7 @@ fn test_drop_enum() { TestEnum::Struct { x: PushOnDrop::new(2, cloned.clone()), y: PushOnDrop::new(1, cloned.clone()), - z: panic!("this panic is catched :D") + z: panic!("this panic is caught :D") }; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -166,7 +166,7 @@ fn test_drop_enum() { TestEnum::Struct { y: PushOnDrop::new(2, cloned.clone()), x: PushOnDrop::new(1, cloned.clone()), - z: panic!("this panic is catched :D") + z: panic!("this panic is caught :D") }; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -177,7 +177,7 @@ fn test_drop_enum() { panic::catch_unwind(|| { TestEnum::Tuple(PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D")); + panic!("this panic is caught :D")); }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); } @@ -207,7 +207,7 @@ fn test_drop_list() { vec![ PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D") + panic!("this panic is caught :D") ]; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -219,7 +219,7 @@ fn test_drop_list() { [ PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D") + panic!("this panic is caught :D") ]; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs index 2c9ef59709d..3c54921ac6e 100644 --- a/src/test/run-pass/simd-target-feature-mixup.rs +++ b/src/test/run-pass/simd-target-feature-mixup.rs @@ -30,7 +30,7 @@ fn main() { // We don't actually know if our computer has the requisite target features // for the test below. Testing for that will get added to libstd later so - // for now just asume sigill means this is a machine that can't run this test. + // for now just assume sigill means this is a machine that can't run this test. if is_sigill(status) { println!("sigill with {}, assuming spurious", level); continue diff --git a/src/test/rustdoc/impl-parts-crosscrate.rs b/src/test/rustdoc/impl-parts-crosscrate.rs index 5fa2e03e0a8..1d055ccbead 100644 --- a/src/test/rustdoc/impl-parts-crosscrate.rs +++ b/src/test/rustdoc/impl-parts-crosscrate.rs @@ -17,7 +17,7 @@ extern crate rustdoc_impl_parts_crosscrate; pub struct Bar { t: T } -// The output file is html embeded in javascript, so the html tags +// The output file is html embedded in javascript, so the html tags // aren't stripped by the processing script and we can't check for the // full impl string. Instead, just make sure something from each part // is mentioned. diff --git a/src/test/ui/explain.stdout b/src/test/ui/explain.stdout index 0bbbd95320a..411cdfb335b 100644 --- a/src/test/ui/explain.stdout +++ b/src/test/ui/explain.stdout @@ -45,7 +45,7 @@ is a function pointer, which is not zero-sized. This pattern should be rewritten. There are a few possible ways to do this: - change the original fn declaration to match the expected signature, - and do the cast in the fn body (the prefered option) + and do the cast in the fn body (the preferred option) - cast the fn item fo a fn pointer before calling transmute, as shown here: ``` diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index 029949b2604..21950402c8c 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -509,7 +509,7 @@ mod reexport_test_harness_main { //~^ WARN unused attribute } -// Cannnot feed "2700" to `#[macro_escape]` without signaling an error. +// Cannot feed "2700" to `#[macro_escape]` without signaling an error. #[macro_escape] //~^ WARN macro_escape is a deprecated synonym for macro_use mod macro_escape { diff --git a/src/test/ui/lifetime-errors/liveness-assign-imm-local-notes.rs b/src/test/ui/lifetime-errors/liveness-assign-imm-local-notes.rs index d4ef87cdd76..20a2cbfd3aa 100644 --- a/src/test/ui/lifetime-errors/liveness-assign-imm-local-notes.rs +++ b/src/test/ui/lifetime-errors/liveness-assign-imm-local-notes.rs @@ -9,7 +9,7 @@ // except according to those terms. // FIXME: Change to UI Test -// Check notes are placed on an assignment that can actually preceed the current assigmnent +// Check notes are placed on an assignment that can actually precede the current assigmnent // Don't emmit a first assignment for assignment in a loop. // compile-flags: -Zborrowck=compare -- cgit 1.4.1-3-g733a5 From 6728f21d85d347bcd5e7ca919b4e9f0c2677572b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 22 Nov 2017 16:16:55 -0500 Subject: Generate documentation for auto-trait impls A new section is added to both both struct and trait doc pages. On struct/enum pages, a new 'Auto Trait Implementations' section displays any synthetic implementations for auto traits. Currently, this is only done for Send and Sync. On trait pages, a new 'Auto Implementors' section displays all types which automatically implement the trait. Effectively, this is a list of all public types in the standard library. Synthesized impls for a particular auto trait ('synthetic impls') take into account generic bounds. For example, a type 'struct Foo(T)' will have 'impl Send for Foo where T: Send' generated for it. Manual implementations of auto traits are also taken into account. If we have the following types: 'struct Foo(T)' 'struct Wrapper(Foo)' 'unsafe impl Send for Wrapper' // pretend that Wrapper makes this sound somehow Then Wrapper will have the following impl generated: 'impl Send for Wrapper' reflecting the fact that 'T: Send' need not hold for 'Wrapper: Send' to hold Lifetimes, HRTBS, and projections (e.g. '::Item') are taken into account by synthetic impls However, if a type can *never* implement a particular auto trait (e.g. 'struct MyStruct(*const T)'), then a negative impl will be generated (in this case, 'impl !Send for MyStruct') All of this means that a user should be able to copy-paste a synthetic impl into their code, without any observable changes in behavior (assuming the rest of the program remains unchanged). --- src/doc/rust-by-example | 2 +- src/librustc/hir/map/definitions.rs | 4 + src/librustc/infer/mod.rs | 13 +- src/librustc/infer/region_constraints/mod.rs | 10 +- src/librustc/traits/mod.rs | 4 +- src/librustc/traits/project.rs | 4 + src/librustc/traits/select.rs | 31 +- src/librustc_data_structures/snapshot_map/mod.rs | 5 + src/librustdoc/clean/auto_trait.rs | 1455 ++++++++++++++++++++++ src/librustdoc/clean/cfg.rs | 2 +- src/librustdoc/clean/inline.rs | 42 +- src/librustdoc/clean/mod.rs | 441 ++++++- src/librustdoc/core.rs | 27 +- src/librustdoc/doctree.rs | 1 + src/librustdoc/html/render.rs | 295 ++++- src/librustdoc/html/static/main.js | 19 +- src/librustdoc/lib.rs | 4 +- src/librustdoc/visit_ast.rs | 26 +- src/test/rustdoc/duplicate_impls/issue-33054.rs | 3 +- src/test/rustdoc/issue-21474.rs | 2 +- src/test/rustdoc/issue-45584.rs | 4 +- src/test/rustdoc/synthetic_auto/basic.rs | 18 + src/test/rustdoc/synthetic_auto/complex.rs | 52 + src/test/rustdoc/synthetic_auto/lifetimes.rs | 28 + src/test/rustdoc/synthetic_auto/manual.rs | 24 + src/test/rustdoc/synthetic_auto/negative.rs | 23 + src/test/rustdoc/synthetic_auto/nested.rs | 28 + src/test/rustdoc/synthetic_auto/no-redundancy.rs | 26 + src/test/rustdoc/synthetic_auto/project.rs | 43 + 29 files changed, 2484 insertions(+), 152 deletions(-) create mode 100644 src/librustdoc/clean/auto_trait.rs create mode 100644 src/test/rustdoc/synthetic_auto/basic.rs create mode 100644 src/test/rustdoc/synthetic_auto/complex.rs create mode 100644 src/test/rustdoc/synthetic_auto/lifetimes.rs create mode 100644 src/test/rustdoc/synthetic_auto/manual.rs create mode 100644 src/test/rustdoc/synthetic_auto/negative.rs create mode 100644 src/test/rustdoc/synthetic_auto/nested.rs create mode 100644 src/test/rustdoc/synthetic_auto/no-redundancy.rs create mode 100644 src/test/rustdoc/synthetic_auto/project.rs (limited to 'src/librustc_data_structures') diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index ebb28c95b2e..919980be7df 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit ebb28c95b2ea68b96eddb9e71aff4d32eacc74f0 +Subproject commit 919980be7df4ea7d45a9dca8efc34da89bcf7d6b diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 43cc437e1e7..61a58a60306 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -72,6 +72,10 @@ impl DefPathTable { index } + pub fn next_id(&self, address_space: DefIndexAddressSpace) -> DefIndex { + DefIndex::from_array_index(self.index_to_key[address_space.index()].len(), address_space) + } + #[inline(always)] pub fn def_key(&self, index: DefIndex) -> DefKey { self.index_to_key[index.address_space().index()] diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 07c5b319970..2a620ecdfff 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -180,7 +180,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // for each body-id in this map, which will process the // obligations within. This is expected to be done 'late enough' // that all type inference variables have been bound and so forth. - region_obligations: RefCell)>>, + pub region_obligations: RefCell)>>, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -1555,11 +1555,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { InferOk { value, obligations } } - fn borrow_region_constraints(&self) -> RefMut<'_, RegionConstraintCollector<'tcx>> { + pub fn borrow_region_constraints(&self) -> RefMut<'_, RegionConstraintCollector<'tcx>> { RefMut::map( self.region_constraints.borrow_mut(), |c| c.as_mut().expect("region constraints already solved")) } + + /// Clears the selection, evaluation, and projection cachesThis is useful when + /// repeatedly attemping to select an Obligation while chagning only + /// its ParamEnv, since FulfillmentContext doesn't use 'probe' + pub fn clear_caches(&self) { + self.selection_cache.clear(); + self.evaluation_cache.clear(); + self.projection_cache.borrow_mut().clear(); + } } impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 68d81a2dee3..be196192371 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -82,7 +82,7 @@ pub type VarOrigins = IndexVec; /// Describes constraints between the region variables and other /// regions, as well as other conditions that must be verified, or /// assumptions that can be made. -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct RegionConstraintData<'tcx> { /// Constraints of the form `A <= B`, where either `A` or `B` can /// be a region variable (or neither, as it happens). @@ -142,7 +142,7 @@ pub enum Constraint<'tcx> { /// outlive `RS`. Therefore verify that `R <= RS[i]` for some /// `i`. Inference variables may be involved (but this verification /// step doesn't influence inference). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Verify<'tcx> { pub kind: GenericKind<'tcx>, pub origin: SubregionOrigin<'tcx>, @@ -159,7 +159,7 @@ pub enum GenericKind<'tcx> { /// When we introduce a verification step, we wish to test that a /// particular region (let's call it `'min`) meets some bound. /// The bound is described the by the following grammar: -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum VerifyBound<'tcx> { /// B = exists {R} --> some 'r in {R} must outlive 'min /// @@ -288,6 +288,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> { &self.var_origins } + pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> { + &self.data + } + /// Once all the constraints have been gathered, extract out the final data. /// /// Not legal during a snapshot. diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 41cc8ca601a..31836f7e3c5 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -32,8 +32,8 @@ use syntax_pos::{Span, DUMMY_SP}; pub use self::coherence::{orphan_check, overlapping_impls, OrphanCheckErr, OverlapResult}; pub use self::fulfill::FulfillmentContext; pub use self::project::MismatchedProjectionTypes; -pub use self::project::{normalize, normalize_projection_type, Normalized}; -pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal}; +pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type}; +pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal, Normalized}; pub use self::object_safety::ObjectSafetyViolation; pub use self::object_safety::MethodViolationCode; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index ae539f07336..0d0476e7c21 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1596,6 +1596,10 @@ impl<'tcx> ProjectionCache<'tcx> { } } + pub fn clear(&mut self) { + self.map.clear(); + } + pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { ProjectionCacheSnapshot { snapshot: self.map.snapshot() } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ed25646d43..e03f3e7f12c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -93,6 +93,11 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { inferred_obligations: SnapshotVec>, intercrate_ambiguity_causes: Option>, + + /// Controls whether or not to filter out negative impls when selecting. + /// This is used in librustdoc to distinguish between the lack of an impl + /// and a negative impl + allow_negative_impls: bool } #[derive(Clone, Debug)] @@ -424,6 +429,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { intercrate: None, inferred_obligations: SnapshotVec::new(), intercrate_ambiguity_causes: None, + allow_negative_impls: false } } @@ -436,6 +442,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { intercrate: Some(mode), inferred_obligations: SnapshotVec::new(), intercrate_ambiguity_causes: None, + allow_negative_impls: false + } + } + + pub fn with_negative(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + allow_negative_impls: bool) -> SelectionContext<'cx, 'gcx, 'tcx> { + debug!("with_negative({:?})", allow_negative_impls); + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: None, + inferred_obligations: SnapshotVec::new(), + intercrate_ambiguity_causes: Vec::new(), + allow_negative_impls } } @@ -1086,7 +1106,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { - if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative { + if !self.allow_negative_impls && + self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative { return Err(Unimplemented) } } @@ -3337,6 +3358,10 @@ impl<'tcx> SelectionCache<'tcx> { hashmap: RefCell::new(FxHashMap()) } } + + pub fn clear(&self) { + *self.hashmap.borrow_mut() = FxHashMap() + } } impl<'tcx> EvaluationCache<'tcx> { @@ -3345,6 +3370,10 @@ impl<'tcx> EvaluationCache<'tcx> { hashmap: RefCell::new(FxHashMap()) } } + + pub fn clear(&self) { + *self.hashmap.borrow_mut() = FxHashMap() + } } impl<'o,'tcx> TraitObligationStack<'o,'tcx> { diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index cd7143ad3ce..cede6f14782 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -45,6 +45,11 @@ impl SnapshotMap } } + pub fn clear(&mut self) { + self.map.clear(); + self.undo_log.clear(); + } + pub fn insert(&mut self, key: K, value: V) -> bool { match self.map.insert(key.clone(), value) { None => { diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs new file mode 100644 index 00000000000..8f0d3929b52 --- /dev/null +++ b/src/librustdoc/clean/auto_trait.rs @@ -0,0 +1,1455 @@ +// Copyright 2018 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. + +use rustc::ty::TypeFoldable; + +use super::*; + +pub struct AutoTraitFinder<'a, 'tcx: 'a, 'rcx: 'a> { + pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, +} + +impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { + pub fn get_with_def_id(&self, def_id: DefId) -> Vec { + let ty = self.cx.tcx.type_of(def_id); + + let def_ctor: fn(DefId) -> Def = match ty.sty { + ty::TyAdt(adt, _) => match adt.adt_kind() { + AdtKind::Struct => Def::Struct, + AdtKind::Enum => Def::Enum, + AdtKind::Union => Def::Union, + }, + _ => panic!("Unexpected type {:?}", def_id), + }; + + self.get_auto_trait_impls(def_id, def_ctor, None) + } + + pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec { + let item = &self.cx.tcx.hir.expect_item(id).node; + let did = self.cx.tcx.hir.local_def_id(id); + + let def_ctor = match *item { + hir::ItemStruct(_, _) => Def::Struct, + hir::ItemUnion(_, _) => Def::Union, + hir::ItemEnum(_, _) => Def::Enum, + _ => panic!("Unexpected type {:?} {:?}", item, id), + }; + + self.get_auto_trait_impls(did, def_ctor, Some(name)) + } + + pub fn get_auto_trait_impls( + &self, + def_id: DefId, + def_ctor: fn(DefId) -> Def, + name: Option, + ) -> Vec { + if self.cx + .tcx + .get_attrs(def_id) + .lists("doc") + .has_word("hidden") + { + debug!( + "get_auto_trait_impls(def_id={:?}, def_ctor={:?}): item has doc('hidden'), \ + aborting", + def_id, def_ctor + ); + return Vec::new(); + } + + let tcx = self.cx.tcx; + let generics = self.cx.tcx.generics_of(def_id); + + debug!( + "get_auto_trait_impls(def_id={:?}, def_ctor={:?}, generics={:?}", + def_id, def_ctor, generics + ); + let auto_traits: Vec<_> = self.cx + .send_trait + .and_then(|send_trait| { + self.get_auto_trait_impl_for( + def_id, + name.clone(), + generics.clone(), + def_ctor, + send_trait, + ) + }) + .into_iter() + .chain(self.get_auto_trait_impl_for( + def_id, + name.clone(), + generics.clone(), + def_ctor, + tcx.require_lang_item(lang_items::SyncTraitLangItem), + ).into_iter()) + .collect(); + + debug!( + "get_auto_traits: type {:?} auto_traits {:?}", + def_id, auto_traits + ); + auto_traits + } + + fn get_auto_trait_impl_for( + &self, + def_id: DefId, + name: Option, + generics: ty::Generics, + def_ctor: fn(DefId) -> Def, + trait_def_id: DefId, + ) -> Option { + if !self.cx + .generated_synthetics + .borrow_mut() + .insert((def_id, trait_def_id)) + { + debug!( + "get_auto_trait_impl_for(def_id={:?}, generics={:?}, def_ctor={:?}, \ + trait_def_id={:?}): already generated, aborting", + def_id, generics, def_ctor, trait_def_id + ); + return None; + } + + let result = self.find_auto_trait_generics(def_id, trait_def_id, &generics); + + if result.is_auto() { + let trait_ = hir::TraitRef { + path: get_path_for_type(self.cx.tcx, trait_def_id, hir::def::Def::Trait), + ref_id: ast::DUMMY_NODE_ID, + }; + + let polarity; + + let new_generics = match result { + AutoTraitResult::PositiveImpl(new_generics) => { + polarity = None; + new_generics + } + AutoTraitResult::NegativeImpl => { + polarity = Some(ImplPolarity::Negative); + + // For negative impls, we use the generic params, but *not* the predicates, + // from the original type. Otherwise, the displayed impl appears to be a + // conditional negative impl, when it's really unconditional. + // + // For example, consider the struct Foo(*mut T). Using + // the original predicates in our impl would cause us to generate + // `impl !Send for Foo`, which makes it appear that Foo + // implements Send where T is not copy. + // + // Instead, we generate `impl !Send for Foo`, which better + // expresses the fact that `Foo` never implements `Send`, + // regardless of the choice of `T`. + let real_generics = (&generics, &Default::default()); + + // Clean the generics, but ignore the '?Sized' bounds generated + // by the `Clean` impl + let clean_generics = real_generics.clean(self.cx); + + Generics { + params: clean_generics.params, + where_predicates: Vec::new(), + } + } + _ => unreachable!(), + }; + + let path = get_path_for_type(self.cx.tcx, def_id, def_ctor); + let mut segments = path.segments.into_vec(); + let last = segments.pop().unwrap(); + + let real_name = name.as_ref().map(|n| Symbol::from(n.as_str())); + + segments.push(hir::PathSegment::new( + real_name.unwrap_or(last.name), + self.generics_to_path_params(generics.clone()), + false, + )); + + let new_path = hir::Path { + span: path.span, + def: path.def, + segments: HirVec::from_vec(segments), + }; + + let ty = hir::Ty { + id: ast::DUMMY_NODE_ID, + node: hir::Ty_::TyPath(hir::QPath::Resolved(None, P(new_path))), + span: DUMMY_SP, + hir_id: hir::DUMMY_HIR_ID, + }; + + return Some(Item { + source: Span::empty(), + name: None, + attrs: Default::default(), + visibility: None, + def_id: self.next_def_id(def_id.krate), + stability: None, + deprecation: None, + inner: ImplItem(Impl { + unsafety: hir::Unsafety::Normal, + generics: new_generics, + provided_trait_methods: FxHashSet(), + trait_: Some(trait_.clean(self.cx)), + for_: ty.clean(self.cx), + items: Vec::new(), + polarity, + synthetic: true, + }), + }); + } + None + } + + fn generics_to_path_params(&self, generics: ty::Generics) -> hir::PathParameters { + let lifetimes = HirVec::from_vec( + generics + .regions + .iter() + .map(|p| { + let name = if p.name == "" { + hir::LifetimeName::Static + } else { + hir::LifetimeName::Name(p.name) + }; + + hir::Lifetime { + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + name, + } + }) + .collect(), + ); + let types = HirVec::from_vec( + generics + .types + .iter() + .map(|p| P(self.ty_param_to_ty(p.clone()))) + .collect(), + ); + + hir::PathParameters { + lifetimes: lifetimes, + types: types, + bindings: HirVec::new(), + parenthesized: false, + } + } + + fn ty_param_to_ty(&self, param: ty::TypeParameterDef) -> hir::Ty { + debug!("ty_param_to_ty({:?}) {:?}", param, param.def_id); + hir::Ty { + id: ast::DUMMY_NODE_ID, + node: hir::Ty_::TyPath(hir::QPath::Resolved( + None, + P(hir::Path { + span: DUMMY_SP, + def: Def::TyParam(param.def_id), + segments: HirVec::from_vec(vec![hir::PathSegment::from_name(param.name)]), + }), + )), + span: DUMMY_SP, + hir_id: hir::DUMMY_HIR_ID, + } + } + + fn find_auto_trait_generics( + &self, + did: DefId, + trait_did: DefId, + generics: &ty::Generics, + ) -> AutoTraitResult { + let tcx = self.cx.tcx; + let ty = self.cx.tcx.type_of(did); + + let orig_params = tcx.param_env(did); + + let trait_ref = ty::TraitRef { + def_id: trait_did, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let trait_pred = ty::Binder(trait_ref); + + let bail_out = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::with_negative(&infcx, true); + let result = selcx.select(&Obligation::new( + ObligationCause::dummy(), + orig_params, + trait_pred.to_poly_trait_predicate(), + )); + match result { + Ok(Some(Vtable::VtableImpl(_))) => { + debug!( + "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): \ + manual impl found, bailing out", + did, trait_did, generics + ); + return true; + } + _ => return false, + }; + }); + + // If an explicit impl exists, it always takes priority over an auto impl + if bail_out { + return AutoTraitResult::ExplicitImpl; + } + + return tcx.infer_ctxt().enter(|mut infcx| { + let mut fresh_preds = FxHashSet(); + + // Due to the way projections are handled by SelectionContext, we need to run + // evaluate_predicates twice: once on the original param env, and once on the result of + // the first evaluate_predicates call + // + // The problem is this: most of rustc, including SelectionContext and traits::project, + // are designed to work with a concrete usage of a type (e.g. Vec + // fn() { Vec }. This information will generally never change - given + // the 'T' in fn() { ... }, we'll never know anything else about 'T'. + // If we're unable to prove that 'T' implements a particular trait, we're done - + // there's nothing left to do but error out. + // + // However, synthesizing an auto trait impl works differently. Here, we start out with + // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing + // with - and progressively discover the conditions we need to fulfill for it to + // implement a certain auto trait. This ends up breaking two assumptions made by trait + // selection and projection: + // + // * We can always cache the result of a particular trait selection for the lifetime of + // an InfCtxt + // * Given a projection bound such as '::SomeItem = K', if 'T: + // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K' + // + // We fix the first assumption by manually clearing out all of the InferCtxt's caches + // in between calls to SelectionContext.select. This allows us to keep all of the + // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift + // them between calls + // + // We fix the second assumption by reprocessing the result of our first call to + // evaluate_predicates. Using the example of '::SomeItem = K', our first + // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass, + // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing + // SelectionContext to return it back to us. + + let (new_env, user_env) = match self.evaluate_predicates( + &mut infcx, + did, + trait_did, + ty, + orig_params.clone(), + orig_params, + &mut fresh_preds, + false, + ) { + Some(e) => e, + None => return AutoTraitResult::NegativeImpl, + }; + + let (full_env, full_user_env) = self.evaluate_predicates( + &mut infcx, + did, + trait_did, + ty, + new_env.clone(), + user_env, + &mut fresh_preds, + true, + ).unwrap_or_else(|| { + panic!( + "Failed to fully process: {:?} {:?} {:?}", + ty, trait_did, orig_params + ) + }); + + debug!( + "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): fulfilling \ + with {:?}", + did, trait_did, generics, full_env + ); + infcx.clear_caches(); + + // At this point, we already have all of the bounds we need. FulfillmentContext is used + // to store all of the necessary region/lifetime bounds in the InferContext, as well as + // an additional sanity check. + let mut fulfill = FulfillmentContext::new(); + fulfill.register_bound( + &infcx, + full_env, + ty, + trait_did, + ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID), + ); + fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| { + panic!( + "Unable to fulfill trait {:?} for '{:?}': {:?}", + trait_did, ty, e + ) + }); + + let names_map: FxHashMap = generics + .regions + .iter() + .map(|l| (l.name.as_str().to_string(), l.clean(self.cx))) + .collect(); + + let body_ids: FxHashSet<_> = infcx + .region_obligations + .borrow() + .iter() + .map(|&(id, _)| id) + .collect(); + + for id in body_ids { + infcx.process_registered_region_obligations(&[], None, full_env.clone(), id); + } + + let region_data = infcx + .borrow_region_constraints() + .region_constraint_data() + .clone(); + + let lifetime_predicates = self.handle_lifetimes(®ion_data, &names_map); + let vid_to_region = self.map_vid_to_region(®ion_data); + + debug!( + "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): computed \ + lifetime information '{:?}' '{:?}'", + did, trait_did, generics, lifetime_predicates, vid_to_region + ); + + let new_generics = self.param_env_to_generics( + infcx.tcx, + did, + full_user_env, + generics.clone(), + lifetime_predicates, + vid_to_region, + ); + debug!( + "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): finished with \ + {:?}", + did, trait_did, generics, new_generics + ); + return AutoTraitResult::PositiveImpl(new_generics); + }); + } + + fn clean_pred<'c, 'd, 'cx>( + &self, + infcx: &InferCtxt<'c, 'd, 'cx>, + p: ty::Predicate<'cx>, + ) -> ty::Predicate<'cx> { + infcx.freshen(p) + } + + fn evaluate_nested_obligations< + 'b, + 'c, + 'd, + 'cx, + T: Iterator>>, + >( + &self, + ty: ty::Ty, + nested: T, + computed_preds: &'b mut FxHashSet>, + fresh_preds: &'b mut FxHashSet>, + predicates: &'b mut VecDeque>, + select: &mut traits::SelectionContext<'c, 'd, 'cx>, + only_projections: bool, + ) -> bool { + let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID); + + for (obligation, predicate) in nested + .filter(|o| o.recursion_depth == 1) + .map(|o| (o.clone(), o.predicate.clone())) + { + let is_new_pred = + fresh_preds.insert(self.clean_pred(select.infcx(), predicate.clone())); + + match &predicate { + &ty::Predicate::Trait(ref p) => { + let substs = &p.skip_binder().trait_ref.substs; + + if self.is_of_param(substs) && !only_projections && is_new_pred { + computed_preds.insert(predicate); + } + predicates.push_back(p.clone()); + } + &ty::Predicate::Projection(p) => { + // If the projection isn't all type vars, then + // we don't want to add it as a bound + if self.is_of_param(p.skip_binder().projection_ty.substs) && is_new_pred { + computed_preds.insert(predicate); + } else { + match traits::poly_project_and_unify_type( + select, + &obligation.with(p.clone()), + ) { + Err(e) => { + debug!( + "evaluate_nested_obligations: Unable to unify predicate \ + '{:?}' '{:?}', bailing out", + ty, e + ); + return false; + } + Ok(Some(v)) => { + if !self.evaluate_nested_obligations( + ty, + v.clone().iter().cloned(), + computed_preds, + fresh_preds, + predicates, + select, + only_projections, + ) { + return false; + } + } + Ok(None) => { + panic!("Unexpected result when selecting {:?} {:?}", ty, obligation) + } + } + } + } + &ty::Predicate::RegionOutlives(ref binder) => { + if let Err(_) = select + .infcx() + .region_outlives_predicate(&dummy_cause, binder) + { + return false; + } + } + &ty::Predicate::TypeOutlives(ref binder) => { + match ( + binder.no_late_bound_regions(), + binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(), + ) { + (None, Some(t_a)) => { + select.infcx().register_region_obligation( + ast::DUMMY_NODE_ID, + RegionObligation { + sup_type: t_a, + sub_region: select.infcx().tcx.types.re_static, + cause: dummy_cause.clone(), + }, + ); + } + (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { + select.infcx().register_region_obligation( + ast::DUMMY_NODE_ID, + RegionObligation { + sup_type: t_a, + sub_region: r_b, + cause: dummy_cause.clone(), + }, + ); + } + _ => {} + }; + } + _ => panic!("Unexpected predicate {:?} {:?}", ty, predicate), + }; + } + return true; + } + + // The core logic responsible for computing the bounds for our synthesized impl. + // + // To calculate the bounds, we call SelectionContext.select in a loop. Like FulfillmentContext, + // we recursively select the nested obligations of predicates we encounter. However, whenver we + // encounter an UnimplementedError involving a type parameter, we add it to our ParamEnv. Since + // our goal is to determine when a particular type implements an auto trait, Unimplemented + // errors tell us what conditions need to be met. + // + // This method ends up working somewhat similary to FulfillmentContext, but with a few key + // differences. FulfillmentContext works under the assumption that it's dealing with concrete + // user code. According, it considers all possible ways that a Predicate could be met - which + // isn't always what we want for a synthesized impl. For example, given the predicate 'T: + // Iterator', FulfillmentContext can end up reporting an Unimplemented error for T: + // IntoIterator - since there's an implementation of Iteratpr where T: IntoIterator, + // FulfillmentContext will drive SelectionContext to consider that impl before giving up. If we + // were to rely on FulfillmentContext's decision, we might end up synthesizing an impl like + // this: + // 'impl Send for Foo where T: IntoIterator' + // + // While it might be technically true that Foo implements Send where T: IntoIterator, + // the bound is overly restrictive - it's really only necessary that T: Iterator. + // + // For this reason, evaluate_predicates handles predicates with type variables specially. When + // we encounter an Unimplemented error for a bound such as 'T: Iterator', we immediately add it + // to our ParamEnv, and add it to our stack for recursive evaluation. When we later select it, + // we'll pick up any nested bounds, without ever inferring that 'T: IntoIterator' needs to + // hold. + // + // One additonal consideration is supertrait bounds. Normally, a ParamEnv is only ever + // consutrcted once for a given type. As part of the construction process, the ParamEnv will + // have any supertrait bounds normalized - e.g. if we have a type 'struct Foo', the + // ParamEnv will contain 'T: Copy' and 'T: Clone', since 'Copy: Clone'. When we construct our + // own ParamEnv, we need to do this outselves, through traits::elaborate_predicates, or else + // SelectionContext will choke on the missing predicates. However, this should never show up in + // the final synthesized generics: we don't want our generated docs page to contain something + // like 'T: Copy + Clone', as that's redundant. Therefore, we keep track of a separate + // 'user_env', which only holds the predicates that will actually be displayed to the user. + fn evaluate_predicates<'b, 'gcx, 'c>( + &self, + infcx: &mut InferCtxt<'b, 'tcx, 'c>, + ty_did: DefId, + trait_did: DefId, + ty: ty::Ty<'c>, + param_env: ty::ParamEnv<'c>, + user_env: ty::ParamEnv<'c>, + fresh_preds: &mut FxHashSet>, + only_projections: bool, + ) -> Option<(ty::ParamEnv<'c>, ty::ParamEnv<'c>)> { + let tcx = infcx.tcx; + + let mut select = traits::SelectionContext::new(&infcx); + + let mut already_visited = FxHashSet(); + let mut predicates = VecDeque::new(); + predicates.push_back(ty::Binder(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: trait_did, + substs: infcx.tcx.mk_substs_trait(ty, &[]), + }, + })); + + let mut computed_preds: FxHashSet<_> = param_env.caller_bounds.iter().cloned().collect(); + let mut user_computed_preds: FxHashSet<_> = + user_env.caller_bounds.iter().cloned().collect(); + + let mut new_env = param_env.clone(); + let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID); + + while let Some(pred) = predicates.pop_front() { + infcx.clear_caches(); + + if !already_visited.insert(pred.clone()) { + continue; + } + + let result = select.select(&Obligation::new(dummy_cause.clone(), new_env, pred)); + + match &result { + &Ok(Some(ref vtable)) => { + let obligations = vtable.clone().nested_obligations().into_iter(); + + if !self.evaluate_nested_obligations( + ty, + obligations, + &mut user_computed_preds, + fresh_preds, + &mut predicates, + &mut select, + only_projections, + ) { + return None; + } + } + &Ok(None) => {} + &Err(SelectionError::Unimplemented) => { + if self.is_of_param(pred.skip_binder().trait_ref.substs) { + already_visited.remove(&pred); + user_computed_preds.insert(ty::Predicate::Trait(pred.clone())); + predicates.push_back(pred); + } else { + debug!( + "evaluate_nested_obligations: Unimplemented found, bailing: {:?} {:?} \ + {:?}", + ty, + pred, + pred.skip_binder().trait_ref.substs + ); + return None; + } + } + _ => panic!("Unexpected error for '{:?}': {:?}", ty, result), + }; + + computed_preds.extend(user_computed_preds.iter().cloned()); + let normalized_preds = + traits::elaborate_predicates(tcx, computed_preds.clone().into_iter().collect()); + new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal); + } + + let final_user_env = ty::ParamEnv::new( + tcx.mk_predicates(user_computed_preds.into_iter()), + user_env.reveal, + ); + debug!( + "evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \ + '{:?}'", + ty_did, trait_did, new_env, final_user_env + ); + + return Some((new_env, final_user_env)); + } + + fn is_of_param(&self, substs: &Substs) -> bool { + if substs.is_noop() { + return false; + } + + return match substs.type_at(0).sty { + ty::TyParam(_) => true, + ty::TyProjection(p) => self.is_of_param(p.substs), + _ => false, + }; + } + + fn get_lifetime(&self, region: Region, names_map: &FxHashMap) -> Lifetime { + self.region_name(region) + .map(|name| { + names_map.get(&name).unwrap_or_else(|| { + panic!("Missing lifetime with name {:?} for {:?}", name, region) + }) + }) + .unwrap_or(&Lifetime::statik()) + .clone() + } + + fn region_name(&self, region: Region) -> Option { + match region { + &ty::ReEarlyBound(r) => Some(r.name.as_str().to_string()), + _ => None, + } + } + + // This is very simiiar to handle_lifetimes. Instead of matching ty::Region's to ty::Region's, + // however, we match ty::RegionVid's to ty::Region's + fn map_vid_to_region<'cx>( + &self, + regions: &RegionConstraintData<'cx>, + ) -> FxHashMap> { + let mut vid_map: FxHashMap, RegionDeps<'cx>> = FxHashMap(); + let mut finished_map = FxHashMap(); + + for constraint in regions.constraints.keys() { + match constraint { + &Constraint::VarSubVar(r1, r2) => { + { + let deps1 = vid_map + .entry(RegionTarget::RegionVid(r1)) + .or_insert_with(|| Default::default()); + deps1.larger.insert(RegionTarget::RegionVid(r2)); + } + + let deps2 = vid_map + .entry(RegionTarget::RegionVid(r2)) + .or_insert_with(|| Default::default()); + deps2.smaller.insert(RegionTarget::RegionVid(r1)); + } + &Constraint::RegSubVar(region, vid) => { + { + let deps1 = vid_map + .entry(RegionTarget::Region(region)) + .or_insert_with(|| Default::default()); + deps1.larger.insert(RegionTarget::RegionVid(vid)); + } + + let deps2 = vid_map + .entry(RegionTarget::RegionVid(vid)) + .or_insert_with(|| Default::default()); + deps2.smaller.insert(RegionTarget::Region(region)); + } + &Constraint::VarSubReg(vid, region) => { + finished_map.insert(vid, region); + } + &Constraint::RegSubReg(r1, r2) => { + { + let deps1 = vid_map + .entry(RegionTarget::Region(r1)) + .or_insert_with(|| Default::default()); + deps1.larger.insert(RegionTarget::Region(r2)); + } + + let deps2 = vid_map + .entry(RegionTarget::Region(r2)) + .or_insert_with(|| Default::default()); + deps2.smaller.insert(RegionTarget::Region(r1)); + } + } + } + + while !vid_map.is_empty() { + let target = vid_map.keys().next().expect("Keys somehow empty").clone(); + let deps = vid_map.remove(&target).expect("Entry somehow missing"); + + for smaller in deps.smaller.iter() { + for larger in deps.larger.iter() { + match (smaller, larger) { + (&RegionTarget::Region(_), &RegionTarget::Region(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*smaller) { + let smaller_deps = v.into_mut(); + smaller_deps.larger.insert(*larger); + smaller_deps.larger.remove(&target); + } + + if let Entry::Occupied(v) = vid_map.entry(*larger) { + let larger_deps = v.into_mut(); + larger_deps.smaller.insert(*smaller); + larger_deps.smaller.remove(&target); + } + } + (&RegionTarget::RegionVid(v1), &RegionTarget::Region(r1)) => { + finished_map.insert(v1, r1); + } + (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => { + // Do nothing - we don't care about regions that are smaller than vids + } + (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*smaller) { + let smaller_deps = v.into_mut(); + smaller_deps.larger.insert(*larger); + smaller_deps.larger.remove(&target); + } + + if let Entry::Occupied(v) = vid_map.entry(*larger) { + let larger_deps = v.into_mut(); + larger_deps.smaller.insert(*smaller); + larger_deps.smaller.remove(&target); + } + } + } + } + } + } + finished_map + } + + // This method calculates two things: Lifetime constraints of the form 'a: 'b, + // and region constraints of the form ReVar: 'a + // + // This is essentially a simplified version of lexical_region_resolve. However, + // handle_lifetimes determines what *needs be* true in order for an impl to hold. + // lexical_region_resolve, along with much of the rest of the compiler, is concerned + // with determining if a given set up constraints/predicates *are* met, given some + // starting conditions (e.g. user-provided code). For this reason, it's easier + // to perform the calculations we need on our own, rather than trying to make + // existing inference/solver code do what we want + fn handle_lifetimes<'cx>( + &self, + regions: &RegionConstraintData<'cx>, + names_map: &FxHashMap, + ) -> Vec { + // Our goal is to 'flatten' the list of constraints by eliminating + // all intermediate RegionVids. At the end, all constraints should + // be between Regions (aka region variables). This gives us the information + // we need to create the Generics + // + let mut finished = FxHashMap(); + + let mut vid_map: FxHashMap = FxHashMap(); + + // Flattening is done in two parts. First, we insert all of the constraints + // into a map. Each RegionTarget (either a RegionVid or a Region) maps + // to its smaller and larger regions. Note that 'larger' regions correspond + // to sub-regions in Rust code (e.g. in 'a: 'b, 'a is the larger region). + for constraint in regions.constraints.keys() { + match constraint { + &Constraint::VarSubVar(r1, r2) => { + { + let deps1 = vid_map + .entry(RegionTarget::RegionVid(r1)) + .or_insert_with(|| Default::default()); + deps1.larger.insert(RegionTarget::RegionVid(r2)); + } + + let deps2 = vid_map + .entry(RegionTarget::RegionVid(r2)) + .or_insert_with(|| Default::default()); + deps2.smaller.insert(RegionTarget::RegionVid(r1)); + } + &Constraint::RegSubVar(region, vid) => { + let deps = vid_map + .entry(RegionTarget::RegionVid(vid)) + .or_insert_with(|| Default::default()); + deps.smaller.insert(RegionTarget::Region(region)); + } + &Constraint::VarSubReg(vid, region) => { + let deps = vid_map + .entry(RegionTarget::RegionVid(vid)) + .or_insert_with(|| Default::default()); + deps.larger.insert(RegionTarget::Region(region)); + } + &Constraint::RegSubReg(r1, r2) => { + // The constraint is already in the form that we want, so we're done with it + // Desired order is 'larger, smaller', so flip then + if self.region_name(r1) != self.region_name(r2) { + finished + .entry(self.region_name(r2).unwrap()) + .or_insert_with(|| Vec::new()) + .push(r1); + } + } + } + } + + // Here, we 'flatten' the map one element at a time. + // All of the element's sub and super regions are connected + // to each other. For example, if we have a graph that looks like this: + // + // (A, B) - C - (D, E) + // Where (A, B) are subregions, and (D,E) are super-regions + // + // then after deleting 'C', the graph will look like this: + // ... - A - (D, E ...) + // ... - B - (D, E, ...) + // (A, B, ...) - D - ... + // (A, B, ...) - E - ... + // + // where '...' signifies the existing sub and super regions of an entry + // When two adjacent ty::Regions are encountered, we've computed a final + // constraint, and add it to our list. Since we make sure to never re-add + // deleted items, this process will always finish. + while !vid_map.is_empty() { + let target = vid_map.keys().next().expect("Keys somehow empty").clone(); + let deps = vid_map.remove(&target).expect("Entry somehow missing"); + + for smaller in deps.smaller.iter() { + for larger in deps.larger.iter() { + match (smaller, larger) { + (&RegionTarget::Region(r1), &RegionTarget::Region(r2)) => { + if self.region_name(r1) != self.region_name(r2) { + finished + .entry(self.region_name(r2).unwrap()) + .or_insert_with(|| Vec::new()) + .push(r1) // Larger, smaller + } + } + (&RegionTarget::RegionVid(_), &RegionTarget::Region(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*smaller) { + let smaller_deps = v.into_mut(); + smaller_deps.larger.insert(*larger); + smaller_deps.larger.remove(&target); + } + } + (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*larger) { + let deps = v.into_mut(); + deps.smaller.insert(*smaller); + deps.smaller.remove(&target); + } + } + (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*smaller) { + let smaller_deps = v.into_mut(); + smaller_deps.larger.insert(*larger); + smaller_deps.larger.remove(&target); + } + + if let Entry::Occupied(v) = vid_map.entry(*larger) { + let larger_deps = v.into_mut(); + larger_deps.smaller.insert(*smaller); + larger_deps.smaller.remove(&target); + } + } + } + } + } + } + + let lifetime_predicates = names_map + .iter() + .flat_map(|(name, lifetime)| { + let empty = Vec::new(); + let bounds: FxHashSet = finished + .get(name) + .unwrap_or(&empty) + .iter() + .map(|region| self.get_lifetime(region, names_map)) + .collect(); + + if bounds.is_empty() { + return None; + } + Some(WherePredicate::RegionPredicate { + lifetime: lifetime.clone(), + bounds: bounds.into_iter().collect(), + }) + }) + .collect(); + + lifetime_predicates + } + + fn extract_for_generics<'b, 'c, 'd>( + &self, + tcx: TyCtxt<'b, 'c, 'd>, + pred: ty::Predicate<'d>, + ) -> FxHashSet { + pred.walk_tys() + .flat_map(|t| { + let mut regions = FxHashSet(); + tcx.collect_regions(&t, &mut regions); + + regions.into_iter().flat_map(|r| { + match r { + // We only care about late bound regions, as we need to add them + // to the 'for<>' section + &ty::ReLateBound(_, ty::BoundRegion::BrNamed(_, name)) => { + Some(GenericParam::Lifetime(Lifetime(name.as_str().to_string()))) + } + &ty::ReVar(_) | &ty::ReEarlyBound(_) => None, + _ => panic!("Unexpected region type {:?}", r), + } + }) + }) + .collect() + } + + fn make_final_bounds<'b, 'c, 'cx>( + &self, + ty_to_bounds: FxHashMap>, + ty_to_fn: FxHashMap, Option)>, + lifetime_to_bounds: FxHashMap>, + ) -> Vec { + let final_predicates = ty_to_bounds + .into_iter() + .flat_map(|(ty, mut bounds)| { + if let Some(data) = ty_to_fn.get(&ty) { + let (poly_trait, output) = + (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned()); + let new_ty = match &poly_trait.trait_ { + &Type::ResolvedPath { + ref path, + ref typarams, + ref did, + ref is_generic, + } => { + let mut new_path = path.clone(); + let last_segment = new_path.segments.pop().unwrap(); + + let (old_input, old_output) = match last_segment.params { + PathParameters::AngleBracketed { types, .. } => (types, None), + PathParameters::Parenthesized { inputs, output, .. } => { + (inputs, output) + } + }; + + if old_output.is_some() && old_output != output { + panic!( + "Output mismatch for {:?} {:?} {:?}", + ty, old_output, data.1 + ); + } + + let new_params = PathParameters::Parenthesized { + inputs: old_input, + output, + }; + + new_path.segments.push(PathSegment { + name: last_segment.name, + params: new_params, + }); + + Type::ResolvedPath { + path: new_path, + typarams: typarams.clone(), + did: did.clone(), + is_generic: *is_generic, + } + } + _ => panic!("Unexpected data: {:?}, {:?}", ty, data), + }; + bounds.insert(TyParamBound::TraitBound( + PolyTrait { + trait_: new_ty, + generic_params: poly_trait.generic_params, + }, + hir::TraitBoundModifier::None, + )); + } + if bounds.is_empty() { + return None; + } + + Some(WherePredicate::BoundPredicate { + ty, + bounds: bounds.into_iter().collect(), + }) + }) + .chain( + lifetime_to_bounds + .into_iter() + .filter(|&(_, ref bounds)| !bounds.is_empty()) + .map(|(lifetime, bounds)| WherePredicate::RegionPredicate { + lifetime, + bounds: bounds.into_iter().collect(), + }), + ) + .collect(); + + final_predicates + } + + // Converts the calculated ParamEnv and lifetime information to a clean::Generics, suitable for + // display on the docs page. Cleaning the Predicates produces sub-optimal WherePredicate's, + // so we fix them up: + // + // * Multiple bounds for the same type are coalesced into one: e.g. 'T: Copy', 'T: Debug' + // becomes 'T: Copy + Debug' + // * Fn bounds are handled specially - instead of leaving it as 'T: Fn(), = + // K', we use the dedicated syntax 'T: Fn() -> K' + // * We explcitly add a '?Sized' bound if we didn't find any 'Sized' predicates for a type + fn param_env_to_generics<'b, 'c, 'cx>( + &self, + tcx: TyCtxt<'b, 'c, 'cx>, + did: DefId, + param_env: ty::ParamEnv<'cx>, + type_generics: ty::Generics, + mut existing_predicates: Vec, + vid_to_region: FxHashMap>, + ) -> Generics { + debug!( + "param_env_to_generics(did={:?}, param_env={:?}, type_generics={:?}, \ + existing_predicates={:?})", + did, param_env, type_generics, existing_predicates + ); + + // The `Sized` trait must be handled specially, since we only only display it when + // it is *not* required (i.e. '?Sized') + let sized_trait = self.cx + .tcx + .require_lang_item(lang_items::SizedTraitLangItem); + + let mut replacer = RegionReplacer { + vid_to_region: &vid_to_region, + tcx, + }; + + let orig_bounds: FxHashSet<_> = self.cx.tcx.param_env(did).caller_bounds.iter().collect(); + let clean_where_predicates = param_env + .caller_bounds + .iter() + .filter(|p| { + !orig_bounds.contains(p) || match p { + &&ty::Predicate::Trait(pred) => pred.def_id() == sized_trait, + _ => false, + } + }) + .map(|p| { + let replaced = p.fold_with(&mut replacer); + (replaced.clone(), replaced.clean(self.cx)) + }); + + let full_generics = (&type_generics, &tcx.predicates_of(did)); + let Generics { + params: mut generic_params, + .. + } = full_generics.clean(self.cx); + + let mut has_sized = FxHashSet(); + let mut ty_to_bounds = FxHashMap(); + let mut lifetime_to_bounds = FxHashMap(); + let mut ty_to_traits: FxHashMap> = FxHashMap(); + + let mut ty_to_fn: FxHashMap, Option)> = FxHashMap(); + + for (orig_p, p) in clean_where_predicates { + match p { + WherePredicate::BoundPredicate { ty, mut bounds } => { + // Writing a projection trait bound of the form + // ::Name : ?Sized + // is illegal, because ?Sized bounds can only + // be written in the (here, nonexistant) definition + // of the type. + // Therefore, we make sure that we never add a ?Sized + // bound for projections + match &ty { + &Type::QPath { .. } => { + has_sized.insert(ty.clone()); + } + _ => {} + } + + if bounds.is_empty() { + continue; + } + + let mut for_generics = self.extract_for_generics(tcx, orig_p.clone()); + + assert!(bounds.len() == 1); + let mut b = bounds.pop().unwrap(); + + if b.is_sized_bound(self.cx) { + has_sized.insert(ty.clone()); + } else if !b.get_trait_type() + .and_then(|t| { + ty_to_traits + .get(&ty) + .map(|bounds| bounds.contains(&strip_type(t.clone()))) + }) + .unwrap_or(false) + { + // If we've already added a projection bound for the same type, don't add + // this, as it would be a duplicate + + // Handle any 'Fn/FnOnce/FnMut' bounds specially, + // as we want to combine them with any 'Output' qpaths + // later + + let is_fn = match &mut b { + &mut TyParamBound::TraitBound(ref mut p, _) => { + // Insert regions into the for_generics hash map first, to ensure + // that we don't end up with duplicate bounds (e.g. for<'b, 'b>) + for_generics.extend(p.generic_params.clone()); + p.generic_params = for_generics.into_iter().collect(); + self.is_fn_ty(&tcx, &p.trait_) + } + _ => false, + }; + + let poly_trait = b.get_poly_trait().unwrap(); + + if is_fn { + ty_to_fn + .entry(ty.clone()) + .and_modify(|e| *e = (Some(poly_trait.clone()), e.1.clone())) + .or_insert(((Some(poly_trait.clone())), None)); + + ty_to_bounds + .entry(ty.clone()) + .or_insert_with(|| FxHashSet()); + } else { + ty_to_bounds + .entry(ty.clone()) + .or_insert_with(|| FxHashSet()) + .insert(b.clone()); + } + } + } + WherePredicate::RegionPredicate { lifetime, bounds } => { + lifetime_to_bounds + .entry(lifetime) + .or_insert_with(|| FxHashSet()) + .extend(bounds); + } + WherePredicate::EqPredicate { lhs, rhs } => { + match &lhs { + &Type::QPath { + name: ref left_name, + ref self_type, + ref trait_, + } => { + let ty = &*self_type; + match **trait_ { + Type::ResolvedPath { + path: ref trait_path, + ref typarams, + ref did, + ref is_generic, + } => { + let mut new_trait_path = trait_path.clone(); + + if self.is_fn_ty(&tcx, trait_) && left_name == FN_OUTPUT_NAME { + ty_to_fn + .entry(*ty.clone()) + .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) + .or_insert((None, Some(rhs))); + continue; + } + + // FIXME: Remove this scope when NLL lands + { + let params = + &mut new_trait_path.segments.last_mut().unwrap().params; + + match params { + // Convert somethiung like ' = u8' + // to 'T: Iterator' + &mut PathParameters::AngleBracketed { + ref mut bindings, + .. + } => { + bindings.push(TypeBinding { + name: left_name.clone(), + ty: rhs, + }); + } + &mut PathParameters::Parenthesized { .. } => { + existing_predicates.push( + WherePredicate::EqPredicate { + lhs: lhs.clone(), + rhs, + }, + ); + continue; // If something other than a Fn ends up + // with parenthesis, leave it alone + } + } + } + + let bounds = ty_to_bounds + .entry(*ty.clone()) + .or_insert_with(|| FxHashSet()); + + bounds.insert(TyParamBound::TraitBound( + PolyTrait { + trait_: Type::ResolvedPath { + path: new_trait_path, + typarams: typarams.clone(), + did: did.clone(), + is_generic: *is_generic, + }, + generic_params: Vec::new(), + }, + hir::TraitBoundModifier::None, + )); + + // Remove any existing 'plain' bound (e.g. 'T: Iterator`) so + // that we don't see a + // duplicate bound like `T: Iterator + Iterator` + // on the docs page. + bounds.remove(&TyParamBound::TraitBound( + PolyTrait { + trait_: *trait_.clone(), + generic_params: Vec::new(), + }, + hir::TraitBoundModifier::None, + )); + // Avoid creating any new duplicate bounds later in the outer + // loop + ty_to_traits + .entry(*ty.clone()) + .or_insert_with(|| FxHashSet()) + .insert(*trait_.clone()); + } + _ => panic!("Unexpected trait {:?} for {:?}", trait_, did), + } + } + _ => panic!("Unexpected LHS {:?} for {:?}", lhs, did), + } + } + }; + } + + let final_bounds = self.make_final_bounds(ty_to_bounds, ty_to_fn, lifetime_to_bounds); + + existing_predicates.extend(final_bounds); + + for p in generic_params.iter_mut() { + match p { + &mut GenericParam::Type(ref mut ty) => { + // We never want something like 'impl' + ty.default.take(); + + let generic_ty = Type::Generic(ty.name.clone()); + + if !has_sized.contains(&generic_ty) { + ty.bounds.insert(0, TyParamBound::maybe_sized(self.cx)); + } + } + _ => {} + } + } + + Generics { + params: generic_params, + where_predicates: existing_predicates, + } + } + + fn is_fn_ty(&self, tcx: &TyCtxt, ty: &Type) -> bool { + match &ty { + &&Type::ResolvedPath { ref did, .. } => { + *did == tcx.require_lang_item(lang_items::FnTraitLangItem) + || *did == tcx.require_lang_item(lang_items::FnMutTraitLangItem) + || *did == tcx.require_lang_item(lang_items::FnOnceTraitLangItem) + } + _ => false, + } + } + + // This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly + // refactorying either librustdoc or librustc. In particular, allowing new DefIds to be + // registered after the AST is constructed would require storing the defid mapping in a + // RefCell, decreasing the performance for normal compilation for very little gain. + // + // Instead, we construct 'fake' def ids, which start immediately after the last DefId in + // DefIndexAddressSpace::Low. In the Debug impl for clean::Item, we explicitly check for fake + // def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds + fn next_def_id(&self, crate_num: CrateNum) -> DefId { + let start_def_id = { + let next_id = if crate_num == LOCAL_CRATE { + self.cx + .tcx + .hir + .definitions() + .def_path_table() + .next_id(DefIndexAddressSpace::Low) + } else { + self.cx + .cstore + .def_path_table(crate_num) + .next_id(DefIndexAddressSpace::Low) + }; + + DefId { + krate: crate_num, + index: next_id, + } + }; + + let mut fake_ids = self.cx.fake_def_ids.borrow_mut(); + + let def_id = fake_ids.entry(crate_num).or_insert(start_def_id).clone(); + fake_ids.insert( + crate_num, + DefId { + krate: crate_num, + index: DefIndex::from_array_index( + def_id.index.as_array_index() + 1, + def_id.index.address_space(), + ), + }, + ); + + MAX_DEF_ID.with(|m| { + m.borrow_mut() + .entry(def_id.krate.clone()) + .or_insert(start_def_id); + }); + + self.cx.all_fake_def_ids.borrow_mut().insert(def_id); + + def_id.clone() + } +} + +// Replaces all ReVars in a type with ty::Region's, using the provided map +struct RegionReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + vid_to_region: &'a FxHashMap>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, +} + +impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + (match r { + &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), + _ => None, + }).unwrap_or_else(|| r.super_fold_with(self)) + } +} diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 5eb3e38d5b3..a769771f8aa 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -25,7 +25,7 @@ use syntax_pos::Span; use html::escape::Escape; -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, PartialEq)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, Hash)] pub enum Cfg { /// Accepts all configurations. True, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9aba399b3b0..f32dbcb8a08 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -12,8 +12,8 @@ use std::collections::BTreeMap; use std::io; -use std::iter::once; use std::rc::Rc; +use std::iter::once; use syntax::ast; use rustc::hir; @@ -25,7 +25,7 @@ use rustc::util::nodemap::FxHashSet; use core::{DocContext, DocAccessLevels}; use doctree; -use clean::{self, GetDefId}; +use clean::{self, GetDefId, get_auto_traits_with_def_id}; use super::Clean; @@ -50,7 +50,7 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name) let inner = match def { Def::Trait(did) => { record_extern_fqn(cx, did, clean::TypeKind::Trait); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, false)); clean::TraitItem(build_external_trait(cx, did)) } Def::Fn(did) => { @@ -59,27 +59,27 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name) } Def::Struct(did) => { record_extern_fqn(cx, did, clean::TypeKind::Struct); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, true)); clean::StructItem(build_struct(cx, did)) } Def::Union(did) => { record_extern_fqn(cx, did, clean::TypeKind::Union); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, true)); clean::UnionItem(build_union(cx, did)) } Def::TyAlias(did) => { record_extern_fqn(cx, did, clean::TypeKind::Typedef); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, true)); clean::TypedefItem(build_type_alias(cx, did), false) } Def::Enum(did) => { record_extern_fqn(cx, did, clean::TypeKind::Enum); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, true)); clean::EnumItem(build_enum(cx, did)) } Def::TyForeign(did) => { record_extern_fqn(cx, did, clean::TypeKind::Foreign); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, false)); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. @@ -120,11 +120,17 @@ pub fn load_attrs(cx: &DocContext, did: DefId) -> clean::Attributes { cx.tcx.get_attrs(did).clean(cx) } + /// Record an external fully qualified name in the external_paths cache. /// /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { + if did.is_local() { + debug!("record_extern_fqn(did={:?}, kind+{:?}): def_id is local, aborting", did, kind); + return; + } + let crate_name = cx.tcx.crate_name(did.krate).to_string(); let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { // extern blocks have an empty name @@ -144,6 +150,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { } pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { + let auto_trait = cx.tcx.trait_def(did).has_auto_impl; let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); let predicates = cx.tcx.predicates_of(did); let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); @@ -152,6 +159,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { let is_spotlight = load_attrs(cx, did).has_doc_flag("spotlight"); let is_auto = cx.tcx.trait_is_auto(did); clean::Trait { + auto: auto_trait, unsafety: cx.tcx.trait_def(did).unsafety, generics, items: trait_items, @@ -227,7 +235,7 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { } } -pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { +pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec { let tcx = cx.tcx; let mut impls = Vec::new(); @@ -235,6 +243,16 @@ pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { build_impl(cx, did, &mut impls); } + if auto_traits { + let auto_impls = get_auto_traits_with_def_id(cx, did); + let mut renderinfo = cx.renderinfo.borrow_mut(); + + let new_impls: Vec = auto_impls.into_iter() + .filter(|i| renderinfo.inlined.insert(i.def_id)).collect(); + + impls.extend(new_impls); + } + // If this is the first time we've inlined something from another crate, then // we inline *all* impls from all the crates into this crate. Note that there's // currently no way for us to filter this based on type, and we likely need @@ -249,6 +267,7 @@ pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { cx.populated_all_crate_impls.set(true); + for &cnum in tcx.crates().iter() { for did in tcx.all_trait_implementations(cnum).iter() { build_impl(cx, *did, &mut impls); @@ -347,13 +366,14 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { ret.push(clean::Item { inner: clean::ImplItem(clean::Impl { - unsafety: hir::Unsafety::Normal, // FIXME: this should be decoded + unsafety: hir::Unsafety::Normal, + generics: (tcx.generics_of(did), &predicates).clean(cx), provided_trait_methods: provided, trait_, for_, - generics: (tcx.generics_of(did), &predicates).clean(cx), items: trait_items, polarity: Some(polarity.clean(cx)), + synthetic: false }), source: tcx.def_span(did).clean(cx), name: None, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7f51b8f68ae..fcefe6cf642 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,31 +26,41 @@ use syntax::codemap::Spanned; use syntax::feature_gate::UnstableFeatures; use syntax::ptr::P; use syntax::symbol::keywords; +use syntax::symbol::Symbol; use syntax_pos::{self, DUMMY_SP, Pos, FileName}; use rustc::middle::const_val::ConstVal; use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime as rl; +use rustc::ty::fold::TypeFolder; use rustc::middle::lang_items; -use rustc::hir::def::{Def, CtorKind}; -use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc::hir::{self, HirVec}; +use rustc::hir::def::{self, Def, CtorKind}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc::hir::def_id::DefIndexAddressSpace; +use rustc::traits; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, AdtKind}; +use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::middle::stability; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_typeck::hir_ty_to_ty; - -use rustc::hir; +use rustc::infer::{InferCtxt, RegionObligation}; +use rustc::infer::region_constraints::{RegionConstraintData, Constraint}; +use rustc::traits::*; +use std::collections::hash_map::Entry; +use std::collections::VecDeque; +use std::fmt; use rustc_const_math::ConstInt; use std::default::Default; use std::{mem, slice, vec}; -use std::iter::FromIterator; +use std::iter::{FromIterator, once}; use std::rc::Rc; +use std::cell::RefCell; use std::sync::Arc; use std::u32; -use core::DocContext; +use core::{self, DocContext}; use doctree; use visit_ast; use html::item_type::ItemType; @@ -59,8 +69,14 @@ use html::markdown::markdown_links; pub mod inline; pub mod cfg; mod simplify; +mod auto_trait; use self::cfg::Cfg; +use self::auto_trait::AutoTraitFinder; + +thread_local!(static MAX_DEF_ID: RefCell> = RefCell::new(FxHashMap())); + +const FN_OUTPUT_NAME: &'static str = "Output"; // extract the stability index for a node from tcx, if possible fn get_stability(cx: &DocContext, def_id: DefId) -> Option { @@ -282,7 +298,7 @@ impl Clean for CrateNum { /// Anything with a source location and set of attributes and, optionally, a /// name. That is, anything that can be documented. This doesn't correspond /// directly to the AST's concept of an item; it's a strict superset. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Item { /// Stringified span pub source: Span, @@ -296,6 +312,26 @@ pub struct Item { pub deprecation: Option, } +impl fmt::Debug for Item { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + + let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate) + .map(|id| self.def_id >= *id).unwrap_or(false)); + let def_id: &fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; + + fmt.debug_struct("Item") + .field("source", &self.source) + .field("name", &self.name) + .field("attrs", &self.attrs) + .field("inner", &self.inner) + .field("visibility", &self.visibility) + .field("def_id", def_id) + .field("stability", &self.stability) + .field("deprecation", &self.deprecation) + .finish() + } +} + impl Item { /// Finds the `doc` attribute as a NameValue and returns the corresponding /// value found. @@ -492,9 +528,9 @@ impl Clean for doctree::Module { let mut items: Vec = vec![]; items.extend(self.extern_crates.iter().map(|x| x.clean(cx))); items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); - items.extend(self.structs.iter().map(|x| x.clean(cx))); - items.extend(self.unions.iter().map(|x| x.clean(cx))); - items.extend(self.enums.iter().map(|x| x.clean(cx))); + items.extend(self.structs.iter().flat_map(|x| x.clean(cx))); + items.extend(self.unions.iter().flat_map(|x| x.clean(cx))); + items.extend(self.enums.iter().flat_map(|x| x.clean(cx))); items.extend(self.fns.iter().map(|x| x.clean(cx))); items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); @@ -601,7 +637,7 @@ impl> NestedAttributesExt for I { /// Included files are kept separate from inline doc comments so that proper line-number /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are /// kept separate because of issue #42760. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub enum DocFragment { // FIXME #44229 (misdreavus): sugared and raw doc comments can be brought back together once // hoedown is completely removed from rustdoc. @@ -653,7 +689,7 @@ impl<'a> FromIterator<&'a DocFragment> for String { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)] pub struct Attributes { pub doc_strings: Vec, pub other_attrs: Vec, @@ -1177,7 +1213,7 @@ impl Clean for [ast::Attribute] { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct TyParam { pub name: String, pub did: DefId, @@ -1212,7 +1248,7 @@ impl<'tcx> Clean for ty::TypeParameterDef { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub enum TyParamBound { RegionBound(Lifetime), TraitBound(PolyTrait, hir::TraitBoundModifier) @@ -1245,6 +1281,21 @@ impl TyParamBound { } false } + + fn get_poly_trait(&self) -> Option { + if let TyParamBound::TraitBound(ref p, _) = *self { + return Some(p.clone()) + } + None + } + + fn get_trait_type(&self) -> Option { + + if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { + return Some(trait_.clone()); + } + None + } } impl Clean for hir::TyParamBound { @@ -1363,7 +1414,7 @@ impl<'tcx> Clean>> for Substs<'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct Lifetime(String); impl Lifetime { @@ -1380,17 +1431,19 @@ impl Lifetime { impl Clean for hir::Lifetime { fn clean(&self, cx: &DocContext) -> Lifetime { - let hir_id = cx.tcx.hir.node_to_hir_id(self.id); - let def = cx.tcx.named_region(hir_id); - match def { - Some(rl::Region::EarlyBound(_, node_id, _)) | - Some(rl::Region::LateBound(_, node_id, _)) | - Some(rl::Region::Free(_, node_id)) => { - if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() { - return lt; + if self.id != ast::DUMMY_NODE_ID { + let hir_id = cx.tcx.hir.node_to_hir_id(self.id); + let def = cx.tcx.named_region(hir_id); + match def { + Some(rl::Region::EarlyBound(_, node_id, _)) | + Some(rl::Region::LateBound(_, node_id, _)) | + Some(rl::Region::Free(_, node_id)) => { + if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() { + return lt; + } } + _ => {} } - _ => {} } Lifetime(self.name.name().to_string()) } @@ -1437,7 +1490,7 @@ impl Clean> for ty::RegionKind { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec}, @@ -1562,7 +1615,7 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub enum GenericParam { Lifetime(Lifetime), Type(TyParam), @@ -1577,7 +1630,8 @@ impl Clean for hir::GenericParam { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)] +// maybe use a Generic enum and use Vec? +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)] pub struct Generics { pub params: Vec, pub where_predicates: Vec, @@ -1747,7 +1801,7 @@ impl Clean for doctree::Function { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct FnDecl { pub inputs: Arguments, pub output: FunctionRetTy, @@ -1765,7 +1819,7 @@ impl FnDecl { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct Arguments { pub values: Vec, } @@ -1840,7 +1894,7 @@ impl<'a, 'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct Argument { pub type_: Type, pub name: String, @@ -1870,7 +1924,7 @@ impl Argument { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub enum FunctionRetTy { Return(Type), DefaultReturn, @@ -1896,6 +1950,7 @@ impl GetDefId for FunctionRetTy { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Trait { + pub auto: bool, pub unsafety: hir::Unsafety, pub items: Vec, pub generics: Generics, @@ -1917,6 +1972,7 @@ impl Clean for doctree::Trait { stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), inner: TraitItem(Trait { + auto: self.is_auto.clean(cx), unsafety: self.unsafety, items: self.items.clean(cx), generics: self.generics.clean(cx), @@ -2158,7 +2214,7 @@ impl<'tcx> Clean for ty::AssociatedItem { } /// A trait reference, which may have higher ranked lifetimes. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct PolyTrait { pub trait_: Type, pub generic_params: Vec, @@ -2167,7 +2223,7 @@ pub struct PolyTrait { /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original /// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly /// it does not preserve mutability or boxes. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub enum Type { /// structs/enums/traits (most that'd be an hir::TyPath) ResolvedPath { @@ -2782,10 +2838,13 @@ pub struct Union { pub fields_stripped: bool, } -impl Clean for doctree::Struct { - fn clean(&self, cx: &DocContext) -> Item { - Item { - name: Some(self.name.clean(cx)), +impl Clean> for doctree::Struct { + fn clean(&self, cx: &DocContext) -> Vec { + let name = self.name.clean(cx); + let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); + + ret.push(Item { + name: Some(name), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2798,14 +2857,19 @@ impl Clean for doctree::Struct { fields: self.fields.clean(cx), fields_stripped: false, }), - } + }); + + ret } } -impl Clean for doctree::Union { - fn clean(&self, cx: &DocContext) -> Item { - Item { - name: Some(self.name.clean(cx)), +impl Clean> for doctree::Union { + fn clean(&self, cx: &DocContext) -> Vec { + let name = self.name.clean(cx); + let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); + + ret.push(Item { + name: Some(name), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2818,7 +2882,9 @@ impl Clean for doctree::Union { fields: self.fields.clean(cx), fields_stripped: false, }), - } + }); + + ret } } @@ -2849,10 +2915,13 @@ pub struct Enum { pub variants_stripped: bool, } -impl Clean for doctree::Enum { - fn clean(&self, cx: &DocContext) -> Item { - Item { - name: Some(self.name.clean(cx)), +impl Clean> for doctree::Enum { + fn clean(&self, cx: &DocContext) -> Vec { + let name = self.name.clean(cx); + let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); + + ret.push(Item { + name: Some(name), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2864,7 +2933,9 @@ impl Clean for doctree::Enum { generics: self.generics.clean(cx), variants_stripped: false, }), - } + }); + + ret } } @@ -2989,7 +3060,7 @@ impl Clean for syntax_pos::Span { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct Path { pub global: bool, pub def: Def, @@ -3027,7 +3098,7 @@ impl Clean for hir::Path { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub enum PathParameters { AngleBracketed { lifetimes: Vec, @@ -3062,7 +3133,7 @@ impl Clean for hir::PathParameters { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct PathSegment { pub name: String, pub params: PathParameters, @@ -3077,6 +3148,50 @@ impl Clean for hir::PathSegment { } } +fn strip_type(ty: Type) -> Type { + match ty { + Type::ResolvedPath { path, typarams, did, is_generic } => { + Type::ResolvedPath { path: strip_path(&path), typarams, did, is_generic } + }, + Type::Tuple(inner_tys) => { + Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect()) + }, + Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), + Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), + Type::Unique(inner_ty) => Type::Unique(Box::new(strip_type(*inner_ty))), + Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), + Type::BorrowedRef { lifetime, mutability, type_ } => { + Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } + }, + Type::QPath { name, self_type, trait_ } => { + Type::QPath { + name, + self_type: Box::new(strip_type(*self_type)), trait_: Box::new(strip_type(*trait_)) + } + }, + _ => ty + } +} + +fn strip_path(path: &Path) -> Path { + let segments = path.segments.iter().map(|s| { + PathSegment { + name: s.name.clone(), + params: PathParameters::AngleBracketed { + lifetimes: Vec::new(), + types: Vec::new(), + bindings: Vec::new() + } + } + }).collect(); + + Path { + global: path.global, + def: path.def.clone(), + segments + } +} + fn qpath_to_string(p: &hir::QPath) -> String { let segments = match *p { hir::QPath::Resolved(_, ref path) => &path.segments, @@ -3125,7 +3240,7 @@ impl Clean for doctree::Typedef { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct BareFunctionDecl { pub unsafety: hir::Unsafety, pub generic_params: Vec, @@ -3198,7 +3313,7 @@ impl Clean for doctree::Constant { } } -#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)] +#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Hash)] pub enum Mutability { Mutable, Immutable, @@ -3213,7 +3328,7 @@ impl Clean for hir::Mutability { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Debug, Hash)] pub enum ImplPolarity { Positive, Negative, @@ -3237,6 +3352,21 @@ pub struct Impl { pub for_: Type, pub items: Vec, pub polarity: Option, + pub synthetic: bool, +} + +pub fn get_auto_traits_with_node_id(cx: &DocContext, id: ast::NodeId, name: String) -> Vec { + let finder = AutoTraitFinder { cx }; + finder.get_with_node_id(id, name) +} + +pub fn get_auto_traits_with_def_id(cx: &DocContext, id: DefId) -> Vec { + + let finder = AutoTraitFinder { + cx, + }; + + finder.get_with_def_id(id) } impl Clean> for doctree::Impl { @@ -3274,7 +3404,8 @@ impl Clean> for doctree::Impl { for_: self.for_.clean(cx), items, polarity: Some(self.polarity.clean(cx)), - }), + synthetic: false + }) }); ret } @@ -3294,7 +3425,7 @@ fn build_deref_target_impls(cx: &DocContext, let primitive = match *target { ResolvedPath { did, .. } if did.is_local() => continue, ResolvedPath { did, .. } => { - ret.extend(inline::build_impls(cx, did)); + ret.extend(inline::build_impls(cx, did, true)); continue } _ => match target.primitive_type() { @@ -3514,7 +3645,11 @@ fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String { fn resolve_type(cx: &DocContext, path: Path, id: ast::NodeId) -> Type { - debug!("resolve_type({:?},{:?})", path, id); + if id == ast::DUMMY_NODE_ID { + debug!("resolve_type({:?})", path); + } else { + debug!("resolve_type({:?},{:?})", path, id); + } let is_generic = match path.def { Def::PrimTy(p) => match p { @@ -3669,7 +3804,7 @@ impl Clean for attr::Deprecation { } /// An equality constraint on an associated type, e.g. `A=Bar` in `Foo` -#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)] +#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)] pub struct TypeBinding { pub name: String, pub ty: Type @@ -3683,3 +3818,191 @@ impl Clean for hir::TypeBinding { } } } + + + +pub fn def_id_to_path(cx: &DocContext, did: DefId, name: Option) -> Vec { + let crate_name = name.unwrap_or_else(|| cx.tcx.crate_name(did.krate).to_string()); + let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { + // extern blocks have an empty name + let s = elem.data.to_string(); + if !s.is_empty() { + Some(s) + } else { + None + } + }); + once(crate_name).chain(relative).collect() +} + + +// Start of code copied from rust-clippy + +pub fn get_trait_def_id(tcx: &TyCtxt, path: &[&str], use_local: bool) -> Option { + return if use_local { + path_to_def_local(tcx, path) + } else { + path_to_def(tcx, path) + }; +} + +pub fn path_to_def_local(tcx: &TyCtxt, path: &[&str]) -> Option { + let krate = tcx.hir.krate(); + let mut items = krate.module.item_ids.clone(); + let mut path_it = path.iter().peekable(); + + loop { + let segment = match path_it.next() { + Some(segment) => segment, + None => return None, + }; + + for item_id in mem::replace(&mut items, HirVec::new()).iter() { + let item = tcx.hir.expect_item(item_id.id); + if item.name == *segment { + if path_it.peek().is_none() { + return Some(tcx.hir.local_def_id(item_id.id)) + } + + items = match &item.node { + &hir::ItemMod(ref m) => m.item_ids.clone(), + _ => panic!("Unexpected item {:?} in path {:?} path") + }; + break; + } + } + } + +} + +pub fn path_to_def(tcx: &TyCtxt, path: &[&str]) -> Option { + let crates = tcx.crates(); + + + let krate = crates + .iter() + .find(|&&krate| tcx.crate_name(krate) == path[0]); + + if let Some(krate) = krate { + let krate = DefId { + krate: *krate, + index: CRATE_DEF_INDEX, + }; + let mut items = tcx.item_children(krate); + let mut path_it = path.iter().skip(1).peekable(); + + loop { + let segment = match path_it.next() { + Some(segment) => segment, + None => return None, + }; + + for item in mem::replace(&mut items, Rc::new(vec![])).iter() { + if item.ident.name == *segment { + if path_it.peek().is_none() { + return match item.def { + def::Def::Trait(did) => Some(did), + _ => None + } + } + + items = tcx.item_children(item.def.def_id()); + break; + } + } + } + } else { + None + } +} + +fn get_path_for_type(tcx: TyCtxt, def_id: DefId, def_ctor: fn(DefId) -> Def) -> hir::Path { + struct AbsolutePathBuffer { + names: Vec, + } + + impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer { + fn root_mode(&self) -> &ty::item_path::RootMode { + const ABSOLUTE: &'static ty::item_path::RootMode = &ty::item_path::RootMode::Absolute; + ABSOLUTE + } + + fn push(&mut self, text: &str) { + self.names.push(text.to_owned()); + } + } + + let mut apb = AbsolutePathBuffer { names: vec![] }; + + tcx.push_item_path(&mut apb, def_id); + + hir::Path { + span: DUMMY_SP, + def: def_ctor(def_id), + segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment { + name: ast::Name::intern(&s), + parameters: None, + infer_types: false + }).collect()) + } +} + +// End of code copied from rust-clippy + + +#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] +enum RegionTarget<'tcx> { + Region(Region<'tcx>), + RegionVid(RegionVid) +} + +#[derive(Default, Debug, Clone)] +struct RegionDeps<'tcx> { + larger: FxHashSet>, + smaller: FxHashSet> +} + +#[derive(Eq, PartialEq, Hash, Debug)] +enum SimpleBound { + RegionBound(Lifetime), + TraitBound(Vec, Vec, Vec, hir::TraitBoundModifier) +} + +enum AutoTraitResult { + ExplicitImpl, + + PositiveImpl(Generics), + + NegativeImpl, +} + +impl AutoTraitResult { + + fn is_auto(&self) -> bool { + match *self { + AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, + _ => false + } + } +} + +impl From for SimpleBound { + + fn from(bound: TyParamBound) -> Self { + match bound.clone() { + TyParamBound::RegionBound(l) => SimpleBound::RegionBound(l), + TyParamBound::TraitBound(t, mod_) => match t.trait_ { + Type::ResolvedPath { path, typarams, .. } => { + SimpleBound::TraitBound(path.segments, + typarams + .map_or_else(|| Vec::new(), |v| v.iter() + .map(|p| SimpleBound::from(p.clone())) + .collect()), + t.generic_params, + mod_) + }, + _ => panic!("Unexpected bound {:?}", bound) + } + } + } +} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 81babd803a5..57773e4e068 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -11,13 +11,14 @@ use rustc_lint; use rustc_driver::{self, driver, target_features, abort_on_err}; use rustc::session::{self, config}; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, CrateNum}; use rustc::hir::def::Def; +use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt, AllArenas}; use rustc::hir::map as hir_map; use rustc::lint; -use rustc::util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_resolve as resolve; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; @@ -48,6 +49,8 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { pub resolver: &'a RefCell>, /// The stack of module NodeIds up till this point pub mod_ids: RefCell>, + pub crate_name: Option, + pub cstore: Rc, pub populated_all_crate_impls: Cell, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -65,6 +68,11 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { pub ty_substs: RefCell>, /// Table node id of lifetime parameter definition -> substituted lifetime pub lt_substs: RefCell>, + pub send_trait: Option, + pub fake_def_ids: RefCell>, + pub all_fake_def_ids: RefCell>, + /// Maps (type_id, trait_id) -> auto trait impl + pub generated_synthetics: RefCell> } impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { @@ -107,6 +115,7 @@ pub fn run_core(search_paths: SearchPaths, triple: Option, maybe_sysroot: Option, allow_warnings: bool, + crate_name: Option, force_unstable_if_unmarked: bool) -> (clean::Crate, RenderInfo) { // Parse, resolve, and typecheck the given crate. @@ -230,9 +239,19 @@ pub fn run_core(search_paths: SearchPaths, .collect() }; + let send_trait; + + if crate_name == Some("core".to_string()) { + send_trait = clean::get_trait_def_id(&tcx, &["marker", "Send"], true); + } else { + send_trait = clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false) + } + let ctxt = DocContext { tcx, resolver: &resolver, + crate_name, + cstore: cstore.clone(), populated_all_crate_impls: Cell::new(false), access_levels: RefCell::new(access_levels), external_traits: Default::default(), @@ -240,6 +259,10 @@ pub fn run_core(search_paths: SearchPaths, ty_substs: Default::default(), lt_substs: Default::default(), mod_ids: Default::default(), + send_trait: send_trait, + fake_def_ids: RefCell::new(FxHashMap()), + all_fake_def_ids: RefCell::new(FxHashSet()), + generated_synthetics: RefCell::new(FxHashSet()) }; debug!("crate: {:?}", tcx.hir.krate()); diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 430236f30c4..413e5623118 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -210,6 +210,7 @@ pub struct Trait { pub depr: Option, } +#[derive(Debug)] pub struct Impl { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d6025920e78..6e265ed0776 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -37,7 +37,7 @@ pub use self::ExternalLocation::*; use std::borrow::Cow; use std::cell::RefCell; use std::cmp::Ordering; -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashSet, VecDeque}; use std::default::Default; use std::error; use std::fmt::{self, Display, Formatter, Write as FmtWrite}; @@ -169,6 +169,7 @@ pub enum ExternalLocation { Unknown, } + /// Metadata about implementations for a type or trait. #[derive(Clone)] pub struct Impl { @@ -270,6 +271,18 @@ pub struct Cache { /// generating explicit hyperlinks to other crates. pub external_paths: FxHashMap, ItemType)>, + /// Maps local def ids of exported types to fully qualified paths. + /// Unlike 'paths', this mapping ignores any renames that occur + /// due to 'use' statements. + /// + /// This map is used when writing out the special 'implementors' + /// javascript file. By using the exact path that the type + /// is declared with, we ensure that each path will be identical + /// to the path used if the corresponding type is inlined. By + /// doing this, we can detect duplicate impls on a trait page, and only display + /// the impl for the inlined type. + pub exact_paths: FxHashMap>, + /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the /// parent trait if no extra documentation is specified, and default methods @@ -322,6 +335,7 @@ pub struct RenderInfo { pub inlined: FxHashSet, pub external_paths: ::core::ExternalPaths, pub external_typarams: FxHashMap, + pub exact_paths: FxHashMap>, pub deref_trait_did: Option, pub deref_mut_trait_did: Option, pub owned_box_did: Option, @@ -436,7 +450,9 @@ fn init_ids() -> FxHashMap { "required-methods", "provided-methods", "implementors", + "synthetic-implementors", "implementors-list", + "synthetic-implementors-list", "methods", "deref-methods", "implementations", @@ -507,6 +523,7 @@ pub fn run(mut krate: clean::Crate, themes, }; + // If user passed in `--playground-url` arg, we fill in crate name here if let Some(url) = playground_url { markdown::PLAYGROUND.with(|slot| { @@ -556,6 +573,7 @@ pub fn run(mut krate: clean::Crate, inlined: _, external_paths, external_typarams, + exact_paths, deref_trait_did, deref_mut_trait_did, owned_box_did, @@ -568,6 +586,7 @@ pub fn run(mut krate: clean::Crate, let mut cache = Cache { impls: FxHashMap(), external_paths, + exact_paths, paths: FxHashMap(), implementors: FxHashMap(), stack: Vec::new(), @@ -873,7 +892,10 @@ themePicker.onclick = function() {{ // should add it. if !imp.impl_item.def_id.is_local() { continue } have_impls = true; - write!(implementors, "{},", as_json(&imp.inner_impl().to_string())).unwrap(); + write!(implementors, "{{text:{},synthetic:{},types:{}}},", + as_json(&imp.inner_impl().to_string()), + imp.inner_impl().synthetic, + as_json(&collect_paths_for_type(imp.inner_impl().for_.clone()))).unwrap(); } implementors.push_str("];"); @@ -1856,8 +1878,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, items: &[clean::Item]) -> fmt::Result { document(w, cx, item)?; - let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()) - .collect::>(); + let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); // the order of item types in the listing fn reorder(ty: ItemType) -> u8 { @@ -2201,6 +2222,50 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, document(w, cx, it) } +fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter, + implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> Result<(), fmt::Error> { + write!(w, "")?; + Ok(()) +} + +fn render_impls(cx: &Context, w: &mut fmt::Formatter, + traits: Vec<&&Impl>, + containing_item: &clean::Item) -> Result<(), fmt::Error> { + for i in &traits { + let did = i.trait_did().unwrap(); + let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); + render_impl(w, cx, i, assoc_link, + RenderMode::Normal, containing_item.stable_since(), true)?; + } + Ok(()) +} + fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Trait) -> fmt::Result { let mut bounds = String::new(); @@ -2380,6 +2445,14 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
    "; + + let synthetic_impl_header = " +

    + Auto implementors +

    +
      + "; + if let Some(implementors) = cache.implementors.get(&it.def_id) { // The DefId is for the first Type found with that name. The bool is // if any Types with the same name but different DefId have been found. @@ -2405,6 +2478,11 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, .partition::, _>(|i| i.inner_impl().for_.def_id() .map_or(true, |d| cache.paths.contains_key(&d))); + + let (synthetic, concrete) = local.iter() + .partition::, _>(|i| i.inner_impl().synthetic); + + if !foreign.is_empty() { write!(w, "

      @@ -2422,42 +2500,48 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } write!(w, "{}", impl_header)?; + for implementor in concrete { + render_implementor(cx, implementor, w, &implementor_dups)?; + } + write!(w, "

    ")?; - for implementor in local { - write!(w, "
  • ")?; - if let Some(l) = (Item { cx, item: &implementor.impl_item }).src_href() { - write!(w, "
    ")?; - write!(w, "[src]", - l, "goto source code")?; - write!(w, "
    ")?; - } - write!(w, "")?; - // If there's already another implementor that has the same abbridged name, use the - // full path, for example in `std::iter::ExactSizeIterator` - let use_absolute = match implementor.inner_impl().for_ { - clean::ResolvedPath { ref path, is_generic: false, .. } | - clean::BorrowedRef { - type_: box clean::ResolvedPath { ref path, is_generic: false, .. }, - .. - } => implementor_dups[path.last_name()].1, - _ => false, - }; - fmt_impl_for_trait_page(&implementor.inner_impl(), w, use_absolute)?; - for it in &implementor.inner_impl().items { - if let clean::TypedefItem(ref tydef, _) = it.inner { - write!(w, " ")?; - assoc_type(w, it, &vec![], Some(&tydef.type_), AssocItemLink::Anchor(None))?; - write!(w, ";")?; - } + if t.auto { + write!(w, "{}", synthetic_impl_header)?; + for implementor in synthetic { + render_implementor(cx, implementor, w, &implementor_dups)?; } - writeln!(w, "
  • ")?; + write!(w, "
")?; } + + write!(w, r#""#, + root_path = vec![".."; cx.current.len()].join("/"), + path = if it.def_id.is_local() { + cx.current.join("/") + } else { + let (ref path, _) = cache.external_paths[&it.def_id]; + path[..path.len() - 1].join("/") + }, + ty = it.type_().css_class(), + name = *it.name.as_ref().unwrap())?; } else { // even without any implementations to write in, we still want the heading and list, so the // implementors javascript file pulled in below has somewhere to write the impls into write!(w, "{}", impl_header)?; + write!(w, "")?; + + write!(w, r#""#)?; + + if t.auto { + write!(w, "{}", synthetic_impl_header)?; + write!(w, "")?; + } } - write!(w, "")?; + write!(w, r#""#, @@ -3075,17 +3159,28 @@ fn render_assoc_items(w: &mut fmt::Formatter, }).is_some(); render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?; } + + let (synthetic, concrete) = traits + .iter() + .partition::, _>(|t| t.inner_impl().synthetic); + write!(w, "

Trait Implementations

+
")?; - for i in &traits { - let did = i.trait_did().unwrap(); - let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); - render_impl(w, cx, i, assoc_link, - RenderMode::Normal, containing_item.stable_since(), true)?; - } + render_impls(cx, w, concrete, containing_item)?; + write!(w, "
")?; + + write!(w, " +

+ Auto Trait Implementations +

+
+ ")?; + render_impls(cx, w, synthetic, containing_item)?; + write!(w, "
")?; } Ok(()) } @@ -3586,32 +3681,48 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { } } } - let mut links = HashSet::new(); - let ret = v.iter() - .filter_map(|i| { - let is_negative_impl = is_negative_impl(i.inner_impl()); - if let Some(ref i) = i.inner_impl().trait_ { - let i_display = format!("{:#}", i); - let out = Escape(&i_display); - let encoded = small_url_encode(&format!("{:#}", i)); - let generated = format!("{}{}", - encoded, - if is_negative_impl { "!" } else { "" }, - out); - if !links.contains(&generated) && links.insert(generated.clone()) { - Some(generated) + let format_impls = |impls: Vec<&Impl>| { + let mut links = HashSet::new(); + impls.iter() + .filter_map(|i| { + let is_negative_impl = is_negative_impl(i.inner_impl()); + if let Some(ref i) = i.inner_impl().trait_ { + let i_display = format!("{:#}", i); + let out = Escape(&i_display); + let encoded = small_url_encode(&format!("{:#}", i)); + let generated = format!("{}{}", + encoded, + if is_negative_impl { "!" } else { "" }, + out); + if links.insert(generated.clone()) { + Some(generated) + } else { + None + } } else { None } - } else { - None - } - }) - .collect::(); - if !ret.is_empty() { + }) + .collect::() + }; + + let (synthetic, concrete) = v + .iter() + .partition::, _>(|i| i.inner_impl().synthetic); + + let concrete_format = format_impls(concrete); + let synthetic_format = format_impls(synthetic); + + if !concrete_format.is_empty() { out.push_str("\ Trait Implementations"); - out.push_str(&format!("
{}
", ret)); + out.push_str(&format!("
{}
", concrete_format)); + } + + if !synthetic_format.is_empty() { + out.push_str("\ + Auto Trait Implementations"); + out.push_str(&format!("
{}
", synthetic_format)); } } } @@ -3734,7 +3845,7 @@ fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item, if let Some(implementors) = c.implementors.get(&it.def_id) { let res = implementors.iter() .filter(|i| i.inner_impl().for_.def_id() - .map_or(false, |d| !c.paths.contains_key(&d))) + .map_or(false, |d| !c.paths.contains_key(&d))) .filter_map(|i| { match extract_for_impl_name(&i.impl_item) { Some((ref name, ref url)) => { @@ -3755,6 +3866,10 @@ fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item, } sidebar.push_str("Implementors"); + if t.auto { + sidebar.push_str("Auto Implementors"); + } sidebar.push_str(&sidebar_assoc_items(it)); @@ -3969,6 +4084,66 @@ fn get_index_type(clean_type: &clean::Type) -> Type { t } +/// Returns a list of all paths used in the type. +/// This is used to help deduplicate imported impls +/// for reexported types. If any of the contained +/// types are re-exported, we don't use the corresponding +/// entry from the js file, as inlining will have already +/// picked up the impl +fn collect_paths_for_type(first_ty: clean::Type) -> Vec { + let mut out = Vec::new(); + let mut visited = FxHashSet(); + let mut work = VecDeque::new(); + let cache = cache(); + + work.push_back(first_ty); + + while let Some(ty) = work.pop_front() { + if !visited.insert(ty.clone()) { + continue; + } + + match ty { + clean::Type::ResolvedPath { did, .. } => { + let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone()); + let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern); + + match fqp { + Some(path) => { + out.push(path.join("::")); + }, + _ => {} + }; + + }, + clean::Type::Tuple(tys) => { + work.extend(tys.into_iter()); + }, + clean::Type::Slice(ty) => { + work.push_back(*ty); + } + clean::Type::Array(ty, _) => { + work.push_back(*ty); + }, + clean::Type::Unique(ty) => { + work.push_back(*ty); + }, + clean::Type::RawPointer(_, ty) => { + work.push_back(*ty); + }, + clean::Type::BorrowedRef { type_, .. } => { + work.push_back(*type_); + }, + clean::Type::QPath { self_type, trait_, .. } => { + work.push_back(*self_type); + work.push_back(*trait_); + }, + _ => {} + } + }; + out +} + fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { match *clean_type { clean::ResolvedPath { ref path, .. } => { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index f688be89bee..5d3f6e84789 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1563,14 +1563,29 @@ window.initSidebarItems = initSidebarItems; window.register_implementors = function(imp) { - var list = document.getElementById('implementors-list'); + var implementors = document.getElementById('implementors-list'); + var synthetic_implementors = document.getElementById('synthetic-implementors-list'); var libs = Object.getOwnPropertyNames(imp); for (var i = 0; i < libs.length; ++i) { if (libs[i] === currentCrate) { continue; } var structs = imp[libs[i]]; for (var j = 0; j < structs.length; ++j) { + var struct = structs[j]; + var list = struct.synthetic ? synthetic_implementors : implementors; + + var bail = false; + for (var k = 0; k < struct.types.length; k++) { + if (window.inlined_types.has(struct.types[k])) { + bail = true; + break; + } + } + if (bail) { + continue; + } + var code = document.createElement('code'); - code.innerHTML = structs[j]; + code.innerHTML = struct.text; var x = code.getElementsByTagName('a'); for (var k = 0; k < x.length; k++) { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 825558648e1..033988fa9d9 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -24,6 +24,7 @@ #![feature(test)] #![feature(unicode)] #![feature(vec_remove_item)] +#![feature(entry_and_modify)] extern crate arena; extern crate getopts; @@ -549,7 +550,8 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { let (mut krate, renderinfo) = core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot, - display_warnings, force_unstable_if_unmarked); + display_warnings, crate_name.clone(), + force_unstable_if_unmarked); info!("finished with rustc"); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 3b882827c61..9dc532953c8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -24,12 +24,12 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::middle::cstore::{LoadedMacro, CrateStore}; use rustc::middle::privacy::AccessLevel; use rustc::ty::Visibility; -use rustc::util::nodemap::FxHashSet; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::hir; use core; -use clean::{self, AttributesExt, NestedAttributesExt}; +use clean::{self, AttributesExt, NestedAttributesExt, def_id_to_path}; use doctree::*; // looks to me like the first two of these are actually @@ -41,7 +41,7 @@ use doctree::*; // framework from syntax? pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { - cstore: &'a CrateStore, + pub cstore: &'a CrateStore, pub module: Module, pub attrs: hir::HirVec, pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, @@ -50,6 +50,7 @@ pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { /// Is the current module and all of its parents public? inside_public_path: bool, reexported_macros: FxHashSet, + exact_paths: Option>> } impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { @@ -66,10 +67,21 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { inlining: false, inside_public_path: true, reexported_macros: FxHashSet(), + exact_paths: Some(FxHashMap()), cstore, } } + fn store_path(&mut self, did: DefId) { + // We can't use the entry api, as that keeps the mutable borrow of self active + // when we try to use cx + let exact_paths = self.exact_paths.as_mut().unwrap(); + if exact_paths.get(&did).is_none() { + let path = def_id_to_path(self.cx, did, self.cx.crate_name.clone()); + exact_paths.insert(did, path); + } + } + fn stability(&self, id: ast::NodeId) -> Option { self.cx.tcx.hir.opt_local_def_id(id) .and_then(|def_id| self.cx.tcx.lookup_stability(def_id)).cloned() @@ -94,6 +106,8 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { krate.exported_macros.iter().map(|def| self.visit_local_macro(def)).collect(); self.module.macros.extend(macro_exports); self.module.is_crate = true; + + self.cx.renderinfo.borrow_mut().exact_paths = self.exact_paths.take().unwrap(); } pub fn visit_variant_data(&mut self, item: &hir::Item, @@ -371,6 +385,12 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { renamed: Option, om: &mut Module) { debug!("Visiting item {:?}", item); let name = renamed.unwrap_or(item.name); + + if item.vis == hir::Public { + let def_id = self.cx.tcx.hir.local_def_id(item.id); + self.store_path(def_id); + } + match item.node { hir::ItemForeignMod(ref fm) => { // If inlining we only want to include public functions. diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs index df6ebcae107..43a425d4c5e 100644 --- a/src/test/rustdoc/duplicate_impls/issue-33054.rs +++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs @@ -11,7 +11,8 @@ // @has issue_33054/impls/struct.Foo.html // @has - '//code' 'impl Foo' // @has - '//code' 'impl Bar for Foo' -// @count - '//*[@class="impl"]' 2 +// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="main"]/*[@class="impl"]' 1 // @has issue_33054/impls/bar/trait.Bar.html // @has - '//code' 'impl Bar for Foo' // @count - '//*[@class="struct"]' 1 diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs index 36f160acf1c..553bbeb0cff 100644 --- a/src/test/rustdoc/issue-21474.rs +++ b/src/test/rustdoc/issue-21474.rs @@ -17,5 +17,5 @@ mod inner { pub trait Blah { } // @count issue_21474/struct.What.html \ -// '//*[@class="impl"]' 1 +// '//*[@id="implementations-list"]/*[@class="impl"]' 1 pub struct What; diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs index 6d6ae3dc94a..b0e64557be2 100644 --- a/src/test/rustdoc/issue-45584.rs +++ b/src/test/rustdoc/issue-45584.rs @@ -14,12 +14,12 @@ pub trait Bar {} // @has 'foo/struct.Foo1.html' pub struct Foo1; -// @count - '//*[@class="impl"]' 1 +// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 // @has - '//*[@class="impl"]' "impl Bar for Foo1" impl Bar for Foo1 {} // @has 'foo/struct.Foo2.html' pub struct Foo2; -// @count - '//*[@class="impl"]' 1 +// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 // @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8" impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs new file mode 100644 index 00000000000..8ff84d11a50 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/basic.rs @@ -0,0 +1,18 @@ +// Copyright 2018 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. + +// @has basic/struct.Foo.html +// @has - '//code' 'impl Send for Foo where T: Send' +// @has - '//code' 'impl Sync for Foo where T: Sync' +// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 2 +pub struct Foo { + field: T, +} diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs new file mode 100644 index 00000000000..896d49ca79a --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/complex.rs @@ -0,0 +1,52 @@ +// Copyright 2018 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. + +mod foo { + pub trait MyTrait<'a> { + type MyItem: ?Sized; + } + + pub struct Inner<'a, Q, R: ?Sized> { + field: Q, + field3: &'a u8, + my_foo: Foo, + field2: R, + } + + pub struct Outer<'a, T, K: ?Sized> { + my_inner: Inner<'a, T, K>, + } + + pub struct Foo { + myfield: T, + } +} + +// @has complex/struct.NotOuter.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<'a, T, K: \ +// ?Sized> Send for NotOuter<'a, T, K> where 'a: 'static, K: for<'b> Fn((&'b bool, &'a u8)) \ +// -> &'b i8, >::MyItem: Copy, T: MyTrait<'a>" + +pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter}; + +unsafe impl Send for Foo +where + T: NotMyTrait<'static>, +{ +} + +unsafe impl<'a, Q, R: ?Sized> Send for NotInner<'a, Q, R> +where + Q: NotMyTrait<'a>, + >::MyItem: Copy, + /* for<'b> */ R: for<'b> Fn((&'b bool, &'a u8)) -> &'b i8, + Foo: Send, +{ +} diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs new file mode 100644 index 00000000000..2f92627f954 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs @@ -0,0 +1,28 @@ +// Copyright 2018 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. +pub struct Inner<'a, T: 'a> { + field: &'a T, +} + +unsafe impl<'a, T> Send for Inner<'a, T> +where + 'a: 'static, + T: for<'b> Fn(&'b bool) -> &'a u8, +{} + +// @has lifetimes/struct.Foo.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<'c, K> Send \ +// for Foo<'c, K> where 'c: 'static, K: for<'b> Fn(&'b bool) -> &'c u8" +// +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<'c, K> Sync \ +// for Foo<'c, K> where K: Sync" +pub struct Foo<'c, K: 'c> { + inner_field: Inner<'c, K>, +} diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs new file mode 100644 index 00000000000..d81e6309dff --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -0,0 +1,24 @@ +// Copyright 2018 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. + +// @has manual/struct.Foo.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' 'impl Sync for \ +// Foo where T: Sync' +// +// @has - '//*[@id="implementations-list"]/*[@class="impl"]/*/code' \ +// 'impl Send for Foo' +// +// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 1 +pub struct Foo { + field: T, +} + +unsafe impl Send for Foo {} diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs new file mode 100644 index 00000000000..ec9cb710f1f --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/negative.rs @@ -0,0 +1,23 @@ +// Copyright 2018 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. + +pub struct Inner { + field: *mut T, +} + +// @has negative/struct.Outer.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl !Send for \ +// Outer" +// +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl \ +// !Sync for Outer" +pub struct Outer { + inner_field: Inner, +} diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs new file mode 100644 index 00000000000..1f33a8b13cb --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/nested.rs @@ -0,0 +1,28 @@ +// Copyright 2018 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. +pub struct Inner { + field: T, +} + +unsafe impl Send for Inner +where + T: Copy, +{ +} + +// @has nested/struct.Foo.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' 'impl Send for \ +// Foo where T: Copy' +// +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' \ +// 'impl Sync for Foo where T: Sync' +pub struct Foo { + inner_field: Inner, +} diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs new file mode 100644 index 00000000000..0b37f2ed317 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs @@ -0,0 +1,26 @@ +// Copyright 2018 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. + +pub struct Inner { + field: T, +} + +unsafe impl Send for Inner +where + T: Copy + Send, +{ +} + +// @has no_redundancy/struct.Outer.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl Send for \ +// Outer where T: Copy + Send" +pub struct Outer { + inner_field: Inner, +} diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs new file mode 100644 index 00000000000..e1b8621ff6d --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/project.rs @@ -0,0 +1,43 @@ +// Copyright 2018 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. + +pub struct Inner<'a, T: 'a> { + field: &'a T, +} + +trait MyTrait { + type MyItem; +} + +trait OtherTrait {} + +unsafe impl<'a, T> Send for Inner<'a, T> +where + 'a: 'static, + T: MyTrait, +{ +} +unsafe impl<'a, T> Sync for Inner<'a, T> +where + 'a: 'static, + T: MyTrait, + ::MyItem: OtherTrait, +{ +} + +// @has project/struct.Foo.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<'c, K> Send \ +// for Foo<'c, K> where 'c: 'static, K: MyTrait" +// +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<'c, K> Sync \ +// for Foo<'c, K> where 'c: 'static, K: MyTrait, ::MyItem: OtherTrait" +pub struct Foo<'c, K: 'c> { + inner_field: Inner<'c, K>, +} -- cgit 1.4.1-3-g733a5 From 713b05f0726b7ee4c45728c01ddb0c40d8ccf0f3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 21 Feb 2018 19:20:09 +0200 Subject: rustc_data_structures: add missing #[inline]. --- src/librustc_data_structures/bitslice.rs | 3 +++ src/librustc_data_structures/indexed_vec.rs | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitslice.rs b/src/librustc_data_structures/bitslice.rs index 7665bfd5b11..2678861be06 100644 --- a/src/librustc_data_structures/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -24,6 +24,7 @@ pub trait BitSlice { impl BitSlice for [Word] { /// Clears bit at `idx` to 0; returns true iff this changed `self.` + #[inline] fn clear_bit(&mut self, idx: usize) -> bool { let words = self; debug!("clear_bit: words={} idx={}", @@ -37,6 +38,7 @@ impl BitSlice for [Word] { } /// Sets bit at `idx` to 1; returns true iff this changed `self.` + #[inline] fn set_bit(&mut self, idx: usize) -> bool { let words = self; debug!("set_bit: words={} idx={}", @@ -50,6 +52,7 @@ impl BitSlice for [Word] { } /// Extracts value of bit at `idx` in `self`. + #[inline] fn get_bit(&self, idx: usize) -> bool { let words = self; let BitLookup { word, bit_mask, .. } = bit_lookup(idx); diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index b11ca107af7..14626f9d5a0 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -29,12 +29,16 @@ pub trait Idx: Copy + 'static + Eq + Debug { } impl Idx for usize { + #[inline] fn new(idx: usize) -> Self { idx } + #[inline] fn index(self) -> usize { self } } impl Idx for u32 { + #[inline] fn new(idx: usize) -> Self { assert!(idx <= u32::MAX as usize); idx as u32 } + #[inline] fn index(self) -> usize { self as usize } } @@ -73,11 +77,13 @@ macro_rules! newtype_index { pub struct $type($($pub)* u32); impl Idx for $type { + #[inline] fn new(value: usize) -> Self { assert!(value < ($max) as usize); $type(value as u32) } + #[inline] fn index(self) -> usize { self.0 as usize } -- cgit 1.4.1-3-g733a5 From e5d79c4bc7c46d8d85a18e71caa02bfb6a3c6df3 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 14 Feb 2018 20:30:49 -0300 Subject: Move word type and word size usage to constants & make it of 128 bits --- src/librustc_data_structures/bitvec.rs | 49 ++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 80cdb0e4417..b565f5ebc7c 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -10,16 +10,19 @@ use std::iter::FromIterator; +type Word = u128; +const WORD_BITS: usize = 128; + /// A very simple BitVector type. #[derive(Clone, Debug, PartialEq)] pub struct BitVector { - data: Vec, + data: Vec, } impl BitVector { #[inline] pub fn new(num_bits: usize) -> BitVector { - let num_words = u64s(num_bits); + let num_words = words(num_bits); BitVector { data: vec![0; num_words] } } @@ -78,7 +81,7 @@ impl BitVector { #[inline] pub fn grow(&mut self, num_bits: usize) { - let num_words = u64s(num_bits); + let num_words = words(num_bits); if self.data.len() < num_words { self.data.resize(num_words, 0) } @@ -96,8 +99,8 @@ impl BitVector { } pub struct BitVectorIter<'a> { - iter: ::std::slice::Iter<'a, u64>, - current: u64, + iter: ::std::slice::Iter<'a, Word>, + current: Word, idx: usize, } @@ -107,10 +110,10 @@ impl<'a> Iterator for BitVectorIter<'a> { while self.current == 0 { self.current = if let Some(&i) = self.iter.next() { if i == 0 { - self.idx += 64; + self.idx += WORD_BITS; continue; } else { - self.idx = u64s(self.idx) * 64; + self.idx = words(self.idx) * WORD_BITS; i } } else { @@ -129,9 +132,9 @@ impl FromIterator for BitVector { fn from_iter(iter: I) -> BitVector where I: IntoIterator { let iter = iter.into_iter(); let (len, _) = iter.size_hint(); - // Make the minimum length for the bitvector 64 bits since that's + // Make the minimum length for the bitvector WORD_BITS bits since that's // the smallest non-zero size anyway. - let len = if len < 64 { 64 } else { len }; + let len = if len < WORD_BITS { WORD_BITS } else { len }; let mut bv = BitVector::new(len); for (idx, val) in iter.enumerate() { if idx > len { @@ -152,26 +155,26 @@ impl FromIterator for BitVector { #[derive(Clone, Debug)] pub struct BitMatrix { columns: usize, - vector: Vec, + vector: Vec, } impl BitMatrix { /// Create a new `rows x columns` matrix, initially empty. pub fn new(rows: usize, columns: usize) -> BitMatrix { // For every element, we need one bit for every other - // element. Round up to an even number of u64s. - let u64s_per_row = u64s(columns); + // element. Round up to an even number of words. + let words_per_row = words(columns); BitMatrix { columns, - vector: vec![0; rows * u64s_per_row], + vector: vec![0; rows * words_per_row], } } /// The range of bits for a given row. fn range(&self, row: usize) -> (usize, usize) { - let u64s_per_row = u64s(self.columns); - let start = row * u64s_per_row; - (start, start + u64s_per_row) + let words_per_row = words(self.columns); + let start = row * words_per_row; + (start, start + words_per_row) } /// Sets the cell at `(row, column)` to true. Put another way, add @@ -208,12 +211,12 @@ impl BitMatrix { let mut result = Vec::with_capacity(self.columns); for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() { let mut v = self.vector[i] & self.vector[j]; - for bit in 0..64 { + for bit in 0..WORD_BITS { if v == 0 { break; } if v & 0x1 != 0 { - result.push(base * 64 + bit); + result.push(base * WORD_BITS + bit); } v >>= 1; } @@ -255,14 +258,14 @@ impl BitMatrix { } #[inline] -fn u64s(elements: usize) -> usize { - (elements + 63) / 64 +fn words(elements: usize) -> usize { + (elements + WORD_BITS - 1) / WORD_BITS } #[inline] -fn word_mask(index: usize) -> (usize, u64) { - let word = index / 64; - let mask = 1 << (index % 64); +fn word_mask(index: usize) -> (usize, Word) { + let word = index / WORD_BITS; + let mask = 1 << (index % WORD_BITS); (word, mask) } -- cgit 1.4.1-3-g733a5 From ff9eb56c6e4bff6c1c74bd628a7e0dd79321829b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 15 Feb 2018 15:47:40 -0300 Subject: Use Sparse bitsets instead of dense ones for NLL results Fixes #48170 --- src/librustc_data_structures/bitvec.rs | 197 +++++++++++++++++++++ src/librustc_data_structures/indexed_vec.rs | 15 ++ .../borrow_check/nll/region_infer/values.rs | 23 +-- 3 files changed, 224 insertions(+), 11 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index b565f5ebc7c..688e9ca9e03 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::BTreeMap; +use std::collections::btree_map::Entry; +use std::marker::PhantomData; use std::iter::FromIterator; +use indexed_vec::{Idx, IndexVec}; type Word = u128; const WORD_BITS: usize = 128; @@ -257,6 +261,199 @@ impl BitMatrix { } } +#[derive(Clone, Debug)] +pub struct SparseBitMatrix where R: Idx, C: Idx { + vector: IndexVec>, +} + +impl SparseBitMatrix { + /// Create a new `rows x columns` matrix, initially empty. + pub fn new(rows: R, _columns: C) -> SparseBitMatrix { + SparseBitMatrix { + vector: IndexVec::from_elem_n(SparseBitSet::new(), rows.index()), + } + } + + /// Sets the cell at `(row, column)` to true. Put another way, insert + /// `column` to the bitset for `row`. + /// + /// Returns true if this changed the matrix, and false otherwise. + pub fn add(&mut self, row: R, column: C) -> bool { + self.vector[row].insert(column) + } + + /// Do the bits from `row` contain `column`? Put another way, is + /// the matrix cell at `(row, column)` true? Put yet another way, + /// if the matrix represents (transitive) reachability, can + /// `row` reach `column`? + pub fn contains(&self, row: R, column: C) -> bool { + self.vector[row].contains(column) + } + + /// Add the bits from row `read` to the bits from row `write`, + /// return true if anything changed. + /// + /// This is used when computing transitive reachability because if + /// you have an edge `write -> read`, because in that case + /// `write` can reach everything that `read` can (and + /// potentially more). + pub fn merge(&mut self, read: R, write: R) -> bool { + let mut changed = false; + + if read != write { + let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write); + + for read_val in bit_set_read.iter() { + changed = changed | bit_set_write.insert(read_val); + } + } + + changed + } + + /// Iterates through all the columns set to true in a given row of + /// the matrix. + pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { + self.vector[row].iter() + } +} + +#[derive(Clone, Debug)] +pub struct SparseBitSet { + chunk_bits: BTreeMap, + _marker: PhantomData, +} + +#[derive(Copy, Clone)] +pub struct SparseChunk { + key: u32, + bits: Word, + _marker: PhantomData, +} + +impl SparseChunk { + pub fn one(index: I) -> Self { + let index = index.index(); + let key_usize = index / 128; + let key = key_usize as u32; + assert_eq!(key as usize, key_usize); + SparseChunk { + key, + bits: 1 << (index % 128), + _marker: PhantomData + } + } + + pub fn any(&self) -> bool { + self.bits != 0 + } + + pub fn iter(&self) -> impl Iterator { + let base = self.key as usize * 128; + let mut bits = self.bits; + (0..128).map(move |i| { + let current_bits = bits; + bits >>= 1; + (i, current_bits) + }).take_while(|&(_, bits)| bits != 0) + .filter_map(move |(i, bits)| { + if (bits & 1) != 0 { + Some(I::new(base + i)) + } else { + None + } + }) + } +} + +impl SparseBitSet { + pub fn new() -> Self { + SparseBitSet { + chunk_bits: BTreeMap::new(), + _marker: PhantomData + } + } + + pub fn capacity(&self) -> usize { + self.chunk_bits.len() * 128 + } + + pub fn contains_chunk(&self, chunk: SparseChunk) -> SparseChunk { + SparseChunk { + bits: self.chunk_bits.get(&chunk.key).map_or(0, |bits| bits & chunk.bits), + ..chunk + } + } + + pub fn insert_chunk(&mut self, chunk: SparseChunk) -> SparseChunk { + if chunk.bits == 0 { + return chunk; + } + let bits = self.chunk_bits.entry(chunk.key).or_insert(0); + let old_bits = *bits; + let new_bits = old_bits | chunk.bits; + *bits = new_bits; + let changed = new_bits ^ old_bits; + SparseChunk { + bits: changed, + ..chunk + } + } + + pub fn remove_chunk(&mut self, chunk: SparseChunk) -> SparseChunk { + if chunk.bits == 0 { + return chunk; + } + let changed = match self.chunk_bits.entry(chunk.key) { + Entry::Occupied(mut bits) => { + let old_bits = *bits.get(); + let new_bits = old_bits & !chunk.bits; + if new_bits == 0 { + bits.remove(); + } else { + bits.insert(new_bits); + } + new_bits ^ old_bits + } + Entry::Vacant(_) => 0 + }; + SparseChunk { + bits: changed, + ..chunk + } + } + + pub fn clear(&mut self) { + self.chunk_bits.clear(); + } + + pub fn chunks<'a>(&'a self) -> impl Iterator> + 'a { + self.chunk_bits.iter().map(|(&key, &bits)| { + SparseChunk { + key, + bits, + _marker: PhantomData + } + }) + } + + pub fn contains(&self, index: I) -> bool { + self.contains_chunk(SparseChunk::one(index)).any() + } + + pub fn insert(&mut self, index: I) -> bool { + self.insert_chunk(SparseChunk::one(index)).any() + } + + pub fn remove(&mut self, index: I) -> bool { + self.remove_chunk(SparseChunk::one(index)).any() + } + + pub fn iter<'a>(&'a self) -> impl Iterator + 'a { + self.chunks().flat_map(|chunk| chunk.iter()) + } +} + #[inline] fn words(elements: usize) -> usize { (elements + WORD_BITS - 1) / WORD_BITS diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index b11ca107af7..3e94b3f4d30 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -482,6 +482,21 @@ impl IndexVec { pub fn get_mut(&mut self, index: I) -> Option<&mut T> { self.raw.get_mut(index.index()) } + + /// Return mutable references to two distinct elements, a and b. Panics if a == b. + #[inline] + pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) { + let (ai, bi) = (a.index(), b.index()); + assert!(ai != bi); + + if ai < bi { + let (c1, c2) = self.raw.split_at_mut(bi); + (&mut c1[ai], &mut c2[0]) + } else { + let (c2, c1) = self.pick2_mut(b, a); + (c1, c2) + } + } } impl IndexVec { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 45236bbc4aa..be3d02be876 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::rc::Rc; -use rustc_data_structures::bitvec::BitMatrix; +use rustc_data_structures::bitvec::SparseBitMatrix; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; @@ -132,7 +132,7 @@ impl RegionValueElements { } /// A newtype for the integers that represent one of the possible -/// elements in a region. These are the rows in the `BitMatrix` that +/// elements in a region. These are the rows in the `SparseBitMatrix` that /// is used to store the values of all regions. They have the following /// convention: /// @@ -184,18 +184,18 @@ impl ToElementIndex for RegionElementIndex { } /// Stores the values for a set of regions. These are stored in a -/// compact `BitMatrix` representation, with one row per region +/// compact `SparseBitMatrix` representation, with one row per region /// variable. The columns consist of either universal regions or /// points in the CFG. #[derive(Clone)] pub(super) struct RegionValues { elements: Rc, - matrix: BitMatrix, + matrix: SparseBitMatrix, /// If cause tracking is enabled, maps from a pair (r, e) /// consisting of a region `r` that contains some element `e` to /// the reason that the element is contained. There should be an - /// entry for every bit set to 1 in `BitMatrix`. + /// entry for every bit set to 1 in `SparseBitMatrix`. causes: Option, } @@ -214,7 +214,8 @@ impl RegionValues { Self { elements: elements.clone(), - matrix: BitMatrix::new(num_region_variables, elements.num_elements()), + matrix: SparseBitMatrix::new(RegionVid::new(num_region_variables), + RegionElementIndex::new(elements.num_elements())), causes: if track_causes.0 { Some(CauseMap::default()) } else { @@ -238,7 +239,7 @@ impl RegionValues { where F: FnOnce(&CauseMap) -> Cause, { - if self.matrix.add(r.index(), i.index()) { + if self.matrix.add(r, i) { debug!("add(r={:?}, i={:?})", r, self.elements.to_element(i)); if let Some(causes) = &mut self.causes { @@ -289,7 +290,7 @@ impl RegionValues { constraint_location: Location, constraint_span: Span, ) -> bool { - // We could optimize this by improving `BitMatrix::merge` so + // We could optimize this by improving `SparseBitMatrix::merge` so // it does not always merge an entire row. That would // complicate causal tracking though. debug!( @@ -315,7 +316,7 @@ impl RegionValues { /// True if the region `r` contains the given element. pub(super) fn contains(&self, r: RegionVid, elem: E) -> bool { let i = self.elements.index(elem); - self.matrix.contains(r.index(), i.index()) + self.matrix.contains(r, i) } /// Iterate over the value of the region `r`, yielding up element @@ -326,8 +327,8 @@ impl RegionValues { r: RegionVid, ) -> impl Iterator + 'a { self.matrix - .iter(r.index()) - .map(move |i| RegionElementIndex::new(i)) + .iter(r) + .map(move |i| i) } /// Returns just the universal regions that are contained in a given region's value. -- cgit 1.4.1-3-g733a5 From aa3409c898b2418c927f3db1743a777fa05bb514 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 15 Feb 2018 19:35:11 -0300 Subject: Fix typo otherwies -> otherwise --- src/librustc_data_structures/bitvec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 688e9ca9e03..e13ccbbd89c 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -184,7 +184,7 @@ impl BitMatrix { /// Sets the cell at `(row, column)` to true. Put another way, add /// `column` to the bitset for `row`. /// - /// Returns true if this changed the matrix, and false otherwies. + /// Returns true if this changed the matrix, and false otherwise. pub fn add(&mut self, row: usize, column: usize) -> bool { let (start, _) = self.range(row); let (word, mask) = word_mask(column); -- cgit 1.4.1-3-g733a5 From 6a74615fe3c81fe5cdbf02f9d4c19e235fab556c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 22 Feb 2018 15:53:54 -0300 Subject: Run rustfmt over bitvec.rs and region_infer/values.rs --- src/librustc_data_structures/bitvec.rs | 76 +++++++++++++--------- .../borrow_check/nll/region_infer/values.rs | 22 +++---- 2 files changed, 52 insertions(+), 46 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index e13ccbbd89c..54565afa4c6 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -27,7 +27,9 @@ impl BitVector { #[inline] pub fn new(num_bits: usize) -> BitVector { let num_words = words(num_bits); - BitVector { data: vec![0; num_words] } + BitVector { + data: vec![0; num_words], + } } #[inline] @@ -133,7 +135,10 @@ impl<'a> Iterator for BitVectorIter<'a> { } impl FromIterator for BitVector { - fn from_iter(iter: I) -> BitVector where I: IntoIterator { + fn from_iter(iter: I) -> BitVector + where + I: IntoIterator, + { let iter = iter.into_iter(); let (len, _) = iter.size_hint(); // Make the minimum length for the bitvector WORD_BITS bits since that's @@ -262,7 +267,11 @@ impl BitMatrix { } #[derive(Clone, Debug)] -pub struct SparseBitMatrix where R: Idx, C: Idx { +pub struct SparseBitMatrix +where + R: Idx, + C: Idx, +{ vector: IndexVec>, } @@ -340,7 +349,7 @@ impl SparseChunk { SparseChunk { key, bits: 1 << (index % 128), - _marker: PhantomData + _marker: PhantomData, } } @@ -351,18 +360,20 @@ impl SparseChunk { pub fn iter(&self) -> impl Iterator { let base = self.key as usize * 128; let mut bits = self.bits; - (0..128).map(move |i| { - let current_bits = bits; - bits >>= 1; - (i, current_bits) - }).take_while(|&(_, bits)| bits != 0) - .filter_map(move |(i, bits)| { - if (bits & 1) != 0 { - Some(I::new(base + i)) - } else { - None - } - }) + (0..128) + .map(move |i| { + let current_bits = bits; + bits >>= 1; + (i, current_bits) + }) + .take_while(|&(_, bits)| bits != 0) + .filter_map(move |(i, bits)| { + if (bits & 1) != 0 { + Some(I::new(base + i)) + } else { + None + } + }) } } @@ -370,7 +381,7 @@ impl SparseBitSet { pub fn new() -> Self { SparseBitSet { chunk_bits: BTreeMap::new(), - _marker: PhantomData + _marker: PhantomData, } } @@ -380,7 +391,9 @@ impl SparseBitSet { pub fn contains_chunk(&self, chunk: SparseChunk) -> SparseChunk { SparseChunk { - bits: self.chunk_bits.get(&chunk.key).map_or(0, |bits| bits & chunk.bits), + bits: self.chunk_bits + .get(&chunk.key) + .map_or(0, |bits| bits & chunk.bits), ..chunk } } @@ -415,7 +428,7 @@ impl SparseBitSet { } new_bits ^ old_bits } - Entry::Vacant(_) => 0 + Entry::Vacant(_) => 0, }; SparseChunk { bits: changed, @@ -428,12 +441,10 @@ impl SparseBitSet { } pub fn chunks<'a>(&'a self) -> impl Iterator> + 'a { - self.chunk_bits.iter().map(|(&key, &bits)| { - SparseChunk { - key, - bits, - _marker: PhantomData - } + self.chunk_bits.iter().map(|(&key, &bits)| SparseChunk { + key, + bits, + _marker: PhantomData, }) } @@ -478,11 +489,12 @@ fn bitvec_iter_works() { bitvec.insert(65); bitvec.insert(66); bitvec.insert(99); - assert_eq!(bitvec.iter().collect::>(), - [1, 10, 19, 62, 63, 64, 65, 66, 99]); + assert_eq!( + bitvec.iter().collect::>(), + [1, 10, 19, 62, 63, 64, 65, 66, 99] + ); } - #[test] fn bitvec_iter_works_2() { let mut bitvec = BitVector::new(319); @@ -514,24 +526,24 @@ fn union_two_vecs() { #[test] fn grow() { let mut vec1 = BitVector::new(65); - for index in 0 .. 65 { + for index in 0..65 { assert!(vec1.insert(index)); assert!(!vec1.insert(index)); } vec1.grow(128); // Check if the bits set before growing are still set - for index in 0 .. 65 { + for index in 0..65 { assert!(vec1.contains(index)); } // Check if the new bits are all un-set - for index in 65 .. 128 { + for index in 65..128 { assert!(!vec1.contains(index)); } // Check that we can set all new bits without running out of bounds - for index in 65 .. 128 { + for index in 65..128 { assert!(vec1.insert(index)); assert!(!vec1.insert(index)); } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index be3d02be876..e6f2a43bfc8 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -69,9 +69,7 @@ impl RegionValueElements { /// Iterates over the `RegionElementIndex` for all points in the CFG. pub(super) fn all_point_indices<'a>(&'a self) -> impl Iterator + 'a { - (0..self.num_points).map(move |i| { - RegionElementIndex::new(i + self.num_universal_regions) - }) + (0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions)) } /// Iterates over the `RegionElementIndex` for all points in the CFG. @@ -154,7 +152,6 @@ pub(super) enum RegionElement { UniversalRegion(RegionVid), } - pub(super) trait ToElementIndex { fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex; } @@ -214,8 +211,10 @@ impl RegionValues { Self { elements: elements.clone(), - matrix: SparseBitMatrix::new(RegionVid::new(num_region_variables), - RegionElementIndex::new(elements.num_elements())), + matrix: SparseBitMatrix::new( + RegionVid::new(num_region_variables), + RegionElementIndex::new(elements.num_elements()), + ), causes: if track_causes.0 { Some(CauseMap::default()) } else { @@ -295,8 +294,7 @@ impl RegionValues { // complicate causal tracking though. debug!( "add_universal_regions_outlived_by(from_region={:?}, to_region={:?})", - from_region, - to_region + from_region, to_region ); let mut changed = false; for elem in self.elements.all_universal_region_indices() { @@ -326,9 +324,7 @@ impl RegionValues { &'a self, r: RegionVid, ) -> impl Iterator + 'a { - self.matrix - .iter(r) - .map(move |i| i) + self.matrix.iter(r).map(move |i| i) } /// Returns just the universal regions that are contained in a given region's value. @@ -416,9 +412,7 @@ impl RegionValues { assert_eq!(location1.block, location2.block); str.push_str(&format!( "{:?}[{}..={}]", - location1.block, - location1.statement_index, - location2.statement_index + location1.block, location1.statement_index, location2.statement_index )); } } -- cgit 1.4.1-3-g733a5 From 89e55d108c5c6d5f29c4eb0cb829e47bccb8598b Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Sun, 3 Dec 2017 14:24:14 +0100 Subject: Make TransitiveRelation thread safe. Avoid locking by using get_mut in some cases. --- src/librustc_data_structures/transitive_relation.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index ba7ab0c07c6..6d63bc4436f 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -10,16 +10,16 @@ use bitvec::BitMatrix; use fx::FxHashMap; +use sync::Lock; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use stable_hasher::{HashStable, StableHasher, StableHasherResult}; -use std::cell::RefCell; use std::fmt::Debug; use std::hash::Hash; use std::mem; #[derive(Clone, Debug)] -pub struct TransitiveRelation { +pub struct TransitiveRelation { // List of elements. This is used to map from a T to a usize. elements: Vec, @@ -32,14 +32,14 @@ pub struct TransitiveRelation { // This is a cached transitive closure derived from the edges. // Currently, we build it lazilly and just throw out any existing - // copy whenever a new edge is added. (The RefCell is to permit + // copy whenever a new edge is added. (The Lock is to permit // the lazy computation.) This is kind of silly, except for the // fact its size is tied to `self.elements.len()`, so I wanted to // wait before building it up to avoid reallocating as new edges // are added with new elements. Perhaps better would be to ask the // user for a batch of edges to minimize this effect, but I // already wrote the code this way. :P -nmatsakis - closure: RefCell>, + closure: Lock>, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)] @@ -51,13 +51,13 @@ struct Edge { target: Index, } -impl TransitiveRelation { +impl TransitiveRelation { pub fn new() -> TransitiveRelation { TransitiveRelation { elements: vec![], map: FxHashMap(), edges: vec![], - closure: RefCell::new(None), + closure: Lock::new(None), } } @@ -72,7 +72,7 @@ impl TransitiveRelation { fn add_index(&mut self, a: T) -> Index { let &mut TransitiveRelation { ref mut elements, - ref closure, + ref mut closure, ref mut map, .. } = self; @@ -82,7 +82,7 @@ impl TransitiveRelation { elements.push(a); // if we changed the dimensions, clear the cache - *closure.borrow_mut() = None; + *closure.get_mut() = None; Index(elements.len() - 1) }) @@ -122,7 +122,7 @@ impl TransitiveRelation { self.edges.push(edge); // added an edge, clear the cache - *self.closure.borrow_mut() = None; + *self.closure.get_mut() = None; } } @@ -443,7 +443,7 @@ impl Decodable for TransitiveRelation .enumerate() .map(|(index, elem)| (elem.clone(), Index(index))) .collect(); - Ok(TransitiveRelation { elements, edges, map, closure: RefCell::new(None) }) + Ok(TransitiveRelation { elements, edges, map, closure: Lock::new(None) }) }) } } -- cgit 1.4.1-3-g733a5 From c7953bb6d67dead45033434161be2ed8cdd6cd31 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 16 Jul 2017 07:07:51 -0400 Subject: obtain `UnificationTable` and `snapshot_vec` from `ena` instead The ena version has an improved interface. I suspect `librustc_data_structures` should start migrating out to crates.io in general. --- src/librustc/infer/combine.rs | 8 ++-- src/librustc/infer/freshen.rs | 4 +- src/librustc/infer/mod.rs | 65 ++++++++++++++++++--------------- src/librustc/infer/type_variable.rs | 15 ++++++-- src/librustc/infer/unify_key.rs | 44 +++++++++++----------- src/librustc/ty/mod.rs | 5 ++- src/librustc/util/ppaux.rs | 6 +++ src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/lib.rs | 5 ++- 9 files changed, 88 insertions(+), 65 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index bd175c510fb..8997e7d99da 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -132,7 +132,7 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { { self.int_unification_table .borrow_mut() - .unify_var_value(vid, val) + .unify_var_value(vid, Some(val)) .map_err(|e| int_unification_error(vid_is_expected, e))?; match val { IntType(v) => Ok(self.tcx.mk_mach_int(v)), @@ -148,7 +148,7 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { { self.float_unification_table .borrow_mut() - .unify_var_value(vid, val) + .unify_var_value(vid, Some(ty::FloatVarValue(val))) .map_err(|e| float_unification_error(vid_is_expected, e))?; Ok(self.tcx.mk_mach_float(val)) } @@ -518,9 +518,9 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int } fn float_unification_error<'tcx>(a_is_expected: bool, - v: (ast::FloatTy, ast::FloatTy)) + v: (ty::FloatVarValue, ty::FloatVarValue)) -> TypeError<'tcx> { - let (a, b) = v; + let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 8b61fcff233..25300eed548 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -143,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyInfer(ty::IntVar(v)) => { self.freshen( self.infcx.int_unification_table.borrow_mut() - .probe(v) + .probe_value(v) .map(|v| v.to_type(tcx)), ty::IntVar(v), ty::FreshIntTy) @@ -152,7 +152,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyInfer(ty::FloatVar(v)) => { self.freshen( self.infcx.float_unification_table.borrow_mut() - .probe(v) + .probe_value(v) .map(|v| v.to_type(tcx)), ty::FloatVar(v), ty::FreshFloatTy) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 42928457925..72a4dfbb7e0 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -29,7 +29,7 @@ use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations, Reveal}; -use rustc_data_structures::unify::{self, UnificationTable}; +use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::collections::BTreeMap; use std::fmt; @@ -99,10 +99,10 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub type_variables: RefCell>, // Map from integral variable to the kind of integer it represents - int_unification_table: RefCell>, + int_unification_table: RefCell>>, // Map from floating variable to the kind of float it represents - float_unification_table: RefCell>, + float_unification_table: RefCell>>, // Tracks the set of region variables and the constraints between // them. This is initially `Some(_)` but when @@ -441,8 +441,8 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { in_progress_tables, projection_cache: RefCell::new(traits::ProjectionCache::new()), type_variables: RefCell::new(type_variable::TypeVariableTable::new()), - int_unification_table: RefCell::new(UnificationTable::new()), - float_unification_table: RefCell::new(UnificationTable::new()), + int_unification_table: RefCell::new(ut::UnificationTable::new()), + float_unification_table: RefCell::new(ut::UnificationTable::new()), region_constraints: RefCell::new(Some(RegionConstraintCollector::new())), lexical_region_resolutions: RefCell::new(None), selection_cache: traits::SelectionCache::new(), @@ -476,8 +476,8 @@ impl<'tcx, T> InferOk<'tcx, T> { pub struct CombinedSnapshot<'a, 'tcx:'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, type_snapshot: type_variable::Snapshot, - int_snapshot: unify::Snapshot, - float_snapshot: unify::Snapshot, + int_snapshot: ut::Snapshot>, + float_snapshot: ut::Snapshot>, region_constraints_snapshot: RegionSnapshot, region_obligations_snapshot: usize, was_in_snapshot: bool, @@ -678,14 +678,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { use ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; match ty.sty { ty::TyInfer(ty::IntVar(vid)) => { - if self.int_unification_table.borrow_mut().has_value(vid) { + if self.int_unification_table.borrow_mut().probe_value(vid).is_some() { Neither } else { UnconstrainedInt } }, ty::TyInfer(ty::FloatVar(vid)) => { - if self.float_unification_table.borrow_mut().has_value(vid) { + if self.float_unification_table.borrow_mut().probe_value(vid).is_some() { Neither } else { UnconstrainedFloat @@ -698,27 +698,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn unsolved_variables(&self) -> Vec> { let mut variables = Vec::new(); - let unbound_ty_vars = self.type_variables - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|t| self.tcx.mk_var(t)); - - let unbound_int_vars = self.int_unification_table - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|v| self.tcx.mk_int_var(v)); + { + let mut type_variables = self.type_variables.borrow_mut(); + variables.extend( + type_variables + .unsolved_variables() + .into_iter() + .map(|t| self.tcx.mk_var(t))); + } - let unbound_float_vars = self.float_unification_table - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|v| self.tcx.mk_float_var(v)); + { + let mut int_unification_table = self.int_unification_table.borrow_mut(); + variables.extend( + (0..int_unification_table.len()) + .map(|i| ty::IntVid { index: i as u32 }) + .filter(|&vid| int_unification_table.probe_value(vid).is_none()) + .map(|v| self.tcx.mk_int_var(v))); + } - variables.extend(unbound_ty_vars); - variables.extend(unbound_int_vars); - variables.extend(unbound_float_vars); + { + let mut float_unification_table = self.float_unification_table.borrow_mut(); + variables.extend( + (0..float_unification_table.len()) + .map(|i| ty::FloatVid { index: i as u32 }) + .filter(|&vid| float_unification_table.probe_value(vid).is_none()) + .map(|v| self.tcx.mk_float_var(v))); + } return variables; } @@ -1262,7 +1267,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyInfer(ty::IntVar(v)) => { self.int_unification_table .borrow_mut() - .probe(v) + .probe_value(v) .map(|v| v.to_type(self.tcx)) .unwrap_or(typ) } @@ -1270,7 +1275,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyInfer(ty::FloatVar(v)) => { self.float_unification_table .borrow_mut() - .probe(v) + .probe_value(v) .map(|v| v.to_type(self.tcx)) .unwrap_or(typ) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index e07cc92ec21..423b18823b1 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -26,7 +26,7 @@ pub struct TypeVariableTable<'tcx> { /// Two variables are unified in `eq_relations` when we have a /// constraint `?X == ?Y`. - eq_relations: ut::UnificationTable, + eq_relations: ut::UnificationTable>, /// Two variables are unified in `eq_relations` when we have a /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second @@ -45,7 +45,7 @@ pub struct TypeVariableTable<'tcx> { /// This is reasonable because, in Rust, subtypes have the same /// "skeleton" and hence there is no possible type such that /// (e.g.) `Box <: ?3` for any `?3`. - sub_relations: ut::UnificationTable, + sub_relations: ut::UnificationTable>, } /// Reasons to create a type inference variable @@ -86,8 +86,8 @@ enum TypeVariableValue<'tcx> { pub struct Snapshot { snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot, - sub_snapshot: ut::Snapshot, + eq_snapshot: ut::Snapshot>, + sub_snapshot: ut::Snapshot>, } struct Instantiate { @@ -354,3 +354,10 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { values[vid.index as usize].value = Unknown; } } + +impl ut::UnifyKey for ty::TyVid { + type Value = (); + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } } + fn tag() -> &'static str { "TyVid" } +} diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index 99b11794cc5..a1145572b79 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::ast; -use ty::{self, IntVarValue, Ty, TyCtxt}; -use rustc_data_structures::unify::{Combine, UnifyKey}; +use ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt}; +use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue}; pub trait ToType { fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>; @@ -20,7 +19,10 @@ impl UnifyKey for ty::IntVid { type Value = Option; fn index(&self) -> u32 { self.index } fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } - fn tag(_: Option) -> &'static str { "IntVid" } + fn tag() -> &'static str { "IntVid" } +} + +impl EqUnifyValue for IntVarValue { } #[derive(PartialEq, Copy, Clone, Debug)] @@ -31,15 +33,17 @@ pub struct RegionVidKey { pub min_vid: ty::RegionVid } -impl Combine for RegionVidKey { - fn combine(&self, other: &RegionVidKey) -> RegionVidKey { - let min_vid = if self.min_vid.index() < other.min_vid.index() { - self.min_vid +impl UnifyValue for RegionVidKey { + type Error = NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result { + let min_vid = if value1.min_vid.index() < value2.min_vid.index() { + value1.min_vid } else { - other.min_vid + value2.min_vid }; - RegionVidKey { min_vid: min_vid } + Ok(RegionVidKey { min_vid: min_vid }) } } @@ -47,7 +51,7 @@ impl UnifyKey for ty::RegionVid { type Value = RegionVidKey; fn index(&self) -> u32 { self.0 } fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid(i) } - fn tag(_: Option) -> &'static str { "RegionVid" } + fn tag() -> &'static str { "RegionVid" } } impl ToType for IntVarValue { @@ -62,21 +66,17 @@ impl ToType for IntVarValue { // Floating point type keys impl UnifyKey for ty::FloatVid { - type Value = Option; + type Value = Option; fn index(&self) -> u32 { self.index } fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } - fn tag(_: Option) -> &'static str { "FloatVid" } + fn tag() -> &'static str { "FloatVid" } } -impl ToType for ast::FloatTy { - fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - tcx.mk_mach_float(*self) - } +impl EqUnifyValue for FloatVarValue { } -impl UnifyKey for ty::TyVid { - type Value = (); - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } } - fn tag(_: Option) -> &'static str { "TyVid" } +impl ToType for FloatVarValue { + fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + tcx.mk_mach_float(self.0) + } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 856c53d19c9..4315d1f2c8c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -685,12 +685,15 @@ pub struct ClosureUpvar<'tcx> { pub ty: Ty<'tcx>, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum IntVarValue { IntType(ast::IntTy), UintType(ast::UintTy), } +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct FloatVarValue(pub ast::FloatTy); + #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct TypeParameterDef { pub name: Name, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 37d1c568515..d390d1c15e2 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -916,6 +916,12 @@ impl fmt::Debug for ty::IntVarValue { } } +impl fmt::Debug for ty::FloatVarValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + // The generic impl doesn't work yet because projections are not // normalized under HRTB. /*impl fmt::Display for ty::Binder diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 23e42f6a672..40d557ee5e0 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,6 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] +ena = "0.8.0" log = "0.4" serialize = { path = "../libserialize" } cfg-if = "0.1.2" diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 33d760d0a14..265c6485830 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -39,6 +39,7 @@ #![cfg_attr(test, feature(test))] extern crate core; +extern crate ena; #[macro_use] extern crate log; extern crate serialize as rustc_serialize; // used by deriving @@ -63,10 +64,10 @@ pub mod indexed_vec; pub mod obligation_forest; pub mod sip128; pub mod snapshot_map; -pub mod snapshot_vec; +pub use ena::snapshot_vec; pub mod stable_hasher; pub mod transitive_relation; -pub mod unify; +pub use ena::unify; pub mod fx; pub mod tuple_slice; pub mod control_flow_graph; -- cgit 1.4.1-3-g733a5 From c30183873e2be5a23021adce01bacc901ccfff63 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 29 Jan 2018 13:46:52 -0700 Subject: Remove dead code These modules were replaced with re-exports from ena --- src/librustc_data_structures/snapshot_vec.rs | 230 ----------------- src/librustc_data_structures/unify/mod.rs | 363 --------------------------- src/librustc_data_structures/unify/tests.rs | 205 --------------- 3 files changed, 798 deletions(-) delete mode 100644 src/librustc_data_structures/snapshot_vec.rs delete mode 100644 src/librustc_data_structures/unify/mod.rs delete mode 100644 src/librustc_data_structures/unify/tests.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/snapshot_vec.rs b/src/librustc_data_structures/snapshot_vec.rs deleted file mode 100644 index 2da91918288..00000000000 --- a/src/librustc_data_structures/snapshot_vec.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A utility class for implementing "snapshottable" things; a snapshottable data structure permits -//! you to take a snapshot (via `start_snapshot`) and then, after making some changes, elect either -//! to rollback to the start of the snapshot or commit those changes. -//! -//! This vector is intended to be used as part of an abstraction, not serve as a complete -//! abstraction on its own. As such, while it will roll back most changes on its own, it also -//! supports a `get_mut` operation that gives you an arbitrary mutable pointer into the vector. To -//! ensure that any changes you make this with this pointer are rolled back, you must invoke -//! `record` to record any changes you make and also supplying a delegate capable of reversing -//! those changes. -use self::UndoLog::*; - -use std::mem; -use std::ops; - -pub enum UndoLog { - /// Indicates where a snapshot started. - OpenSnapshot, - - /// Indicates a snapshot that has been committed. - CommittedSnapshot, - - /// New variable with given index was created. - NewElem(usize), - - /// Variable with given index was changed *from* the given value. - SetElem(usize, D::Value), - - /// Extensible set of actions - Other(D::Undo), -} - -pub struct SnapshotVec { - values: Vec, - undo_log: Vec>, -} - -// Snapshots are tokens that should be created/consumed linearly. -pub struct Snapshot { - // Length of the undo log at the time the snapshot was taken. - length: usize, -} - -pub trait SnapshotVecDelegate { - type Value; - type Undo; - - fn reverse(values: &mut Vec, action: Self::Undo); -} - -impl SnapshotVec { - pub fn new() -> SnapshotVec { - SnapshotVec { - values: Vec::new(), - undo_log: Vec::new(), - } - } - - pub fn with_capacity(n: usize) -> SnapshotVec { - SnapshotVec { - values: Vec::with_capacity(n), - undo_log: Vec::new(), - } - } - - fn in_snapshot(&self) -> bool { - !self.undo_log.is_empty() - } - - pub fn record(&mut self, action: D::Undo) { - if self.in_snapshot() { - self.undo_log.push(Other(action)); - } - } - - pub fn len(&self) -> usize { - self.values.len() - } - - pub fn push(&mut self, elem: D::Value) -> usize { - let len = self.values.len(); - self.values.push(elem); - - if self.in_snapshot() { - self.undo_log.push(NewElem(len)); - } - - len - } - - pub fn get(&self, index: usize) -> &D::Value { - &self.values[index] - } - - /// Returns a mutable pointer into the vec; whatever changes you make here cannot be undone - /// automatically, so you should be sure call `record()` with some sort of suitable undo - /// action. - pub fn get_mut(&mut self, index: usize) -> &mut D::Value { - &mut self.values[index] - } - - /// Updates the element at the given index. The old value will saved (and perhaps restored) if - /// a snapshot is active. - pub fn set(&mut self, index: usize, new_elem: D::Value) { - let old_elem = mem::replace(&mut self.values[index], new_elem); - if self.in_snapshot() { - self.undo_log.push(SetElem(index, old_elem)); - } - } - - pub fn start_snapshot(&mut self) -> Snapshot { - let length = self.undo_log.len(); - self.undo_log.push(OpenSnapshot); - Snapshot { length: length } - } - - pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog] { - &self.undo_log[snapshot.length..] - } - - fn assert_open_snapshot(&self, snapshot: &Snapshot) { - // Or else there was a failure to follow a stack discipline: - assert!(self.undo_log.len() > snapshot.length); - - // Invariant established by start_snapshot(): - assert!(match self.undo_log[snapshot.length] { - OpenSnapshot => true, - _ => false, - }); - } - - pub fn rollback_to(&mut self, snapshot: Snapshot) { - debug!("rollback_to({})", snapshot.length); - - self.assert_open_snapshot(&snapshot); - - while self.undo_log.len() > snapshot.length + 1 { - match self.undo_log.pop().unwrap() { - OpenSnapshot => { - // This indicates a failure to obey the stack discipline. - panic!("Cannot rollback an uncommitted snapshot"); - } - - CommittedSnapshot => { - // This occurs when there are nested snapshots and - // the inner is committed but outer is rolled back. - } - - NewElem(i) => { - self.values.pop(); - assert!(self.values.len() == i); - } - - SetElem(i, v) => { - self.values[i] = v; - } - - Other(u) => { - D::reverse(&mut self.values, u); - } - } - } - - let v = self.undo_log.pop().unwrap(); - assert!(match v { - OpenSnapshot => true, - _ => false, - }); - assert!(self.undo_log.len() == snapshot.length); - } - - /// Commits all changes since the last snapshot. Of course, they - /// can still be undone if there is a snapshot further out. - pub fn commit(&mut self, snapshot: Snapshot) { - debug!("commit({})", snapshot.length); - - self.assert_open_snapshot(&snapshot); - - if snapshot.length == 0 { - // The root snapshot. - self.undo_log.truncate(0); - } else { - self.undo_log[snapshot.length] = CommittedSnapshot; - } - } -} - -impl ops::Deref for SnapshotVec { - type Target = [D::Value]; - fn deref(&self) -> &[D::Value] { - &*self.values - } -} - -impl ops::DerefMut for SnapshotVec { - fn deref_mut(&mut self) -> &mut [D::Value] { - &mut *self.values - } -} - -impl ops::Index for SnapshotVec { - type Output = D::Value; - fn index(&self, index: usize) -> &D::Value { - self.get(index) - } -} - -impl ops::IndexMut for SnapshotVec { - fn index_mut(&mut self, index: usize) -> &mut D::Value { - self.get_mut(index) - } -} - -impl Extend for SnapshotVec { - fn extend(&mut self, iterable: T) where T: IntoIterator { - for item in iterable { - self.push(item); - } - } -} diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs deleted file mode 100644 index 5411ae0257a..00000000000 --- a/src/librustc_data_structures/unify/mod.rs +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::marker; -use std::fmt::Debug; -use std::marker::PhantomData; -use snapshot_vec as sv; - -#[cfg(test)] -mod tests; - -/// This trait is implemented by any type that can serve as a type -/// variable. We call such variables *unification keys*. For example, -/// this trait is implemented by `IntVid`, which represents integral -/// variables. -/// -/// Each key type has an associated value type `V`. For example, for -/// `IntVid`, this is `Option`, representing some -/// (possibly not yet known) sort of integer. -/// -/// Clients are expected to provide implementations of this trait; you -/// can see some examples in the `test` module. -pub trait UnifyKey: Copy + Clone + Debug + PartialEq { - type Value: Clone + PartialEq + Debug; - - fn index(&self) -> u32; - - fn from_index(u: u32) -> Self; - - fn tag(k: Option) -> &'static str; -} - -/// This trait is implemented for unify values that can be -/// combined. This relation should be a monoid. -pub trait Combine { - fn combine(&self, other: &Self) -> Self; -} - -impl Combine for () { - fn combine(&self, _other: &()) {} -} - -/// Value of a unification key. We implement Tarjan's union-find -/// algorithm: when two keys are unified, one of them is converted -/// into a "redirect" pointing at the other. These redirects form a -/// DAG: the roots of the DAG (nodes that are not redirected) are each -/// associated with a value of type `V` and a rank. The rank is used -/// to keep the DAG relatively balanced, which helps keep the running -/// time of the algorithm under control. For more information, see -/// . -#[derive(PartialEq,Clone,Debug)] -pub struct VarValue { - parent: K, // if equal to self, this is a root - value: K::Value, // value assigned (only relevant to root) - rank: u32, // max depth (only relevant to root) -} - -/// Table of unification keys and their values. -pub struct UnificationTable { - /// Indicates the current value of each key. - values: sv::SnapshotVec>, -} - -/// At any time, users may snapshot a unification table. The changes -/// made during the snapshot may either be *committed* or *rolled back*. -pub struct Snapshot { - // Link snapshot to the key type `K` of the table. - marker: marker::PhantomData, - snapshot: sv::Snapshot, -} - -#[derive(Copy, Clone)] -struct Delegate(PhantomData); - -impl VarValue { - fn new_var(key: K, value: K::Value) -> VarValue { - VarValue::new(key, value, 0) - } - - fn new(parent: K, value: K::Value, rank: u32) -> VarValue { - VarValue { - parent: parent, // this is a root - value, - rank, - } - } - - fn redirect(self, to: K) -> VarValue { - VarValue { parent: to, ..self } - } - - fn root(self, rank: u32, value: K::Value) -> VarValue { - VarValue { - rank, - value, - ..self - } - } - - /// Returns the key of this node. Only valid if this is a root - /// node, which you yourself must ensure. - fn key(&self) -> K { - self.parent - } - - fn parent(&self, self_key: K) -> Option { - self.if_not_self(self.parent, self_key) - } - - fn if_not_self(&self, key: K, self_key: K) -> Option { - if key == self_key { None } else { Some(key) } - } -} - -/// We can't use V:LatticeValue, much as I would like to, -/// because frequently the pattern is that V=Option for some -/// other type parameter U, and we have no way to say -/// Option:LatticeValue. - -impl UnificationTable { - pub fn new() -> UnificationTable { - UnificationTable { values: sv::SnapshotVec::new() } - } - - /// Starts a new snapshot. Each snapshot must be either - /// rolled back or committed in a "LIFO" (stack) order. - pub fn snapshot(&mut self) -> Snapshot { - Snapshot { - marker: marker::PhantomData::, - snapshot: self.values.start_snapshot(), - } - } - - /// Reverses all changes since the last snapshot. Also - /// removes any keys that have been created since then. - pub fn rollback_to(&mut self, snapshot: Snapshot) { - debug!("{}: rollback_to()", UnifyKey::tag(None::)); - self.values.rollback_to(snapshot.snapshot); - } - - /// Commits all changes since the last snapshot. Of course, they - /// can still be undone if there is a snapshot further out. - pub fn commit(&mut self, snapshot: Snapshot) { - debug!("{}: commit()", UnifyKey::tag(None::)); - self.values.commit(snapshot.snapshot); - } - - pub fn new_key(&mut self, value: K::Value) -> K { - let len = self.values.len(); - let key: K = UnifyKey::from_index(len as u32); - self.values.push(VarValue::new_var(key, value)); - debug!("{}: created new key: {:?}", UnifyKey::tag(None::), key); - key - } - - /// Find the root node for `vid`. This uses the standard - /// union-find algorithm with path compression: - /// . - /// - /// NB. This is a building-block operation and you would probably - /// prefer to call `probe` below. - fn get(&mut self, vid: K) -> VarValue { - let index = vid.index() as usize; - let mut value: VarValue = self.values.get(index).clone(); - match value.parent(vid) { - Some(redirect) => { - let root: VarValue = self.get(redirect); - if root.key() != redirect { - // Path compression - value.parent = root.key(); - self.values.set(index, value); - } - root - } - None => value, - } - } - - fn is_root(&self, key: K) -> bool { - let index = key.index() as usize; - self.values.get(index).parent(key).is_none() - } - - /// Sets the value for `vid` to `new_value`. `vid` MUST be a root - /// node! This is an internal operation used to impl other things. - fn set(&mut self, key: K, new_value: VarValue) { - assert!(self.is_root(key)); - - debug!("Updating variable {:?} to {:?}", key, new_value); - - let index = key.index() as usize; - self.values.set(index, new_value); - } - - /// Either redirects `node_a` to `node_b` or vice versa, depending - /// on the relative rank. The value associated with the new root - /// will be `new_value`. - /// - /// NB: This is the "union" operation of "union-find". It is - /// really more of a building block. If the values associated with - /// your key are non-trivial, you would probably prefer to call - /// `unify_var_var` below. - fn unify(&mut self, root_a: VarValue, root_b: VarValue, new_value: K::Value) -> K { - debug!("unify(root_a(id={:?}, rank={:?}), root_b(id={:?}, rank={:?}))", - root_a.key(), - root_a.rank, - root_b.key(), - root_b.rank); - - if root_a.rank > root_b.rank { - // a has greater rank, so a should become b's parent, - // i.e., b should redirect to a. - self.redirect_root(root_a.rank, root_b, root_a, new_value) - } else if root_a.rank < root_b.rank { - // b has greater rank, so a should redirect to b. - self.redirect_root(root_b.rank, root_a, root_b, new_value) - } else { - // If equal, redirect one to the other and increment the - // other's rank. - self.redirect_root(root_a.rank + 1, root_a, root_b, new_value) - } - } - - fn redirect_root(&mut self, - new_rank: u32, - old_root: VarValue, - new_root: VarValue, - new_value: K::Value) - -> K { - let old_root_key = old_root.key(); - let new_root_key = new_root.key(); - self.set(old_root_key, old_root.redirect(new_root_key)); - self.set(new_root_key, new_root.root(new_rank, new_value)); - new_root_key - } -} - -impl sv::SnapshotVecDelegate for Delegate { - type Value = VarValue; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -/// # Base union-find algorithm, where we are just making sets - -impl<'tcx, K: UnifyKey> UnificationTable - where K::Value: Combine -{ - pub fn union(&mut self, a_id: K, b_id: K) -> K { - let node_a = self.get(a_id); - let node_b = self.get(b_id); - let a_id = node_a.key(); - let b_id = node_b.key(); - if a_id != b_id { - let new_value = node_a.value.combine(&node_b.value); - self.unify(node_a, node_b, new_value) - } else { - a_id - } - } - - pub fn find(&mut self, id: K) -> K { - self.get(id).key() - } - - pub fn find_value(&mut self, id: K) -> K::Value { - self.get(id).value - } - - #[cfg(test)] - fn unioned(&mut self, a_id: K, b_id: K) -> bool { - self.find(a_id) == self.find(b_id) - } -} - -/// # Non-subtyping unification -/// -/// Code to handle keys which carry a value, like ints, -/// floats---anything that doesn't have a subtyping relationship we -/// need to worry about. - -impl<'tcx, K, V> UnificationTable - where K: UnifyKey>, - V: Clone + PartialEq + Debug -{ - pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result { - let node_a = self.get(a_id); - let node_b = self.get(b_id); - let a_id = node_a.key(); - let b_id = node_b.key(); - - if a_id == b_id { - return Ok(a_id); - } - - let combined = { - match (&node_a.value, &node_b.value) { - (&None, &None) => None, - (&Some(ref v), &None) | - (&None, &Some(ref v)) => Some(v.clone()), - (&Some(ref v1), &Some(ref v2)) => { - if *v1 != *v2 { - return Err((v1.clone(), v2.clone())); - } - Some(v1.clone()) - } - } - }; - - Ok(self.unify(node_a, node_b, combined)) - } - - /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping - /// relationships, if `a_id` already has a value, it must be the same as `b`. - pub fn unify_var_value(&mut self, a_id: K, b: V) -> Result<(), (V, V)> { - let mut node_a = self.get(a_id); - - match node_a.value { - None => { - node_a.value = Some(b); - self.set(node_a.key(), node_a); - Ok(()) - } - - Some(ref a_t) => { - if *a_t == b { - Ok(()) - } else { - Err((a_t.clone(), b)) - } - } - } - } - - pub fn has_value(&mut self, id: K) -> bool { - self.get(id).value.is_some() - } - - pub fn probe(&mut self, a_id: K) -> Option { - self.get(a_id).value - } - - pub fn unsolved_variables(&mut self) -> Vec { - self.values - .iter() - .filter_map(|vv| { - if vv.value.is_some() { - None - } else { - Some(vv.key()) - } - }) - .collect() - } -} diff --git a/src/librustc_data_structures/unify/tests.rs b/src/librustc_data_structures/unify/tests.rs deleted file mode 100644 index f29a7132e83..00000000000 --- a/src/librustc_data_structures/unify/tests.rs +++ /dev/null @@ -1,205 +0,0 @@ -// 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. - -#![allow(non_snake_case)] - -extern crate test; -use self::test::Bencher; -use unify::{UnifyKey, UnificationTable}; - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -struct UnitKey(u32); - -impl UnifyKey for UnitKey { - type Value = (); - fn index(&self) -> u32 { - self.0 - } - fn from_index(u: u32) -> UnitKey { - UnitKey(u) - } - fn tag(_: Option) -> &'static str { - "UnitKey" - } -} - -#[test] -fn basic() { - let mut ut: UnificationTable = UnificationTable::new(); - let k1 = ut.new_key(()); - let k2 = ut.new_key(()); - assert_eq!(ut.unioned(k1, k2), false); - ut.union(k1, k2); - assert_eq!(ut.unioned(k1, k2), true); -} - -#[test] -fn big_array() { - let mut ut: UnificationTable = UnificationTable::new(); - let mut keys = Vec::new(); - const MAX: usize = 1 << 15; - - for _ in 0..MAX { - keys.push(ut.new_key(())); - } - - for i in 1..MAX { - let l = keys[i - 1]; - let r = keys[i]; - ut.union(l, r); - } - - for i in 0..MAX { - assert!(ut.unioned(keys[0], keys[i])); - } -} - -#[bench] -fn big_array_bench(b: &mut Bencher) { - let mut ut: UnificationTable = UnificationTable::new(); - let mut keys = Vec::new(); - const MAX: usize = 1 << 15; - - for _ in 0..MAX { - keys.push(ut.new_key(())); - } - - - b.iter(|| { - for i in 1..MAX { - let l = keys[i - 1]; - let r = keys[i]; - ut.union(l, r); - } - - for i in 0..MAX { - assert!(ut.unioned(keys[0], keys[i])); - } - }) -} - -#[test] -fn even_odd() { - let mut ut: UnificationTable = UnificationTable::new(); - let mut keys = Vec::new(); - const MAX: usize = 1 << 10; - - for i in 0..MAX { - let key = ut.new_key(()); - keys.push(key); - - if i >= 2 { - ut.union(key, keys[i - 2]); - } - } - - for i in 1..MAX { - assert!(!ut.unioned(keys[i - 1], keys[i])); - } - - for i in 2..MAX { - assert!(ut.unioned(keys[i - 2], keys[i])); - } -} - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -struct IntKey(u32); - -impl UnifyKey for IntKey { - type Value = Option; - fn index(&self) -> u32 { - self.0 - } - fn from_index(u: u32) -> IntKey { - IntKey(u) - } - fn tag(_: Option) -> &'static str { - "IntKey" - } -} - -/// Test unifying a key whose value is `Some(_)` with a key whose value is `None`. -/// Afterwards both should be `Some(_)`. -#[test] -fn unify_key_Some_key_None() { - let mut ut: UnificationTable = UnificationTable::new(); - let k1 = ut.new_key(Some(22)); - let k2 = ut.new_key(None); - assert!(ut.unify_var_var(k1, k2).is_ok()); - assert_eq!(ut.probe(k2), Some(22)); - assert_eq!(ut.probe(k1), Some(22)); -} - -/// Test unifying a key whose value is `None` with a key whose value is `Some(_)`. -/// Afterwards both should be `Some(_)`. -#[test] -fn unify_key_None_key_Some() { - let mut ut: UnificationTable = UnificationTable::new(); - let k1 = ut.new_key(Some(22)); - let k2 = ut.new_key(None); - assert!(ut.unify_var_var(k2, k1).is_ok()); - assert_eq!(ut.probe(k2), Some(22)); - assert_eq!(ut.probe(k1), Some(22)); -} - -/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(y)`. -/// This should yield an error. -#[test] -fn unify_key_Some_x_key_Some_y() { - let mut ut: UnificationTable = UnificationTable::new(); - let k1 = ut.new_key(Some(22)); - let k2 = ut.new_key(Some(23)); - assert_eq!(ut.unify_var_var(k1, k2), Err((22, 23))); - assert_eq!(ut.unify_var_var(k2, k1), Err((23, 22))); - assert_eq!(ut.probe(k1), Some(22)); - assert_eq!(ut.probe(k2), Some(23)); -} - -/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(x)`. -/// This should be ok. -#[test] -fn unify_key_Some_x_key_Some_x() { - let mut ut: UnificationTable = UnificationTable::new(); - let k1 = ut.new_key(Some(22)); - let k2 = ut.new_key(Some(22)); - assert!(ut.unify_var_var(k1, k2).is_ok()); - assert_eq!(ut.probe(k1), Some(22)); - assert_eq!(ut.probe(k2), Some(22)); -} - -/// Test unifying a key whose value is `None` with a value is `x`. -/// Afterwards key should be `x`. -#[test] -fn unify_key_None_val() { - let mut ut: UnificationTable = UnificationTable::new(); - let k1 = ut.new_key(None); - assert!(ut.unify_var_value(k1, 22).is_ok()); - assert_eq!(ut.probe(k1), Some(22)); -} - -/// Test unifying a key whose value is `Some(x)` with the value `y`. -/// This should yield an error. -#[test] -fn unify_key_Some_x_val_y() { - let mut ut: UnificationTable = UnificationTable::new(); - let k1 = ut.new_key(Some(22)); - assert_eq!(ut.unify_var_value(k1, 23), Err((22, 23))); - assert_eq!(ut.probe(k1), Some(22)); -} - -/// Test unifying a key whose value is `Some(x)` with the value `x`. -/// This should be ok. -#[test] -fn unify_key_Some_x_val_x() { - let mut ut: UnificationTable = UnificationTable::new(); - let k1 = ut.new_key(Some(22)); - assert!(ut.unify_var_value(k1, 22).is_ok()); - assert_eq!(ut.probe(k1), Some(22)); -} -- cgit 1.4.1-3-g733a5 From fec4d3b71161aa7b2861861cbf9b708c8c393b30 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Wed, 28 Feb 2018 10:27:18 -0700 Subject: Bump ena --- src/Cargo.lock | 6 +++--- src/librustc_data_structures/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/Cargo.lock b/src/Cargo.lock index d70631fa519..2cc647c49c6 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -600,7 +600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ena" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1874,7 +1874,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2870,7 +2870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c" "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" -"checksum ena 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb80e4764284ff0ec7054cb05c557f5ba01ccf65ff0c265e981c0b303d0ffc" +"checksum ena 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1733e41a3c37b0893685933d09dcb0c30269aa5d14dc5cafebf4bcded1e58225" "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 40d557ee5e0..e1f0a74fc68 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -ena = "0.8.0" +ena = "0.9.1" log = "0.4" serialize = { path = "../libserialize" } cfg-if = "0.1.2" -- cgit 1.4.1-3-g733a5 From 2e7e68b76223b9f14b54852584a5334f33a8798d Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 5 Mar 2018 15:58:54 -0300 Subject: while let all the things --- src/librustc/hir/print.rs | 9 ++------- src/librustc/middle/reachable.rs | 6 +----- .../obligation_forest/mod.rs | 8 +------- src/libstd/sys_common/wtf8.rs | 23 +++++++++------------- src/libsyntax_ext/format.rs | 17 ++++++---------- src/libsyntax_pos/lib.rs | 7 +------ 6 files changed, 20 insertions(+), 50 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index ed8cea3eb65..d91aa3a3851 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -2208,13 +2208,8 @@ impl<'a> State<'a> { if self.next_comment().is_none() { self.s.hardbreak()?; } - loop { - match self.next_comment() { - Some(ref cmnt) => { - self.print_comment(cmnt)?; - } - _ => break, - } + while let Some(ref cmnt) = self.next_comment() { + self.print_comment(cmnt)? } Ok(()) } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 749685182a8..5658b5b6832 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -206,11 +206,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Step 2: Mark all symbols that the symbols on the worklist touch. fn propagate(&mut self) { let mut scanned = FxHashSet(); - loop { - let search_item = match self.worklist.pop() { - Some(item) => item, - None => break, - }; + while let Some(search_item) = self.worklist.pop() { if !scanned.insert(search_item) { continue } diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 02cae52166a..42a17d33fa6 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -415,13 +415,7 @@ impl ObligationForest { } } - loop { - // non-standard `while let` to bypass #6393 - let i = match error_stack.pop() { - Some(i) => i, - None => break - }; - + while let Some(i) = error_stack.pop() { let node = &self.nodes[i]; match node.state.get() { diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 46d554d6411..9fff8b91f96 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -428,20 +428,15 @@ impl fmt::Debug for Wtf8 { formatter.write_str("\"")?; let mut pos = 0; - loop { - match self.next_surrogate(pos) { - None => break, - Some((surrogate_pos, surrogate)) => { - write_str_escaped( - formatter, - unsafe { str::from_utf8_unchecked( - &self.bytes[pos .. surrogate_pos] - )}, - )?; - write!(formatter, "\\u{{{:x}}}", surrogate)?; - pos = surrogate_pos + 3; - } - } + while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { + write_str_escaped( + formatter, + unsafe { str::from_utf8_unchecked( + &self.bytes[pos .. surrogate_pos] + )}, + )?; + write!(formatter, "\\u{{{:x}}}", surrogate)?; + pos = surrogate_pos + 3; } write_str_escaped( formatter, diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index a7822414c69..8fd95aa1ca8 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -732,18 +732,13 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let mut parser = parse::Parser::new(fmt_str); let mut pieces = vec![]; - loop { - match parser.next() { - Some(mut piece) => { - if !parser.errors.is_empty() { - break; - } - cx.verify_piece(&piece); - cx.resolve_name_inplace(&mut piece); - pieces.push(piece); - } - None => break, + while let Some(mut piece) = parser.next() { + if !parser.errors.is_empty() { + break; } + cx.verify_piece(&piece); + cx.resolve_name_inplace(&mut piece); + pieces.push(piece); } let numbered_position_args = pieces.iter().any(|arg: &parse::Piece| { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9f746adbe65..ed9eb5d5c92 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -322,12 +322,7 @@ impl Span { pub fn macro_backtrace(mut self) -> Vec { let mut prev_span = DUMMY_SP; let mut result = vec![]; - loop { - let info = match self.ctxt().outer().expn_info() { - Some(info) => info, - None => break, - }; - + while let Some(info) = self.ctxt().outer().expn_info() { let (pre, post) = match info.callee.format { ExpnFormat::MacroAttribute(..) => ("#[", "]"), ExpnFormat::MacroBang(..) => ("", "!"), -- cgit 1.4.1-3-g733a5 From 6701d9020f0deb0e8d673fe5ad1247514b3e9db3 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 6 Mar 2018 00:58:01 +0000 Subject: Remove IdxSet::reset_to_empty --- src/librustc_data_structures/indexed_set.rs | 5 ----- src/librustc_mir/dataflow/at_location.rs | 8 ++++---- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 223e08de826..7c926cc784b 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -231,11 +231,6 @@ impl IdxSet { each_bit(self, max_bits, f) } - /// Removes all elements from this set. - pub fn reset_to_empty(&mut self) { - for word in self.words_mut() { *word = 0; } - } - pub fn elems(&self, universe_size: usize) -> Elems { Elems { i: 0, set: self, universe_size: universe_size } } diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index b1f73bfbe22..30248ccf931 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -147,8 +147,8 @@ impl FlowsAtLocation for FlowAtLocation } fn reconstruct_statement_effect(&mut self, loc: Location) { - self.stmt_gen.reset_to_empty(); - self.stmt_kill.reset_to_empty(); + self.stmt_gen.clear(); + self.stmt_kill.clear(); { let mut sets = BlockSets { on_entry: &mut self.curr_state, @@ -172,8 +172,8 @@ impl FlowsAtLocation for FlowAtLocation } fn reconstruct_terminator_effect(&mut self, loc: Location) { - self.stmt_gen.reset_to_empty(); - self.stmt_kill.reset_to_empty(); + self.stmt_gen.clear(); + self.stmt_kill.clear(); { let mut sets = BlockSets { on_entry: &mut self.curr_state, -- cgit 1.4.1-3-g733a5 From 89d12478ac4f56e45da7ece5d5cac983897653d6 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 6 Mar 2018 01:00:44 +0000 Subject: Remove IdxSet::each_bit --- src/librustc_data_structures/indexed_set.rs | 33 ----------------------------- src/librustc_mir/dataflow/at_location.rs | 6 ++---- src/librustc_mir/dataflow/mod.rs | 3 +-- 3 files changed, 3 insertions(+), 39 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 7c926cc784b..34457d94c3a 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -225,12 +225,6 @@ impl IdxSet { } } - /// Calls `f` on each index value held in this set, up to the - /// bound `max_bits` on the size of universe of indexes. - pub fn each_bit(&self, max_bits: usize, f: F) where F: FnMut(T) { - each_bit(self, max_bits, f) - } - pub fn elems(&self, universe_size: usize) -> Elems { Elems { i: 0, set: self, universe_size: universe_size } } @@ -256,33 +250,6 @@ impl<'a, T: Idx> Iterator for Elems<'a, T> { } } } - -fn each_bit(words: &IdxSet, max_bits: usize, mut f: F) where F: FnMut(T) { - let usize_bits: usize = mem::size_of::() * 8; - - for (word_index, &word) in words.words().iter().enumerate() { - if word != 0 { - let base_index = word_index * usize_bits; - for offset in 0..usize_bits { - let bit = 1 << offset; - if (word & bit) != 0 { - // NB: we round up the total number of bits - // that we store in any given bit set so that - // it is an even multiple of usize::BITS. This - // means that there may be some stray bits at - // the end that do not correspond to any - // actual value; that's why we first check - // that we are in range of bits_per_block. - let bit_index = base_index + offset as usize; - if bit_index >= max_bits { - return; - } else { - f(Idx::new(bit_index)); - } - } - } - } - } } pub struct Iter<'a, T: Idx> { diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index 30248ccf931..32ca513d7df 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -81,8 +81,7 @@ where where F: FnMut(BD::Idx), { - self.curr_state - .each_bit(self.base_results.operator().bits_per_block(), f) + self.curr_state.iter().for_each(f) } /// Iterate over each `gen` bit in the current effect (invoke @@ -92,8 +91,7 @@ where where F: FnMut(BD::Idx), { - self.stmt_gen - .each_bit(self.base_results.operator().bits_per_block(), f) + self.stmt_gen.iter().for_each(f) } pub fn new(results: DataflowResults) -> Self { diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index aa7bb6f9778..7785b6ec173 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -444,8 +444,7 @@ pub struct DataflowState impl DataflowState { pub fn each_bit(&self, words: &IdxSet, f: F) where F: FnMut(O::Idx) { - let bits_per_block = self.operator.bits_per_block(); - words.each_bit(bits_per_block, f) + words.iter().for_each(f) } pub(crate) fn interpret_set<'c, P>(&self, -- cgit 1.4.1-3-g733a5 From f69a0999e742a6fc45fd4b962c30c56d04c2245c Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 6 Mar 2018 01:00:53 +0000 Subject: Remove IdxSet::elems --- src/librustc_data_structures/indexed_set.rs | 26 -------------------------- src/librustc_mir/borrow_check/mod.rs | 10 +++++----- src/librustc_mir/dataflow/at_location.rs | 14 ++++++-------- 3 files changed, 11 insertions(+), 39 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 34457d94c3a..7ab6a269148 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -224,32 +224,6 @@ impl IdxSet { _pd: PhantomData, } } - - pub fn elems(&self, universe_size: usize) -> Elems { - Elems { i: 0, set: self, universe_size: universe_size } - } -} - -pub struct Elems<'a, T: Idx> { i: usize, set: &'a IdxSet, universe_size: usize } - -impl<'a, T: Idx> Iterator for Elems<'a, T> { - type Item = T; - fn next(&mut self) -> Option { - if self.i >= self.universe_size { return None; } - let mut i = self.i; - loop { - if i >= self.universe_size { - self.i = i; // (mark iteration as complete.) - return None; - } - if self.set.contains(&T::new(i)) { - self.i = i + 1; // (next element to start at.) - return Some(T::new(i)); - } - i = i + 1; - } - } -} } pub struct Iter<'a, T: Idx> { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 1ff0ffaaa68..f0304ccd040 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -555,7 +555,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx // Look for any active borrows to locals let domain = flow_state.borrows.operator(); let data = domain.borrows(); - flow_state.borrows.with_elems_outgoing(|borrows| { + flow_state.borrows.with_iter_outgoing(|borrows| { for i in borrows { let borrow = &data[i.borrow_index()]; self.check_for_local_borrow(borrow, span); @@ -571,7 +571,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx // so this "extra check" serves as a kind of backup. let domain = flow_state.borrows.operator(); let data = domain.borrows(); - flow_state.borrows.with_elems_outgoing(|borrows| { + flow_state.borrows.with_iter_outgoing(|borrows| { for i in borrows { let borrow = &data[i.borrow_index()]; let context = ContextKind::StorageDead.new(loc); @@ -1310,7 +1310,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { place ); - for i in flow_state.ever_inits.elems_incoming() { + for i in flow_state.ever_inits.iter_incoming() { let init = self.move_data.inits[i]; let init_place = &self.move_data.move_paths[init.path].place; if self.places_conflict(&init_place, place, Deep) { @@ -2155,8 +2155,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // check for loan restricting path P being used. Accounts for // borrows of P, P.a.b, etc. - let mut elems_incoming = flow_state.borrows.elems_incoming(); - while let Some(i) = elems_incoming.next() { + let mut iter_incoming = flow_state.borrows.iter_incoming(); + while let Some(i) = iter_incoming.next() { let borrowed = &data[i.borrow_index()]; if self.places_conflict(&borrowed.borrowed_place, place, access) { diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index 32ca513d7df..0fbb54e8e0a 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -12,7 +12,7 @@ //! locations. use rustc::mir::{BasicBlock, Location}; -use rustc_data_structures::indexed_set::{self, IdxSetBuf}; +use rustc_data_structures::indexed_set::{IdxSetBuf, Iter}; use rustc_data_structures::indexed_vec::Idx; use dataflow::{BitDenotation, BlockSets, DataflowResults}; @@ -117,23 +117,21 @@ where } /// Returns an iterator over the elements present in the current state. - pub fn elems_incoming(&self) -> iter::Peekable> { - let univ = self.base_results.sets().bits_per_block(); - self.curr_state.elems(univ).peekable() + pub fn iter_incoming(&self) -> iter::Peekable> { + self.curr_state.iter().peekable() } /// Creates a clone of the current state and applies the local /// effects to the clone (leaving the state of self intact). /// Invokes `f` with an iterator over the resulting state. - pub fn with_elems_outgoing(&self, f: F) + pub fn with_iter_outgoing(&self, f: F) where - F: FnOnce(indexed_set::Elems), + F: FnOnce(Iter), { let mut curr_state = self.curr_state.clone(); curr_state.union(&self.stmt_gen); curr_state.subtract(&self.stmt_kill); - let univ = self.base_results.sets().bits_per_block(); - f(curr_state.elems(univ)); + f(curr_state.iter()); } } -- cgit 1.4.1-3-g733a5 From 62089c335fbdbe2a04c432239dce9e6e8f9a5e8e Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Sat, 3 Mar 2018 06:17:06 +0100 Subject: Make metadata references Send + Sync --- src/librustc/middle/cstore.rs | 7 ++-- src/librustc_data_structures/owning_ref/mod.rs | 47 ++++++++++++++++++++++---- src/librustc_data_structures/sync.rs | 3 +- src/librustc_llvm/archive_ro.rs | 2 ++ src/librustc_llvm/lib.rs | 2 ++ src/librustc_metadata/cstore.rs | 5 +-- src/librustc_metadata/lib.rs | 1 + src/librustc_metadata/locator.rs | 10 +++--- src/librustc_trans/lib.rs | 2 +- src/librustc_trans/metadata.rs | 12 ++++--- src/librustc_trans_utils/lib.rs | 2 +- src/librustc_trans_utils/trans_crate.rs | 14 ++++---- 12 files changed, 76 insertions(+), 31 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 7f068e8f71b..ea11930ae89 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -37,13 +37,12 @@ use util::nodemap::NodeSet; use std::any::Any; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -use rustc_data_structures::owning_ref::ErasedBoxRef; use syntax::ast; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; use syntax_pos::Span; use rustc_back::target::Target; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{MetadataRef, Lrc}; pub use self::NativeLibraryKind::*; @@ -187,11 +186,11 @@ pub trait MetadataLoader { fn get_rlib_metadata(&self, target: &Target, filename: &Path) - -> Result, String>; + -> Result; fn get_dylib_metadata(&self, target: &Target, filename: &Path) - -> Result, String>; + -> Result; } #[derive(Clone)] diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index 23e0733748b..c466b8f8ad1 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -243,6 +243,7 @@ fn main() { ``` */ +use std::mem; pub use stable_deref_trait::{StableDeref as StableAddress, CloneStableDeref as CloneStableAddress}; /// An owning reference. @@ -279,7 +280,7 @@ pub struct OwningRefMut { pub trait Erased {} impl Erased for T {} -/// Helper trait for erasing the concrete type of what an owner derferences to, +/// Helper trait for erasing the concrete type of what an owner dereferences to, /// for example `Box -> Box`. This would be unneeded with /// higher kinded types support in the language. pub unsafe trait IntoErased<'a> { @@ -289,10 +290,20 @@ pub unsafe trait IntoErased<'a> { fn into_erased(self) -> Self::Erased; } -/// Helper trait for erasing the concrete type of what an owner derferences to, +/// Helper trait for erasing the concrete type of what an owner dereferences to, +/// for example `Box -> Box`. This would be unneeded with +/// higher kinded types support in the language. +pub unsafe trait IntoErasedSend<'a> { + /// Owner with the dereference type substituted to `Erased + Send`. + type Erased: Send; + /// Perform the type erasure. + fn into_erased_send(self) -> Self::Erased; +} + +/// Helper trait for erasing the concrete type of what an owner dereferences to, /// for example `Box -> Box`. This would be unneeded with /// higher kinded types support in the language. -pub unsafe trait IntoErasedSendSync<'a>: Send + Sync { +pub unsafe trait IntoErasedSendSync<'a> { /// Owner with the dereference type substituted to `Erased + Send + Sync`. type Erased: Send + Sync; /// Perform the type erasure. @@ -472,6 +483,18 @@ impl OwningRef { } } + /// Erases the concrete base type of the owner with a trait object which implements `Send`. + /// + /// This allows mixing of owned references with different owner base types. + pub fn erase_send_owner<'a>(self) -> OwningRef + where O: IntoErasedSend<'a>, + { + OwningRef { + reference: self.reference, + owner: self.owner.into_erased_send(), + } + } + /// Erases the concrete base type of the owner with a trait object which implements `Send` and `Sync`. /// /// This allows mixing of owned references with different owner base types. @@ -1161,13 +1184,25 @@ unsafe impl<'a, T: 'a> IntoErased<'a> for Arc { } } -unsafe impl<'a, T: Send + Sync + 'a> IntoErasedSendSync<'a> for Box { - type Erased = Box; - fn into_erased_send_sync(self) -> Self::Erased { +unsafe impl<'a, T: Send + 'a> IntoErasedSend<'a> for Box { + type Erased = Box; + fn into_erased_send(self) -> Self::Erased { self } } +unsafe impl<'a, T: Send + 'a> IntoErasedSendSync<'a> for Box { + type Erased = Box; + fn into_erased_send_sync(self) -> Self::Erased { + let result: Box = self; + // This is safe since Erased can always implement Sync + // Only the destructor is available and it takes &mut self + unsafe { + mem::transmute(result) + } + } +} + unsafe impl<'a, T: Send + Sync + 'a> IntoErasedSendSync<'a> for Arc { type Erased = Arc; fn into_erased_send_sync(self) -> Self::Erased { diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index b1ab4eaa069..69fc9ef785e 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -177,7 +177,7 @@ cfg_if! { macro_rules! rustc_erase_owner { ($v:expr) => {{ let v = $v; - ::rustc_data_structures::sync::assert_send_sync_val(&v); + ::rustc_data_structures::sync::assert_send_val(&v); v.erase_send_sync_owner() }} } @@ -262,6 +262,7 @@ cfg_if! { } pub fn assert_sync() {} +pub fn assert_send_val(_t: &T) {} pub fn assert_send_sync_val(_t: &T) {} #[macro_export] diff --git a/src/librustc_llvm/archive_ro.rs b/src/librustc_llvm/archive_ro.rs index 6c3626cd880..9d869007270 100644 --- a/src/librustc_llvm/archive_ro.rs +++ b/src/librustc_llvm/archive_ro.rs @@ -22,6 +22,8 @@ pub struct ArchiveRO { ptr: ArchiveRef, } +unsafe impl Send for ArchiveRO {} + pub struct Iter<'a> { archive: &'a ArchiveRO, ptr: ::ArchiveIteratorRef, diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 8dcf7444dd1..16bee5b987e 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -221,6 +221,8 @@ pub struct ObjectFile { pub llof: ObjectFileRef, } +unsafe impl Send for ObjectFile {} + impl ObjectFile { // This will take ownership of llmb pub fn new(llmb: MemoryBufferRef) -> Option { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 8b59eec0190..d5a1771d535 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -24,7 +24,6 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap}; use std::cell::{RefCell, Cell}; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::owning_ref::ErasedBoxRef; use syntax::{ast, attr}; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; @@ -42,7 +41,9 @@ pub use cstore_impl::{provide, provide_extern}; // own crate numbers. pub type CrateNumMap = IndexVec; -pub struct MetadataBlob(pub ErasedBoxRef<[u8]>); +pub use rustc_data_structures::sync::MetadataRef; + +pub struct MetadataBlob(pub MetadataRef); /// Holds information about a syntax_pos::FileMap imported from another crate. /// See `imported_filemaps()` for more information. diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 2d015fa81f9..da0da622d52 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -39,6 +39,7 @@ extern crate proc_macro; #[macro_use] extern crate rustc; extern crate rustc_back; +#[macro_use] extern crate rustc_data_structures; mod diagnostics; diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index e0fb924f1aa..c56674bd6c5 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -219,7 +219,7 @@ //! no means all of the necessary details. Take a look at the rest of //! metadata::locator or metadata::creader for all the juicy details! -use cstore::MetadataBlob; +use cstore::{MetadataRef, MetadataBlob}; use creader::Library; use schema::{METADATA_HEADER, rustc_version}; @@ -243,8 +243,8 @@ use std::path::{Path, PathBuf}; use std::time::Instant; use flate2::read::DeflateDecoder; -use rustc_data_structures::owning_ref::{ErasedBoxRef, OwningRef}; +use rustc_data_structures::owning_ref::OwningRef; pub struct CrateMismatch { path: PathBuf, got: String, @@ -842,7 +842,7 @@ fn get_metadata_section_imp(target: &Target, if !filename.exists() { return Err(format!("no such file: '{}'", filename.display())); } - let raw_bytes: ErasedBoxRef<[u8]> = match flavor { + let raw_bytes: MetadataRef = match flavor { CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?, CrateFlavor::Dylib => { let buf = loader.get_dylib_metadata(target, filename)?; @@ -862,7 +862,7 @@ fn get_metadata_section_imp(target: &Target, match DeflateDecoder::new(compressed_bytes).read_to_end(&mut inflated) { Ok(_) => { let buf = unsafe { OwningRef::new_assert_stable_address(inflated) }; - buf.map_owner_box().erase_owner() + rustc_erase_owner!(buf.map_owner_box()) } Err(_) => { return Err(format!("failed to decompress metadata: {}", filename.display())); @@ -872,7 +872,7 @@ fn get_metadata_section_imp(target: &Target, CrateFlavor::Rmeta => { let buf = fs::read(filename).map_err(|_| format!("failed to read rmeta metadata: '{}'", filename.display()))?; - OwningRef::new(buf).map_owner_box().erase_owner() + rustc_erase_owner!(OwningRef::new(buf).map_owner_box()) } }; let blob = MetadataBlob(raw_bytes); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6cb9d2027c7..960e2ed629a 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -51,7 +51,7 @@ extern crate rustc_apfloat; extern crate rustc_back; extern crate rustc_binaryen; extern crate rustc_const_math; -extern crate rustc_data_structures; +#[macro_use] extern crate rustc_data_structures; extern crate rustc_demangle; extern crate rustc_incremental; extern crate rustc_llvm as llvm; diff --git a/src/librustc_trans/metadata.rs b/src/librustc_trans/metadata.rs index d57624da0c6..9483420f2f0 100644 --- a/src/librustc_trans/metadata.rs +++ b/src/librustc_trans/metadata.rs @@ -15,17 +15,19 @@ use llvm; use llvm::{False, ObjectFile, mk_section_iter}; use llvm::archive_ro::ArchiveRO; -use rustc_data_structures::owning_ref::{ErasedBoxRef, OwningRef}; +use rustc_data_structures::owning_ref::OwningRef; use std::path::Path; use std::ptr; use std::slice; +pub use rustc_data_structures::sync::MetadataRef; + pub const METADATA_FILENAME: &str = "rust.metadata.bin"; pub struct LlvmMetadataLoader; impl MetadataLoader for LlvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result, String> { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap // internally to read the file. We also avoid even using a memcpy by // just keeping the archive along while the metadata is in use. @@ -47,13 +49,13 @@ impl MetadataLoader for LlvmMetadataLoader { filename.display()) }) })?; - Ok(buf.erase_owner()) + Ok(rustc_erase_owner!(buf)) } fn get_dylib_metadata(&self, target: &Target, filename: &Path) - -> Result, String> { + -> Result { unsafe { let buf = common::path2cstr(filename); let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); @@ -65,7 +67,7 @@ impl MetadataLoader for LlvmMetadataLoader { .ok_or_else(|| format!("provided path not an object file: '{}'", filename.display()))?; let buf = of.try_map(|of| search_meta_section(of, target, filename))?; - Ok(buf.erase_owner()) + Ok(rustc_erase_owner!(buf)) } } } diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index bfecb201983..e87ab3abdf8 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -40,7 +40,7 @@ extern crate rustc_incremental; #[macro_use] extern crate syntax; extern crate syntax_pos; -extern crate rustc_data_structures; +#[macro_use] extern crate rustc_data_structures; pub extern crate rustc as __rustc; diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index 419371ba3e3..1e896f261c0 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -28,7 +28,7 @@ use std::fs::File; use std::path::Path; use std::sync::mpsc; -use rustc_data_structures::owning_ref::{ErasedBoxRef, OwningRef}; +use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::sync::Lrc; use ar::{Archive, Builder, Header}; use flate2::Compression; @@ -47,6 +47,8 @@ use rustc_back::target::Target; use rustc_mir::monomorphize::collector; use link::{build_link_meta, out_filename}; +pub use rustc_data_structures::sync::MetadataRef; + pub trait TransCrate { fn init(&self, _sess: &Session) {} fn print(&self, _req: PrintRequest, _sess: &Session) {} @@ -119,7 +121,7 @@ impl MetadataLoader for DummyMetadataLoader { &self, _target: &Target, _filename: &Path - ) -> Result, String> { + ) -> Result { bug!("DummyMetadataLoader::get_rlib_metadata"); } @@ -127,7 +129,7 @@ impl MetadataLoader for DummyMetadataLoader { &self, _target: &Target, _filename: &Path - ) -> Result, String> { + ) -> Result { bug!("DummyMetadataLoader::get_dylib_metadata"); } } @@ -135,7 +137,7 @@ impl MetadataLoader for DummyMetadataLoader { pub struct NoLlvmMetadataLoader; impl MetadataLoader for NoLlvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result, String> { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { let file = File::open(filename) .map_err(|e| format!("metadata file open err: {:?}", e))?; let mut archive = Archive::new(file); @@ -147,7 +149,7 @@ impl MetadataLoader for NoLlvmMetadataLoader { let mut buf = Vec::new(); io::copy(&mut entry, &mut buf).unwrap(); let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); - return Ok(buf.map_owner_box().erase_owner()); + return Ok(rustc_erase_owner!(buf.map_owner_box())); } } @@ -158,7 +160,7 @@ impl MetadataLoader for NoLlvmMetadataLoader { &self, _target: &Target, _filename: &Path, - ) -> Result, String> { + ) -> Result { // FIXME: Support reading dylibs from llvm enabled rustc self.get_rlib_metadata(_target, _filename) } -- cgit 1.4.1-3-g733a5 From 3e60d996a00c6151b635994820edeb43ffd12e6c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 3 Mar 2018 10:22:07 -0500 Subject: Replace iterator structures with `impl Trait`. --- src/librustc_data_structures/graph/mod.rs | 102 ++++++++---------------------- src/librustc_data_structures/lib.rs | 1 + 2 files changed, 26 insertions(+), 77 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 56d5f5ffa3f..9ce9c738b16 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -196,27 +196,27 @@ impl Graph { // # Iterating over nodes, edges - pub fn enumerated_nodes(&self) -> EnumeratedNodes { - EnumeratedNodes { - iter: self.nodes.iter().enumerate() - } + pub fn enumerated_nodes(&self) -> impl Iterator)> { + self.nodes + .iter() + .enumerate() + .map(|(idx, n)| (NodeIndex(idx), n)) } - pub fn enumerated_edges(&self) -> EnumeratedEdges { - EnumeratedEdges { - iter: self.edges.iter().enumerate() - } + pub fn enumerated_edges(&self) -> impl Iterator)> { + self.edges + .iter() + .enumerate() + .map(|(idx, e)| (EdgeIndex(idx), e)) } - pub fn each_node<'a, F>(&'a self, mut f: F) -> bool - where F: FnMut(NodeIndex, &'a Node) -> bool + pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { //! Iterates over all edges defined in the graph. self.enumerated_nodes().all(|(node_idx, node)| f(node_idx, node)) } - pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool - where F: FnMut(EdgeIndex, &'a Edge) -> bool + pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { //! Iterates over all edges defined in the graph self.enumerated_edges().all(|(edge_idx, edge)| f(edge_idx, edge)) @@ -239,11 +239,17 @@ impl Graph { } } - pub fn successor_nodes(&self, source: NodeIndex) -> AdjacentTargets { + pub fn successor_nodes<'a>( + &'a self, + source: NodeIndex, + ) -> impl Iterator + 'a { self.outgoing_edges(source).targets() } - pub fn predecessor_nodes(&self, target: NodeIndex) -> AdjacentSources { + pub fn predecessor_nodes<'a>( + &'a self, + target: NodeIndex, + ) -> impl Iterator + 'a { self.incoming_edges(target).sources() } @@ -293,34 +299,6 @@ impl Graph { // # Iterators -pub struct EnumeratedNodes<'g, N> - where N: 'g, -{ - iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Node>> -} - -impl<'g, N: Debug> Iterator for EnumeratedNodes<'g, N> { - type Item = (NodeIndex, &'g Node); - - fn next(&mut self) -> Option<(NodeIndex, &'g Node)> { - self.iter.next().map(|(idx, n)| (NodeIndex(idx), n)) - } -} - -pub struct EnumeratedEdges<'g, E> - where E: 'g, -{ - iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Edge>> -} - -impl<'g, E: Debug> Iterator for EnumeratedEdges<'g, E> { - type Item = (EdgeIndex, &'g Edge); - - fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { - self.iter.next().map(|(idx, e)| (EdgeIndex(idx), e)) - } -} - pub struct AdjacentEdges<'g, N, E> where N: 'g, E: 'g @@ -330,13 +308,13 @@ pub struct AdjacentEdges<'g, N, E> next: EdgeIndex, } -impl<'g, N, E> AdjacentEdges<'g, N, E> { - fn targets(self) -> AdjacentTargets<'g, N, E> { - AdjacentTargets { edges: self } +impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { + fn targets(self) -> impl Iterator + 'g { + self.into_iter().map(|(_, edge)| edge.target) } - fn sources(self) -> AdjacentSources<'g, N, E> { - AdjacentSources { edges: self } + fn sources(self) -> impl Iterator + 'g { + self.into_iter().map(|(_, edge)| edge.source) } } @@ -355,36 +333,6 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { } } -pub struct AdjacentTargets<'g, N, E> - where N: 'g, - E: 'g -{ - edges: AdjacentEdges<'g, N, E>, -} - -impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> { - type Item = NodeIndex; - - fn next(&mut self) -> Option { - self.edges.next().map(|(_, edge)| edge.target) - } -} - -pub struct AdjacentSources<'g, N, E> - where N: 'g, - E: 'g -{ - edges: AdjacentEdges<'g, N, E>, -} - -impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> { - type Item = NodeIndex; - - fn next(&mut self) -> Option { - self.edges.next().map(|(_, edge)| edge.source) - } -} - pub struct DepthFirstTraversal<'g, N, E> where N: 'g, E: 'g diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 265c6485830..81246aea1b5 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -34,6 +34,7 @@ #![feature(underscore_lifetimes)] #![feature(macro_vis_matcher)] #![feature(allow_internal_unstable)] +#![feature(universal_impl_trait)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] -- cgit 1.4.1-3-g733a5 From 08a01825364c429675d28b326e047ce4bc56ff7f Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 3 Mar 2018 10:24:29 -0500 Subject: Run rustfmt on `src/librustc_data_structures/graph/mod.rs`. --- src/librustc_data_structures/graph/mod.rs | 53 +++++++++++++++++-------------- 1 file changed, 29 insertions(+), 24 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 9ce9c738b16..1945b82c031 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -210,16 +210,16 @@ impl Graph { .map(|(idx, e)| (EdgeIndex(idx), e)) } - pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool - { + pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { //! Iterates over all edges defined in the graph. - self.enumerated_nodes().all(|(node_idx, node)| f(node_idx, node)) + self.enumerated_nodes() + .all(|(node_idx, node)| f(node_idx, node)) } - pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool - { + pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { //! Iterates over all edges defined in the graph - self.enumerated_edges().all(|(edge_idx, edge)| f(edge_idx, edge)) + self.enumerated_edges() + .all(|(edge_idx, edge)| f(edge_idx, edge)) } pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { @@ -253,18 +253,19 @@ impl Graph { self.incoming_edges(target).sources() } - pub fn depth_traverse<'a>(&'a self, - start: NodeIndex, - direction: Direction) - -> DepthFirstTraversal<'a, N, E> { + pub fn depth_traverse<'a>( + &'a self, + start: NodeIndex, + direction: Direction, + ) -> DepthFirstTraversal<'a, N, E> { DepthFirstTraversal::with_start_node(self, start, direction) } - pub fn nodes_in_postorder<'a>(&'a self, - direction: Direction, - entry_node: NodeIndex) - -> Vec - { + pub fn nodes_in_postorder<'a>( + &'a self, + direction: Direction, + entry_node: NodeIndex, + ) -> Vec { let mut visited = BitVector::new(self.len_nodes()); let mut stack = vec![]; let mut result = Vec::with_capacity(self.len_nodes()); @@ -274,7 +275,8 @@ impl Graph { } }; - for node in Some(entry_node).into_iter() + for node in Some(entry_node) + .into_iter() .chain(self.enumerated_nodes().map(|(node, _)| node)) { push_node(&mut stack, node); @@ -300,8 +302,9 @@ impl Graph { // # Iterators pub struct AdjacentEdges<'g, N, E> - where N: 'g, - E: 'g +where + N: 'g, + E: 'g, { graph: &'g Graph, direction: Direction, @@ -334,8 +337,9 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { } pub struct DepthFirstTraversal<'g, N, E> - where N: 'g, - E: 'g +where + N: 'g, + E: 'g, { graph: &'g Graph, stack: Vec, @@ -344,10 +348,11 @@ pub struct DepthFirstTraversal<'g, N, E> } impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { - pub fn with_start_node(graph: &'g Graph, - start_node: NodeIndex, - direction: Direction) - -> Self { + pub fn with_start_node( + graph: &'g Graph, + start_node: NodeIndex, + direction: Direction, + ) -> Self { let mut visited = BitVector::new(graph.len_nodes()); visited.insert(start_node.node_id()); DepthFirstTraversal { -- cgit 1.4.1-3-g733a5 From 2aa19feeb988710e6e9ca9e1c8a77f99e3fe7213 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Thu, 8 Mar 2018 04:50:43 +0100 Subject: Add with_lock, with_read_lock and with_write_lock --- src/librustc_data_structures/sync.rs | 126 ++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 39 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index b1ab4eaa069..f17ab264bff 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -62,7 +62,7 @@ cfg_if! { pub use std::cell::RefMut as WriteGuard; pub use std::cell::RefMut as LockGuard; - pub use std::cell::RefCell as RwLock; + use std::cell::RefCell as InnerRwLock; use std::cell::RefCell as InnerLock; use std::cell::Cell; @@ -159,13 +159,12 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; - use parking_lot; - pub use std::sync::Arc as Lrc; pub use self::Lock as MTLock; use parking_lot::Mutex as InnerLock; + use parking_lot::RwLock as InnerRwLock; pub type MetadataRef = OwningRef, [u8]>; @@ -222,42 +221,6 @@ cfg_if! { self.0.lock().take() } } - - #[derive(Debug)] - pub struct RwLock(parking_lot::RwLock); - - impl RwLock { - #[inline(always)] - pub fn new(inner: T) -> Self { - RwLock(parking_lot::RwLock::new(inner)) - } - - #[inline(always)] - pub fn borrow(&self) -> ReadGuard { - if ERROR_CHECKING { - self.0.try_read().expect("lock was already held") - } else { - self.0.read() - } - } - - #[inline(always)] - pub fn borrow_mut(&self) -> WriteGuard { - if ERROR_CHECKING { - self.0.try_write().expect("lock was already held") - } else { - self.0.write() - } - } - } - - // FIXME: Probably a bad idea - impl Clone for RwLock { - #[inline] - fn clone(&self) -> Self { - RwLock::new(self.borrow().clone()) - } - } } } @@ -383,6 +346,11 @@ impl Lock { self.0.borrow_mut() } + #[inline(always)] + pub fn with_lock R, R>(&self, f: F) -> R { + f(&mut *self.lock()) + } + #[inline(always)] pub fn borrow(&self) -> LockGuard { self.lock() @@ -401,3 +369,83 @@ impl Clone for Lock { Lock::new(self.borrow().clone()) } } + +#[derive(Debug)] +pub struct RwLock(InnerRwLock); + +impl RwLock { + #[inline(always)] + pub fn new(inner: T) -> Self { + RwLock(InnerRwLock::new(inner)) + } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0.into_inner() + } + + #[inline(always)] + pub fn get_mut(&mut self) -> &mut T { + self.0.get_mut() + } + + #[cfg(not(parallel_queries))] + #[inline(always)] + pub fn read(&self) -> ReadGuard { + self.0.borrow() + } + + #[cfg(parallel_queries)] + #[inline(always)] + pub fn read(&self) -> ReadGuard { + if ERROR_CHECKING { + self.0.try_read().expect("lock was already held") + } else { + self.0.read() + } + } + + #[inline(always)] + pub fn with_read_lock R, R>(&self, f: F) -> R { + f(&*self.read()) + } + + #[cfg(not(parallel_queries))] + #[inline(always)] + pub fn write(&self) -> WriteGuard { + self.0.borrow_mut() + } + + #[cfg(parallel_queries)] + #[inline(always)] + pub fn write(&self) -> WriteGuard { + if ERROR_CHECKING { + self.0.try_write().expect("lock was already held") + } else { + self.0.write() + } + } + + #[inline(always)] + pub fn with_write_lock R, R>(&self, f: F) -> R { + f(&mut *self.write()) + } + + #[inline(always)] + pub fn borrow(&self) -> ReadGuard { + self.read() + } + + #[inline(always)] + pub fn borrow_mut(&self) -> WriteGuard { + self.write() + } +} + +// FIXME: Probably a bad idea +impl Clone for RwLock { + #[inline] + fn clone(&self) -> Self { + RwLock::new(self.borrow().clone()) + } +} -- cgit 1.4.1-3-g733a5 From 918b6d763319863fb53c5b7bceebc14ad5fb4024 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:24:38 +0100 Subject: Produce instead of pointers --- src/libcore/cmp.rs | 4 +- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/middle/const_val.rs | 39 ++- src/librustc/middle/lang_items.rs | 1 + src/librustc/middle/mem_categorization.rs | 3 +- src/librustc/mir/interpret/value.rs | 10 + src/librustc/mir/mod.rs | 80 ++++- src/librustc/mir/tcx.rs | 2 +- src/librustc/mir/visit.rs | 14 +- src/librustc/ty/context.rs | 39 ++- src/librustc/ty/error.rs | 11 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/layout.rs | 4 +- src/librustc/ty/maps/config.rs | 1 + src/librustc/ty/maps/keys.rs | 1 + src/librustc/ty/maps/on_disk_cache.rs | 9 +- src/librustc/ty/mod.rs | 28 ++ src/librustc/ty/relate.rs | 9 + src/librustc/ty/structural_impls.rs | 55 ++++ src/librustc/ty/util.rs | 2 + src/librustc/util/ppaux.rs | 4 + src/librustc_const_eval/_match.rs | 180 +++++++++-- src/librustc_const_eval/eval.rs | 180 +++++------ src/librustc_const_eval/pattern.rs | 335 +++++++++++++-------- src/librustc_data_structures/stable_hasher.rs | 8 + src/librustc_lint/types.rs | 11 + src/librustc_metadata/decoder.rs | 38 ++- src/librustc_metadata/encoder.rs | 14 +- .../borrow_check/nll/type_check/mod.rs | 47 ++- src/librustc_mir/build/expr/as_rvalue.rs | 21 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 69 ++++- src/librustc_mir/build/misc.rs | 19 +- src/librustc_mir/hair/cx/expr.rs | 46 ++- src/librustc_mir/hair/cx/mod.rs | 178 ++++++++++- src/librustc_mir/interpret/const_eval.rs | 153 +++++++--- src/librustc_mir/interpret/eval_context.rs | 4 +- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/operator.rs | 5 + src/librustc_mir/interpret/place.rs | 43 +-- src/librustc_mir/interpret/terminator/mod.rs | 4 +- src/librustc_mir/monomorphize/item.rs | 2 +- src/librustc_mir/shim.rs | 29 +- src/librustc_mir/transform/generator.rs | 9 +- src/librustc_mir/transform/inline.rs | 7 + src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/transform/simplify_branches.rs | 4 +- src/librustc_mir/util/elaborate_drops.rs | 15 +- src/librustc_passes/consts.rs | 23 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/mir/analyze.rs | 19 +- src/librustc_trans/mir/block.rs | 9 +- src/librustc_trans/mir/constant.rs | 110 ++++--- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/op.rs | 8 +- src/librustc_typeck/collect.rs | 16 +- src/librustc_typeck/lib.rs | 1 + src/test/mir-opt/end_region_2.rs | 2 +- src/test/mir-opt/end_region_3.rs | 2 +- src/test/mir-opt/end_region_9.rs | 2 +- src/test/mir-opt/end_region_cyclic.rs | 2 +- src/test/mir-opt/issue-38669.rs | 2 +- src/test/mir-opt/match_false_edges.rs | 10 +- src/test/mir-opt/nll/region-liveness-basic.rs | 2 +- src/test/mir-opt/simplify_if.rs | 2 +- src/test/ui/const-eval-overflow-2.rs | 3 +- src/test/ui/const-eval-overflow-4.rs | 3 +- src/test/ui/const-eval/issue-43197.rs | 2 - src/test/ui/const-expr-addr-operator.rs | 3 +- src/test/ui/const-fn-error.rs | 13 +- src/test/ui/const-fn-error.stderr | 14 + src/test/ui/const-len-underflow-separate-spans.rs | 3 +- src/test/ui/const-pattern-not-const-evaluable.rs | 4 +- src/test/ui/feature-gate-const-indexing.rs | 3 +- src/test/ui/issue-38875/issue_38875.rs | 1 + src/test/ui/union/union-const-eval.rs | 9 +- 80 files changed, 1496 insertions(+), 532 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index b9847044982..6602643dc51 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -427,6 +427,7 @@ impl Ord for Reverse { /// } /// } /// ``` +#[cfg_attr(not(stage0), lang = "ord")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -596,7 +597,8 @@ impl PartialOrd for Ordering { /// assert_eq!(x < y, true); /// assert_eq!(x.lt(&y), true); /// ``` -#[lang = "ord"] +#[cfg_attr(stage0, lang = "ord")] +#[cfg_attr(not(stage0), lang = "partial_ord")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index ed46296389d..15e1d38be69 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -63,6 +63,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; +use mir; use ich::Fingerprint; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 589890947cd..cf322010e05 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; use rustc_const_math::*; -use mir::interpret::Value; +use mir::interpret::{Value, PrimVal}; use graphviz::IntoCow; use errors::DiagnosticBuilder; @@ -39,7 +39,7 @@ pub enum ConstVal<'tcx> { Function(DefId, &'tcx Substs<'tcx>), Aggregate(ConstAggregate<'tcx>), Unevaluated(DefId, &'tcx Substs<'tcx>), - /// A miri value, currently only produced if old ctfe fails, but miri succeeds + /// A miri value, currently only produced if --miri is enabled Value(Value), } @@ -71,12 +71,37 @@ impl<'tcx> Decodable for ConstAggregate<'tcx> { } impl<'tcx> ConstVal<'tcx> { - pub fn to_const_int(&self) -> Option { + pub fn to_u128(&self) -> Option { match *self { - ConstVal::Integral(i) => Some(i), - ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)), - ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)), - _ => None + ConstVal::Integral(i) => i.to_u128(), + ConstVal::Bool(b) => Some(b as u128), + ConstVal::Char(ch) => Some(ch as u32 as u128), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + Some(b) + }, + _ => None, + } + } + pub fn unwrap_u64(&self) -> u64 { + match self.to_u128() { + Some(val) => { + assert_eq!(val as u64 as u128, val); + val as u64 + }, + None => bug!("expected constant u64, got {:#?}", self), + } + } + pub fn unwrap_usize<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> ConstUsize { + match *self { + ConstVal::Integral(ConstInt::Usize(i)) => i, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + assert_eq!(b as u64 as u128, b); + match ConstUsize::new(b as u64, tcx.sess.target.usize_ty) { + Ok(val) => val, + Err(e) => bug!("{:#?} is not a usize {:?}", self, e), + } + }, + _ => bug!("expected constant u64, got {:#?}", self), } } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 447ce46ee5c..3b37031cf46 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -280,6 +280,7 @@ language_item_table! { GeneratorTraitLangItem, "generator", gen_trait; EqTraitLangItem, "eq", eq_trait; + PartialOrdTraitLangItem, "partial_ord", partial_ord_trait; OrdTraitLangItem, "ord", ord_trait; // A number of panic-related lang items. The `panic` item corresponds to diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c532427cc9b..1c60ae36cd3 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -913,8 +913,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, len) if - len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true, + ty::TyArray(_, len) if len.val.to_u128() == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 8d67856c0df..c00956c0a85 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,6 +1,7 @@ #![allow(unknown_lints)] use ty::layout::{Align, HasDataLayout}; +use ty; use super::{EvalResult, MemoryPointer, PointerArithmetic}; use syntax::ast::FloatTy; @@ -36,6 +37,15 @@ pub enum Value { ByValPair(PrimVal, PrimVal), } +impl<'tcx> ty::TypeFoldable<'tcx> for Value { + fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally. /// This type clears up a few APIs where having a `PrimVal` argument for something that is /// potentially an integer pointer or a pointer to an allocation was unclear. diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 4c1b8cb79ed..d35cbd0027f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,7 +15,7 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use middle::region; -use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; +use rustc_const_math::{ConstUsize, ConstMathErr}; use rustc_data_structures::sync::{Lrc}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; @@ -25,9 +25,11 @@ use rustc_serialize as serialize; use hir::def::CtorKind; use hir::def_id::DefId; use mir::visit::MirVisitable; +use mir::interpret::{Value, PrimVal}; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::TypeAndMut; use util::ppaux; use std::slice; use hir::{self, InlineAsm}; @@ -707,7 +709,7 @@ pub enum TerminatorKind<'tcx> { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. - values: Cow<'tcx, [ConstInt]>, + values: Cow<'tcx, [u128]>, /// Possible branch sites. The last element of this vector is used /// for the otherwise branch, so targets.len() == values.len() + 1 @@ -858,7 +860,7 @@ impl<'tcx> Terminator<'tcx> { impl<'tcx> TerminatorKind<'tcx> { pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)]; + static BOOL_SWITCH_FALSE: &'static [u128] = &[0]; TerminatorKind::SwitchInt { discr: cond, switch_ty: tcx.types.bool, @@ -1144,12 +1146,16 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], - SwitchInt { ref values, .. } => { + SwitchInt { ref values, switch_ty, .. } => { values.iter() - .map(|const_val| { - let mut buf = String::new(); - fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap(); - buf.into() + .map(|&u| { + let mut s = String::new(); + print_miri_value( + Value::ByVal(PrimVal::Bytes(u)), + switch_ty, + &mut s, + ).unwrap(); + s.into() }) .chain(iter::once(String::from("otherwise").into())) .collect() @@ -1533,7 +1539,12 @@ impl<'tcx> Operand<'tcx> { ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, substs) + }, ty }) }, @@ -1853,7 +1864,7 @@ impl<'tcx> Debug for Literal<'tcx> { match *self { Value { value } => { write!(fmt, "const ")?; - fmt_const_val(fmt, &value.val) + fmt_const_val(fmt, value) } Promoted { index } => { write!(fmt, "{:?}", index) @@ -1863,9 +1874,9 @@ impl<'tcx> Debug for Literal<'tcx> { } /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. -fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { +fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { use middle::const_val::ConstVal::*; - match *const_val { + match const_val.val { Float(f) => write!(fmt, "{:?}", f), Integral(n) => write!(fmt, "{}", n), Str(s) => write!(fmt, "{:?}", s), @@ -1882,7 +1893,41 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), Unevaluated(..) => write!(fmt, "{:?}", const_val), - Value(val) => write!(fmt, "{:?}", val), + Value(val) => print_miri_value(val, const_val.ty, fmt), + } +} + +fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { + use ty::TypeVariants::*; + use rustc_const_math::ConstFloat; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(fty)) => + write!(f, "{}", ConstFloat { bits, ty: fty }), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + (Value::ByVal(PrimVal::Undef), &TyFnDef(did, _)) => + write!(f, "{}", item_path_str(did)), + (Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)), &TyRef(_, TypeAndMut { + ty: &ty::TyS { sty: TyStr, .. }, .. + })) => { + ty::tls::with(|tcx| { + let alloc = tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + write!(f, "{:?}", s) + }) + }, + _ => write!(f, "{:?}:{}", value, ty), } } @@ -2468,6 +2513,15 @@ impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> } } +impl<'tcx> TypeFoldable<'tcx> for Field { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { Constant { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index bbfb9c89b3f..067c1742040 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { PlaceTy::Ty { ty: match ty.sty { ty::TyArray(inner, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let len = size - (from as u64) - (to as u64); tcx.mk_array(inner, len) } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 0b6f1275bdb..54d3ed38d65 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -243,12 +243,6 @@ macro_rules! make_mir_visitor { self.super_generator_interior(interior); } - fn visit_const_int(&mut self, - const_int: &ConstInt, - _: Location) { - self.super_const_int(const_int); - } - fn visit_const_usize(&mut self, const_usize: & $($mutability)* ConstUsize, _: Location) { @@ -426,13 +420,10 @@ macro_rules! make_mir_visitor { TerminatorKind::SwitchInt { ref $($mutability)* discr, ref $($mutability)* switch_ty, - ref values, + values: _, ref targets } => { self.visit_operand(discr, source_location); self.visit_ty(switch_ty, TyContext::Location(source_location)); - for value in &values[..] { - self.visit_const_int(value, source_location); - } for &target in targets { self.visit_branch(block, target); } @@ -798,9 +789,6 @@ macro_rules! make_mir_visitor { _substs: & $($mutability)* ClosureSubsts<'tcx>) { } - fn super_const_int(&mut self, _const_int: &ConstInt) { - } - fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) { } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 520da34c40a..17926eeec00 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -30,7 +30,8 @@ use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; -use mir::{Mir, interpret}; +use mir::{self, Mir, interpret}; +use mir::interpret::{Value, PrimVal}; use ty::subst::{Kind, Substs}; use ty::ReprOptions; use ty::Instance; @@ -1267,6 +1268,36 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_lang_items(LOCAL_CRATE) } + pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> { + let items = self.lang_items(); + let def_id = Some(def_id); + if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } + else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } + else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } + else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } + else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } + else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } + else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } + else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } + else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } + else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } + else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } + else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } + else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } + else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } + else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } + else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } + else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } + else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } + else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } + else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } + else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } + else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } + else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } + else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } + else { None } + } + pub fn stability(self) -> Lrc> { self.stability_index(LOCAL_CRATE) } @@ -2068,7 +2099,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> { self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(n)), + val: if self.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.as_u64().into()))) + } else { + ConstVal::Integral(ConstInt::Usize(n)) + }, ty: self.types.usize }))) } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index be89aeebdea..07920c58271 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -11,6 +11,7 @@ use hir::def_id::DefId; use middle::const_val::ConstVal; use ty::{self, BoundRegion, Region, Ty, TyCtxt}; +use mir::interpret::{Value, PrimVal}; use std::fmt; use syntax::abi; @@ -186,10 +187,12 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { - if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { - format!("array of {} elements", n) - } else { - "array".to_string() + match n.val { + ConstVal::Integral(ConstInt::Usize(n)) => + format!("array of {} elements", n), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))) => + format!("array of {} elements", n), + _ => "array".to_string(), } } ty::TySlice(_) => "slice".to_string(), diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 93e4cd9adf8..bfaa661b243 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - match len.val.to_const_int().and_then(|i| i.to_u64()) { + match len.val.to_u128() { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1aa7f671ad3..35d8fb2a67a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -952,7 +952,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { enum StructKind { /// A tuple, closure, or univariant which cannot be coerced to unsized. AlwaysSized, - /// A univariant, the last field of which may be coerced to unsized. + /// A univariant, the last field of which fn compute_uncachedmay be coerced to unsized. MaybeUnsized, /// A univariant, but with a prefix of an arbitrary size & alignment (e.g. enum tag). Prefixed(Size, Align), @@ -1237,7 +1237,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let element = self.layout_of(element)?; - let count = count.val.to_const_int().unwrap().to_u64().unwrap(); + let count = count.val.unwrap_u64(); let size = element.size.checked_mul(count, dl) .ok_or(LayoutError::SizeOverflow(ty))?; diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index d880b022e2f..ef1c8a8d4fa 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -13,6 +13,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::maps::queries; use ty::subst::Substs; +use mir; use std::hash::Hash; use syntax_pos::symbol::InternedString; diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index b7b64c9761a..3dd482ad164 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; use ty::fast_reject::SimplifiedType; +use mir; use std::fmt::Debug; use std::hash::Hash; diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index b18837ff35a..77e022fe730 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -15,7 +15,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; use hir::map::definitions::DefPathHash; use ich::{CachingCodemapView, Fingerprint}; -use mir; +use mir::{self, interpret}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -542,6 +542,13 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + unimplemented!() + } +} + impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { let tag: u8 = Decodable::decode(self)?; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index be27e3d5152..1577e78d81e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -26,6 +26,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; +use mir::interpret::{Value, PrimVal}; use mir::GeneratorLayout; use session::CrateDisambiguator; use traits; @@ -1838,6 +1839,19 @@ impl<'a, 'gcx, 'tcx> AdtDef { Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { discr = v; } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + trace!("discriminants: {} ({:?})", b, repr_type); + use syntax::attr::IntType; + discr = match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }; + } err => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), @@ -1879,6 +1893,20 @@ impl<'a, 'gcx, 'tcx> AdtDef { explicit_value = v; break; } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + trace!("discriminants: {} ({:?})", b, repr_type); + use syntax::attr::IntType; + explicit_value = match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }; + break; + } err => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index b9927c7eeb2..bac78508993 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -20,6 +20,7 @@ use ty::subst::{UnpackedKind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::{TypeVisitor, TypeFolder}; use ty::error::{ExpectedFound, TypeError}; +use mir::interpret::{Value, PrimVal}; use util::common::ErrorReported; use std::rc::Rc; use std::iter; @@ -483,6 +484,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { match x.val { ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), + ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()), ConstVal::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. let param_env = ty::ParamEnv::empty(Reveal::UserFacing); @@ -492,6 +494,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => { return Ok(x.to_u64().unwrap()); } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + assert_eq!(b as u64 as u128, b); + return Ok(b as u64); + } _ => {} } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 54db2d4f06b..80250949b0b 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -890,6 +890,61 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use ty::InstanceDef::*; + Self { + substs: self.substs.fold_with(folder), + def: match self.def { + Item(did) => Item(did.fold_with(folder)), + Intrinsic(did) => Intrinsic(did.fold_with(folder)), + FnPtrShim(did, ty) => FnPtrShim( + did.fold_with(folder), + ty.fold_with(folder), + ), + Virtual(did, i) => Virtual( + did.fold_with(folder), + i, + ), + ClosureOnceShim { call_once } => ClosureOnceShim { + call_once: call_once.fold_with(folder), + }, + DropGlue(did, ty) => DropGlue( + did.fold_with(folder), + ty.fold_with(folder), + ), + CloneShim(did, ty) => CloneShim( + did.fold_with(folder), + ty.fold_with(folder), + ), + }, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use ty::InstanceDef::*; + self.substs.visit_with(visitor) || + match self.def { + Item(did) => did.visit_with(visitor), + Intrinsic(did) => did.visit_with(visitor), + FnPtrShim(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + Virtual(did, _) => did.visit_with(visitor), + ClosureOnceShim { call_once } => call_once.visit_with(visitor), + DropGlue(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + CloneShim(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + } + } +} + impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let sty = match self.sty { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 785035ee5f4..6ad2901ce3a 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -24,6 +24,7 @@ use ty::maps::TyCtxtAt; use ty::TypeVariants::*; use util::common::ErrorReported; use middle::lang_items; +use mir::interpret::{Value, PrimVal}; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, @@ -765,6 +766,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> self.hash_discriminant_u8(&n.val); match n.val { ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b), ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), _ => bug!("arrays should not have {:?} as length", n) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index a2620da4c10..63d1f146825 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,6 +21,7 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use util::nodemap::FxHashSet; +use mir::interpret::{Value, PrimVal}; use std::cell::Cell; use std::fmt; @@ -1168,6 +1169,9 @@ define_print! { ConstVal::Integral(ConstInt::Usize(sz)) => { write!(f, "{}", sz)?; } + ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => { + write!(f, "{}", sz)?; + } ConstVal::Unevaluated(_def_id, substs) => { write!(f, "", &substs[..])?; } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 8e3b99f2dbf..9e9eb4a81d0 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -28,6 +28,7 @@ use rustc::hir::RangeEnd; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::mir::Field; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::util::common::ErrorReported; use syntax_pos::{Span, DUMMY_SP}; @@ -195,6 +196,41 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } })).collect() } + box PatternKind::Constant { + value: &ty::Const { val: ConstVal::Value(b), ty } + } => { + match b { + Value::ByVal(PrimVal::Ptr(ptr)) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + let alloc = tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap(); + assert_eq!(ptr.offset, 0); + // FIXME: check length + alloc.bytes.iter().map(|b| { + &*pattern_arena.alloc(Pattern { + ty: tcx.types.u8, + span: pat.span, + kind: box PatternKind::Constant { + value: tcx.mk_const(ty::Const { + val: ConstVal::Value(Value::ByVal( + PrimVal::Bytes(*b as u128), + )), + ty: tcx.types.u8 + }) + } + }) + }).collect() + }, + _ => bug!("not a byte str: {:?}", b), + } + } _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat) } }).clone() @@ -422,13 +458,17 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ty::TyBool => { [true, false].iter().map(|&b| { ConstantValue(cx.tcx.mk_const(ty::Const { - val: ConstVal::Bool(b), + val: if cx.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))) + } else { + ConstVal::Bool(b) + }, ty: cx.tcx.types.bool })) }).collect() } - ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + ty::TyArray(ref sub_ty, len) if len.val.to_u128().is_some() => { + let len = len.val.unwrap_u64(); if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { @@ -461,7 +501,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, } fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( - _cx: &mut MatchCheckCtxt<'a, 'tcx>, + cx: &mut MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64 where I: Iterator> { @@ -538,6 +578,25 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => { max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64); } + PatternKind::Constant { + value: &ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))), + ty, + } + } => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + if is_array_ptr { + let alloc = cx.tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap(); + max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); + } + } PatternKind::Slice { ref prefix, slice: None, ref suffix } => { let fixed_len = prefix.len() as u64 + suffix.len() as u64; max_fixed_len = cmp::max(max_fixed_len, fixed_len); @@ -581,7 +640,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; - debug!("is_useful({:?}, {:?})", matrix, v); + debug!("is_useful({:#?}, {:#?})", matrix, v); // The base case. We are pattern-matching on () and the return value is // based on whether our matrix has a row or not. @@ -626,10 +685,10 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))) }; - debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]); + debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - debug!("is_useful - expanding constructors: {:?}", constructors); + debug!("is_useful - expanding constructors: {:#?}", constructors); constructors.into_iter().map(|c| is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) ).find(|result| result.is_useful()).unwrap_or(NotUseful) @@ -639,9 +698,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let used_ctors: Vec = rows.iter().flat_map(|row| { pat_constructors(cx, row[0], pcx).unwrap_or(vec![]) }).collect(); - debug!("used_ctors = {:?}", used_ctors); + debug!("used_ctors = {:#?}", used_ctors); let all_ctors = all_constructors(cx, pcx); - debug!("all_ctors = {:?}", all_ctors); + debug!("all_ctors = {:#?}", all_ctors); let missing_ctors: Vec = all_ctors.iter().filter(|c| { !used_ctors.contains(*c) }).cloned().collect(); @@ -669,7 +728,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty); let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty); - debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}", + debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", missing_ctors, is_privately_empty, is_declared_nonexhaustive); // For privately empty and non-exhaustive enums, we work as if there were an "extra" @@ -769,7 +828,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( lty: Ty<'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { - debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty); + debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty); let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| { Pattern { @@ -821,7 +880,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, Some(vec![ConstantRange(lo, hi, end)]), PatternKind::Array { .. } => match pcx.ty.sty { ty::TyArray(_, length) => Some(vec![ - Slice(length.val.to_const_int().unwrap().to_u64().unwrap()) + Slice(length.val.unwrap_u64()) ]), _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) }, @@ -842,7 +901,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// A struct pattern's arity is the number of fields it contains, etc. fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 { - debug!("constructor_arity({:?}, {:?})", ctor, ty); + debug!("constructor_arity({:#?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs, _) => fs.len() as u64, ty::TySlice(..) | ty::TyArray(..) => match *ctor { @@ -866,12 +925,13 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor, ty: Ty<'tcx>) -> Vec> { - debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty); + debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(), ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(_) => vec![], + Single => vec![ty], _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) }, ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty], @@ -880,6 +940,9 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, // Use T as the sub pattern type of Box. vec![substs.type_at(0)] } else { + if let ConstantValue(_) = *ctor { + return vec![]; + } adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); @@ -901,14 +964,30 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, } } -fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, +fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, ctor: &Constructor, prefix: &[Pattern], slice: &Option, suffix: &[Pattern]) -> Result { - let data = match *ctor { + let data: &[u8] = match *ctor { ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data, + ConstantValue(&ty::Const { val: ConstVal::Value( + Value::ByVal(PrimVal::Ptr(ptr)) + ), ty }) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap() + .bytes + .as_ref() + } _ => bug!() }; @@ -928,6 +1007,12 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, return Ok(false); } }, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + assert_eq!(b as u8 as u128, b); + if b as u8 != *ch { + return Ok(false); + } + } _ => span_bug!(pat.span, "bad const u8 {:?}", value) }, _ => {} @@ -937,32 +1022,43 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, Ok(true) } -fn constructor_covered_by_range(tcx: TyCtxt, span: Span, - ctor: &Constructor, +fn constructor_covered_by_range(ctor: &Constructor, from: &ConstVal, to: &ConstVal, - end: RangeEnd) + end: RangeEnd, + ty: Ty) -> Result { - let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less); - let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to); + trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); + let cmp_from = |c_from| compare_const_vals(c_from, from, ty) + .map(|res| res != Ordering::Less); + let cmp_to = |c_to| compare_const_vals(c_to, to, ty); + macro_rules! some_or_ok { + ($e:expr) => { + match $e { + Some(to) => to, + None => return Ok(false), // not char or int + } + }; + } match *ctor { ConstantValue(value) => { - let to = cmp_to(&value.val)?; + let to = some_or_ok!(cmp_to(&value.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(&value.val)? && end) + Ok(some_or_ok!(cmp_from(&value.val)) && end) }, ConstantRange(from, to, RangeEnd::Included) => { - let to = cmp_to(&to.val)?; + let to = some_or_ok!(cmp_to(&to.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(&from.val)? && end) + Ok(some_or_ok!(cmp_from(&from.val)) && end) }, ConstantRange(from, to, RangeEnd::Excluded) => { - let to = cmp_to(&to.val)?; + let to = some_or_ok!(cmp_to(&to.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); - Ok(cmp_from(&from.val)? && end) + Ok(some_or_ok!(cmp_from(&from.val)) && end) } + Variant(_) | Single => Ok(true), _ => bug!(), } @@ -979,7 +1075,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( result[subpat.field.index()] = &subpat.pattern; } - debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result); + debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result); result } @@ -994,7 +1090,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( fn specialize<'p, 'a: 'p, 'tcx: 'a>( cx: &mut MatchCheckCtxt<'a, 'tcx>, r: &[&'p Pattern<'tcx>], - constructor: &Constructor, + constructor: &Constructor<'tcx>, wild_patterns: &[&'p Pattern<'tcx>]) -> Option>> { @@ -1031,12 +1127,32 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( None } } + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => { + let is_array_ptr = value.ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + assert!(is_array_ptr); + let data_len = cx.tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap() + .bytes + .len(); + if wild_patterns.len() == data_len { + Some(cx.lower_byte_str_pattern(pat)) + } else { + None + } + } _ => span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor) }, _ => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included + constructor, &value.val, &value.val, RangeEnd::Included, + value.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -1048,7 +1164,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone() + constructor, &lo.val, &hi.val, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -1092,7 +1208,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( } } }; - debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head); + debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head); head.map(|mut head| { head.extend_from_slice(&r[1 ..]); diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 2a571fa8264..58fe40d12be 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -26,7 +26,6 @@ use syntax::abi::Abi; use syntax::ast; use syntax::attr; use rustc::hir::{self, Expr}; -use syntax_pos::Span; use std::cmp::Ordering; @@ -104,60 +103,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, hir::ExprUnary(hir::UnNeg, ref inner) => { // unary neg literals already got their sign during creation if let hir::ExprLit(ref lit) = inner.node { - use syntax::ast::*; - use syntax::ast::LitIntType::*; - const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128; - const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128; - const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128; - const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128; - const I128_OVERFLOW: u128 = i128::min_value() as u128; - let negated = match (&lit.node, &ty.sty) { - (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) | - (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { - Some(I8(i8::min_value())) - }, - (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) | - (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { - Some(I16(i16::min_value())) - }, - (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) | - (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { - Some(I32(i32::min_value())) - }, - (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) | - (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { - Some(I64(i64::min_value())) - }, - (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) | - (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => { - Some(I128(i128::min_value())) - }, - (&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) | - (&LitKind::Int(n, Signed(IntTy::Isize)), _) => { - match tcx.sess.target.isize_ty { - IntTy::I16 => if n == I16_OVERFLOW { - Some(Isize(Is16(i16::min_value()))) - } else { - None - }, - IntTy::I32 => if n == I32_OVERFLOW { - Some(Isize(Is32(i32::min_value()))) - } else { - None - }, - IntTy::I64 => if n == I64_OVERFLOW { - Some(Isize(Is64(i64::min_value()))) - } else { - None - }, - _ => span_bug!(e.span, "typeck error") - } - }, - _ => None + return match lit_to_const(&lit.node, tcx, ty, true) { + Ok(val) => Ok(mk_const(val)), + Err(err) => signal!(e, err), }; - if let Some(i) = negated { - return Ok(mk_const(Integral(i))); - } } mk_const(match cx.eval(inner)?.val { Float(f) => Float(-f), @@ -377,7 +326,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }; callee_cx.eval(&body.value)? }, - hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) { + hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty, false) { Ok(val) => mk_const(val), Err(err) => signal!(e, err), }, @@ -438,7 +387,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } hir::ExprRepeat(ref elem, _) => { let n = match ty.sty { - ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(), + ty::TyArray(_, n) => n.val.unwrap_u64(), _ => span_bug!(e.span, "typeck error") }; mk_const(Aggregate(Repeat(cx.eval(elem)?, n))) @@ -447,7 +396,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, if let Aggregate(Tuple(fields)) = cx.eval(base)?.val { fields[index.node] } else { - signal!(base, ExpectedConstTuple); + span_bug!(base.span, "{:#?}", cx.eval(base)?.val); + //signal!(base, ExpectedConstTuple); } } hir::ExprField(ref base, field_name) => { @@ -557,7 +507,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }, ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { ty::TyArray(ty, n) => { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); if ty == tcx.types.u8 && n == b.data.len() as u64 { Ok(val) } else { @@ -583,13 +533,66 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, +pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut ty: Ty<'tcx>) + mut ty: Ty<'tcx>, + neg: bool) -> Result, ErrKind<'tcx>> { use syntax::ast::*; use syntax::ast::LitIntType::*; + if tcx.sess.opts.debugging_opts.miri { + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = tcx.allocate_cached(data); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + return Ok(ConstVal::Value(lit)); + } + if let ty::TyAdt(adt, _) = ty.sty { if adt.is_enum() { ty = adt.repr.discr_type().to_ty(tcx) @@ -604,26 +607,38 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, match (&ty.sty, hint) { (&ty::TyInt(ity), _) | (_, Signed(ity)) => { - Ok(Integral(ConstInt::new_signed_truncating(n as i128, + let mut n = n as i128; + if neg { + n = n.overflowing_neg().0; + } + Ok(Integral(ConstInt::new_signed_truncating(n, ity, tcx.sess.target.isize_ty))) } (&ty::TyUint(uty), _) | (_, Unsigned(uty)) => { - Ok(Integral(ConstInt::new_unsigned_truncating(n as u128, + Ok(Integral(ConstInt::new_unsigned_truncating(n, uty, tcx.sess.target.usize_ty))) } _ => bug!() } } LitKind::Float(n, fty) => { - parse_float(&n.as_str(), fty).map(Float) + let mut f = parse_float(&n.as_str(), fty)?; + if neg { + f = -f; + } + Ok(Float(f)) } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - parse_float(&n.as_str(), fty).map(Float) + let mut f = parse_float(&n.as_str(), fty)?; + if neg { + f = -f; + } + Ok(Float(f)) } LitKind::Bool(b) => Ok(Bool(b)), LitKind::Char(c) => Ok(Char(c)), @@ -638,36 +653,31 @@ fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) }) } -pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) - -> Result -{ - let result = match (a, b) { +pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { + trace!("compare_const_vals: {:?}, {:?}", a, b); + use rustc::mir::interpret::{Value, PrimVal}; + match (a, b) { (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(), - (&Float(a), &Float(b)) => a.try_cmp(b).ok(), - (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), - (&Bool(a), &Bool(b)) => Some(a.cmp(&b)), - (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)), (&Char(a), &Char(b)) => Some(a.cmp(&b)), + (&Value(Value::ByVal(PrimVal::Bytes(a))), + &Value(Value::ByVal(PrimVal::Bytes(b)))) => { + Some(if ty.is_signed() { + (a as i128).cmp(&(b as i128)) + } else { + a.cmp(&b) + }) + }, + _ if a == b => Some(Ordering::Equal), _ => None, - }; - - match result { - Some(result) => Ok(result), - None => { - // FIXME: can this ever be reached? - tcx.sess.delay_span_bug(span, - &format!("type mismatch comparing {:?} and {:?}", a, b)); - Err(ErrorReported) - } } } impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn compare_lit_exprs(&self, - span: Span, a: &'tcx Expr, - b: &'tcx Expr) -> Result { + b: &'tcx Expr) -> Result, ErrorReported> { let tcx = self.tcx; + let ty = self.tables.expr_ty(a); let a = match self.eval(a) { Ok(a) => a, Err(e) => { @@ -682,6 +692,6 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { return Err(ErrorReported); } }; - compare_const_vals(tcx, span, &a.val, &b.val) + Ok(compare_const_vals(&a.val, &b.val, ty)) } } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a09e2f2edd5..a2daf22c3b4 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -10,8 +10,9 @@ use eval; -use rustc::middle::const_val::{ConstEvalErr, ConstVal}; +use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate}; use rustc::mir::{Field, BorrowKind, Mutability}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; @@ -110,22 +111,35 @@ pub enum PatternKind<'tcx> { }, } -fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { - match *value { +fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { + match value.val { ConstVal::Float(ref x) => write!(f, "{}", x), ConstVal::Integral(ref i) => write!(f, "{}", i), ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]), ConstVal::ByteStr(b) => write!(f, "{:?}", b.data), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Value(v) => print_miri_value(v, value.ty, f), ConstVal::Variant(_) | ConstVal::Function(..) | ConstVal::Aggregate(_) | - ConstVal::Value(_) | ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } +fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result { + use rustc::ty::TypeVariants::*; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + _ => bug!("{:?}: {} not printable in a pattern", value, ty), + } +} + impl<'tcx> fmt::Display for Pattern<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.kind { @@ -233,15 +247,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { write!(f, "{}", subpattern) } PatternKind::Constant { value } => { - print_const_val(&value.val, f) + print_const_val(value, f) } PatternKind::Range { lo, hi, end } => { - print_const_val(&lo.val, f)?; + print_const_val(lo, f)?; match end { RangeEnd::Included => write!(f, "...")?, RangeEnd::Excluded => write!(f, "..")?, } - print_const_val(&hi.val, f) + print_const_val(hi, f) } PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Array { ref prefix, ref slice, ref suffix } => { @@ -362,7 +376,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Path(ref qpath) => { - return self.lower_path(qpath, pat.hir_id, pat.id, pat.span); + return self.lower_path(qpath, pat.hir_id, pat.span); } PatKind::Ref(ref subpattern, _) | @@ -581,7 +595,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyArray(_, len) => { // fixed-length array - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len = len.val.unwrap_u64(); assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } } @@ -632,7 +646,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_path(&mut self, qpath: &hir::QPath, id: hir::HirId, - pat_id: ast::NodeId, span: Span) -> Pattern<'tcx> { let ty = self.tables.node_id_to_type(id); @@ -644,29 +657,23 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); - match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) { - Some((def_id, substs)) => { - // Enter the inlined constant's tables&substs temporarily. - let old_tables = self.tables; - let old_substs = self.substs; - self.tables = self.tcx.typeck_tables_of(def_id); - self.substs = substs; - let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - self.tcx.hir.body(self.tcx.hir.body_owned_by(id)) - } else { - self.tcx.extern_const_body(def_id).body - }; - let pat = self.lower_const_expr(&body.value, pat_id, span); - self.tables = old_tables; - self.substs = old_substs; - return pat; - } - None => { - self.errors.push(if is_associated_const { - PatternError::AssociatedConstInPattern(span) - } else { - PatternError::StaticInPattern(span) - }); + match self.tcx.at(span).const_eval(self.param_env.and((def_id, substs))) { + Ok(value) => { + if self.tcx.sess.opts.debugging_opts.miri { + if let ConstVal::Value(_) = value.val {} else { + panic!("const eval produced non-miri value: {:#?}", value); + } + } + let instance = ty::Instance::resolve( + self.tcx, + self.param_env, + def_id, + substs, + ).unwrap(); + return self.const_to_pat(instance, value, span) + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(e)); PatternKind::Wild } } @@ -682,6 +689,52 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { + if self.tcx.sess.opts.debugging_opts.miri { + return match expr.node { + hir::ExprLit(ref lit) => { + let ty = self.tables.expr_ty(expr); + match ::eval::lit_to_const(&lit.node, self.tcx, ty, false) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, + } + }, + hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, + hir::ExprUnary(hir::UnNeg, ref expr) => { + let ty = self.tables.expr_ty(expr); + let lit = match expr.node { + hir::ExprLit(ref lit) => lit, + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + }; + match ::eval::lit_to_const(&lit.node, self.tcx, ty, true) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, + } + } + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + } + } let const_cx = eval::ConstContext::new(self.tcx, self.param_env.and(self.substs), self.tables); @@ -701,118 +754,156 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - fn lower_const_expr(&mut self, - expr: &'tcx hir::Expr, - pat_id: ast::NodeId, - span: Span) - -> Pattern<'tcx> { - let pat_ty = self.tables.expr_ty(expr); - debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id); - match pat_ty.sty { + fn const_to_pat( + &self, + instance: ty::Instance<'tcx>, + cv: &'tcx ty::Const<'tcx>, + span: Span, + ) -> Pattern<'tcx> { + debug!("const_to_pat: cv={:#?}", cv); + let kind = match cv.ty.sty { ty::TyFloat(_) => { self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns"); + PatternKind::Wild } ty::TyAdt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); + PatternKind::Wild } + ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => { + let msg = format!("to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + self.tcx.item_path_str(adt_def.did), + self.tcx.item_path_str(adt_def.did)); + self.tcx.sess.span_err(span, &msg); + PatternKind::Wild + }, + ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { + match cv.val { + ConstVal::Value(val) => { + let discr = self.tcx.const_discr(self.param_env.and(( + instance, val, cv.ty + ))).unwrap(); + let variant_index = adt_def + .discriminants(self.tcx) + .position(|var| var.to_u128_unchecked() == discr) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: adt_def + .variants[variant_index] + .fields + .iter() + .enumerate() + .map(|(i, _)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect(), + } + }, + ConstVal::Variant(var_did) => { + let variant_index = adt_def + .variants + .iter() + .position(|var| var.did == var_did) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: Vec::new(), + } + } + _ => return Pattern { + span, + ty: cv.ty, + kind: Box::new(PatternKind::Constant { + value: cv, + }), + } + } + }, ty::TyAdt(adt_def, _) => { - if !self.tcx.has_attr(adt_def.did, "structural_match") { - let msg = format!("to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - self.tcx.item_path_str(adt_def.did), - self.tcx.item_path_str(adt_def.did)); - self.tcx.sess.span_err(span, &msg); + let struct_var = adt_def.struct_variant(); + PatternKind::Leaf { + subpatterns: struct_var.fields.iter().enumerate().map(|(i, f)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Struct(consts)) => { + consts.iter().find(|&&(name, _)| name == f.name).unwrap().1 + }, + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect() } } - _ => { } - } - let kind = match expr.node { - hir::ExprTup(ref exprs) => { + ty::TyTuple(fields, _) => { PatternKind::Leaf { - subpatterns: exprs.iter().enumerate().map(|(i, expr)| { + subpatterns: (0..fields.len()).map(|i| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i], + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; FieldPattern { - field: Field::new(i), - pattern: self.lower_const_expr(expr, pat_id, span) + field, + pattern: self.const_to_pat(instance, val, span), } }).collect() } } - - hir::ExprCall(ref callee, ref args) => { - let qpath = match callee.node { - hir::ExprPath(ref qpath) => qpath, - _ => bug!() - }; - let ty = self.tables.node_id_to_type(callee.hir_id); - let def = self.tables.qpath_def(qpath, callee.hir_id); - match def { - Def::Fn(..) | Def::Method(..) => self.lower_lit(expr), - _ => { - let subpatterns = args.iter().enumerate().map(|(i, expr)| { - FieldPattern { - field: Field::new(i), - pattern: self.lower_const_expr(expr, pat_id, span) - } - }).collect(); - self.lower_variant_or_leaf(def, ty, subpatterns) - } + ty::TyArray(_, n) => { + PatternKind::Leaf { + subpatterns: (0..n.val.unwrap_u64()).map(|i| { + let i = i as usize; + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i], + ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv, + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect() } } - - hir::ExprStruct(ref qpath, ref fields, None) => { - let def = self.tables.qpath_def(qpath, expr.hir_id); - let adt_def = match pat_ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => { - span_bug!( - expr.span, - "struct expr without ADT type"); - } - }; - let variant_def = adt_def.variant_of_def(def); - - let subpatterns = - fields.iter() - .map(|field| { - let index = variant_def.index_of_field_named(field.name.node); - let index = index.unwrap_or_else(|| { - span_bug!( - expr.span, - "no field with name {:?}", - field.name); - }); - FieldPattern { - field: Field::new(index), - pattern: self.lower_const_expr(&field.expr, pat_id, span), - } - }) - .collect(); - - self.lower_variant_or_leaf(def, pat_ty, subpatterns) - } - - hir::ExprArray(ref exprs) => { - let pats = exprs.iter() - .map(|expr| self.lower_const_expr(expr, pat_id, span)) - .collect(); - PatternKind::Array { - prefix: pats, - slice: None, - suffix: vec![] + _ => { + PatternKind::Constant { + value: cv, } - } - - hir::ExprPath(ref qpath) => { - return self.lower_path(qpath, expr.hir_id, pat_id, span); - } - - _ => self.lower_lit(expr) + }, }; Pattern { span, - ty: pat_ty, + ty: cv.ty, kind: Box::new(kind), } } diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index d82b712b5b1..70733bc6aed 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -259,6 +259,14 @@ impl HashStable for f64 { } } +impl HashStable for ::std::cmp::Ordering { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (*self as i8).hash_stable(ctx, hasher); + } +} + impl, CTX> HashStable for (T1,) { fn hash_stable(&self, ctx: &mut CTX, diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1c4bd0ff4c2..f400ce42a90 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -16,6 +16,7 @@ use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; use middle::const_val::ConstVal; use rustc_const_eval::ConstContext; +use rustc::mir::interpret::{Value, PrimVal}; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -122,6 +123,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { .map(|i| i >= bits) .unwrap_or(true) } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + ty, + }) => { + if ty.is_signed() { + (b as i128) < 0 + } else { + b >= bits as u128 + } + } _ => false, } }; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3c3c489d0ff..1663cab0a59 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -276,38 +276,54 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { const MAX1: usize = usize::max_value() - 1; - let mut interpret_interner = self.tcx.unwrap().interpret_interner.borrow_mut(); + let tcx = self.tcx; + let interpret_interner = || tcx.unwrap().interpret_interner.borrow_mut(); let pos = self.position(); - match self.read_usize()? { + match usize::decode(self)? { ::std::usize::MAX => { + let id = interpret_interner().reserve(); + let alloc_id = interpret::AllocId(id); + trace!("creating alloc id {:?} at {}", alloc_id, pos); + // insert early to allow recursive allocs + self.interpret_alloc_cache.insert(pos, alloc_id); + let allocation = interpret::Allocation::decode(self)?; - let id = interpret_interner.reserve(); + trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); let allocation = self.tcx.unwrap().intern_const_alloc(allocation); - interpret_interner.intern_at_reserved(id, allocation); - let id = interpret::AllocId(id); - self.interpret_alloc_cache.insert(pos, id); + interpret_interner().intern_at_reserved(id, allocation); let num = usize::decode(self)?; let ptr = interpret::Pointer { primval: interpret::PrimVal::Ptr(interpret::MemoryPointer { - alloc_id: id, + alloc_id, offset: 0, }), }; for _ in 0..num { let glob = interpret::GlobalId::decode(self)?; - interpret_interner.cache(glob, ptr); + interpret_interner().cache(glob, ptr); } - Ok(id) + Ok(alloc_id) }, MAX1 => { + trace!("creating fn alloc id at {}", pos); let instance = ty::Instance::decode(self)?; - let id = interpret::AllocId(interpret_interner.create_fn_alloc(instance)); + trace!("decoded fn alloc instance: {:?}", instance); + let id = interpret::AllocId(interpret_interner().create_fn_alloc(instance)); + trace!("created fn alloc id: {:?}", id); self.interpret_alloc_cache.insert(pos, id); Ok(id) }, - shorthand => Ok(self.interpret_alloc_cache[&shorthand]), + shorthand => { + trace!("loading shorthand {}", shorthand); + if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) { + return Ok(alloc_id); + } + trace!("shorthand {} not cached, loading entire allocation", shorthand); + // need to load allocation + self.with_position(shorthand, |this| interpret::AllocId::decode(this)) + }, } } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 928bf0a56ae..1e1baba2bac 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -189,12 +189,18 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { + trace!("encoding {:?} at {}", alloc_id, self.position()); if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() { - return self.emit_usize(shorthand); + trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand); + return shorthand.encode(self); } let start = self.position(); + // cache the allocation shorthand now, because the allocation itself might recursively + // point to itself. + self.interpret_alloc_shorthands.insert(*alloc_id, start); let interpret_interner = self.tcx.interpret_interner.borrow(); if let Some(alloc) = interpret_interner.get_alloc(alloc_id.0) { + trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; let globals = interpret_interner.get_globals(interpret::Pointer { @@ -208,16 +214,12 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx glob.encode(self)?; } } else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id.0) { + trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; } else { bug!("alloc id without corresponding allocation: {}", alloc_id.0); } - let len = self.position() - start * 7; - // Check that the shorthand is a not longer than the - // full encoding itself, i.e. it's an obvious win. - assert!(len >= 64 || (start as u64) < (1 << len)); - self.interpret_alloc_shorthands.insert(*alloc_id, start); Ok(()) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index bbf4357e5b0..5955d0ca59a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -26,6 +26,7 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; use rustc::middle::const_val::ConstVal; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; use std::fmt; @@ -258,7 +259,24 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // constraints on `'a` and `'b`. These constraints // would be lost if we just look at the normalized // value. - if let ConstVal::Function(def_id, ..) = value.val { + let did = match value.val { + ConstVal::Function(def_id, ..) => Some(def_id), + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + self.tcx() + .interpret_interner + .borrow() + .get_fn(p.alloc_id.0) + .map(|instance| instance.def_id()) + }, + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { + match value.ty.sty { + ty::TyFnDef(ty_def_id, _) => Some(ty_def_id), + _ => None, + } + }, + _ => None, + }; + if let Some(def_id) = did { let tcx = self.tcx(); let type_checker = &mut self.cx; @@ -436,7 +454,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ProjectionElem::Subslice { from, to } => PlaceTy::Ty { ty: match base_ty.sty { ty::TyArray(inner, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let min_size = (from as u64) + (to as u64); if let Some(rest_size) = size.checked_sub(min_size) { tcx.mk_array(inner, rest_size) @@ -1019,13 +1037,32 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Literal::Value { value: &ty::Const { - val: ConstVal::Function(def_id, _), - .. + val, + ty, }, .. }, .. - }) => Some(def_id) == self.tcx().lang_items().box_free_fn(), + }) => match val { + ConstVal::Function(def_id, _) => { + Some(def_id) == self.tcx().lang_items().box_free_fn() + }, + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + let inst = self.tcx().interpret_interner.borrow().get_fn(p.alloc_id.0); + inst.map_or(false, |inst| { + Some(inst.def_id()) == self.tcx().lang_items().box_free_fn() + }) + }, + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { + match ty.sty { + ty::TyFnDef(ty_def_id, _) => { + Some(ty_def_id) == self.tcx().lang_items().box_free_fn() + } + _ => false, + } + } + _ => false, + } _ => false, } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index d3cc9527590..b5b8f8d7e78 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::ty::{self, Ty}; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use syntax::ast; use syntax_pos::Span; @@ -203,7 +204,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty: this.hir.tcx().types.u32, literal: Literal::Value { value: this.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U32(0)), + val: if this.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(ConstInt::U32(0)) + }, ty: this.hir.tcx().types.u32 }), }, @@ -401,7 +406,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.to_u128_unchecked()))) + } else { + ConstVal::Integral(val) + }, ty }) } @@ -439,7 +448,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes( + val.to_u128_unchecked() + ))) + } else { + ConstVal::Integral(val) + }, ty }) } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 58ce572ae8d..229e33dcd78 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -354,7 +354,7 @@ enum TestKind<'tcx> { // test the branches of enum SwitchInt { switch_ty: Ty<'tcx>, - options: Vec<&'tcx ty::Const<'tcx>>, + options: Vec, indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index bdcbfc0bdd8..fafdee5b1e1 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::ty::util::IntTypeExt; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::hir::RangeEnd; use syntax_pos::Span; use std::cmp::Ordering; @@ -112,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { test_place: &Place<'tcx>, candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, - options: &mut Vec<&'tcx ty::Const<'tcx>>, + options: &mut Vec, indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) -> bool { @@ -128,7 +129,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { indices.entry(value) .or_insert_with(|| { - options.push(value); + options.push(value.val.to_u128().expect("switching on int")); options.len() - 1 }); true @@ -231,7 +232,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); for (idx, discr) in adt_def.discriminants(tcx).enumerate() { target_blocks.place_back() <- if variants.contains(idx) { - values.push(discr); + values.push(discr.to_u128_unchecked()); *(targets.place_back() <- self.cfg.start_new_block()) } else { if otherwise_block.is_none() { @@ -266,9 +267,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(options.len() > 0 && options.len() <= 2); let (true_bb, false_bb) = (self.cfg.start_new_block(), self.cfg.start_new_block()); - let ret = match options[0].val { - ConstVal::Bool(true) => vec![true_bb, false_bb], - ConstVal::Bool(false) => vec![false_bb, true_bb], + let ret = match options[0] { + 1 => vec![true_bb, false_bb], + 0 => vec![false_bb, true_bb], v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()), @@ -282,13 +283,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|_| self.cfg.start_new_block()) .chain(Some(otherwise)) .collect(); - let values: Vec<_> = options.iter().map(|v| - v.val.to_const_int().expect("switching on integral") - ).collect(); (targets.clone(), TerminatorKind::SwitchInt { discr: Operand::Copy(place.clone()), switch_ty, - values: From::from(values), + values: options.clone().into(), targets, }) }; @@ -300,14 +298,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); let mut val = Operand::Copy(place.clone()); + let bytes = match value.val { + ConstVal::ByteStr(bytes) => Some(bytes.data), + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == self.hir.tcx().types.u8); + if is_array_ptr { + self.hir + .tcx() + .interpret_interner + .borrow() + .get_alloc(p.alloc_id.0) + .map(|alloc| &alloc.bytes[..]) + } else { + None + } + }, + _ => None, + }; // If we're using b"..." as a pattern, we need to insert an // unsizing coercion, as the byte string has the type &[u8; N]. // // We want to do this even when the scrutinee is a reference to an // array, so we can call `<[u8]>::eq` rather than having to find an // `<[u8; N]>::eq`. - let (expect, val) = if let ConstVal::ByteStr(bytes) = value.val { - let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64); + let expect = if let Some(bytes) = bytes { + let tcx = self.hir.tcx(); + + // Unsize the place to &[u8], too, if necessary. + if let ty::TyRef(region, mt) = ty.sty { + if let ty::TyArray(_, _) = mt.ty.sty { + ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); + let val_slice = self.temp(ty, test.span); + self.cfg.push_assign(block, source_info, &val_slice, + Rvalue::Cast(CastKind::Unsize, val, ty)); + val = Operand::Move(val_slice); + } + } + + assert!(ty.is_slice()); + + let array_ty = tcx.mk_array(tcx.types.u8, bytes.len() as u64); let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty); let array = self.literal_operand(test.span, array_ref, Literal::Value { value @@ -324,11 +357,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq. let fail = self.cfg.start_new_block(); - let ty = expect.ty(&self.local_decls, tcx); - if let ty::TyRef(_, mt) = ty.sty { - assert!(ty.is_slice()); + let str_or_bytestr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|tam| match tam.ty.sty { + ty::TyStr => Some(tam.ty), + ty::TySlice(inner) if inner == self.hir.tcx().types.u8 => Some(tam.ty), + _ => None, + }); + if let Some(ty) = str_or_bytestr { let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); - let ty = mt.ty; let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let bool_ty = self.hir.bool_ty(); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index a3350cb1671..efb36720118 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -16,6 +16,7 @@ use build::Builder; use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::*; use syntax::ast; @@ -62,7 +63,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty::TyChar => { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Char('\0'), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Char('\0') + }, ty }) } @@ -83,7 +88,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(val) + }, ty }) } @@ -104,7 +113,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(val) + }, ty }) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 00ab2e45995..198e55358e7 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -10,7 +10,6 @@ use hair::*; use rustc_data_structures::indexed_vec::Idx; -use rustc_const_math::ConstInt; use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; @@ -18,6 +17,7 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; use rustc::hir::def_id::LocalDefId; @@ -100,7 +100,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Deref { arg: expr.to_ref() } } Adjust::Deref(Some(deref)) => { - let call = deref.method_call(cx.tcx, expr.ty); + let call = deref.method_call(cx.tcx(), expr.ty); expr = Expr { temp_lifetime, @@ -314,7 +314,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, + hir::ExprLit(ref lit) => ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), + }, hir::ExprBinary(op, ref lhs, ref rhs) => { if cx.tables().is_method_call(expr) { @@ -400,9 +402,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, if cx.tables().is_method_call(expr) { overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { - // FIXME runtime-overflow - if let hir::ExprLit(_) = arg.node { - ExprKind::Literal { literal: cx.const_eval_literal(expr) } + if let hir::ExprLit(ref lit) = arg.node { + ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), + } } else { ExprKind::Unary { op: UnOp::Neg, @@ -509,8 +512,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let def_id = cx.tcx.hir.body_owner_def_id(count); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id); let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) { - Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u, - Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), + Ok(cv) => cv.val.unwrap_usize(cx.tcx), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") }; @@ -634,8 +636,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + value: cx.tcx().mk_const(ty::Const { + val: const_fn(cx.tcx, def_id, substs), ty }), }, @@ -675,6 +677,28 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) } } +fn const_fn<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, +) -> ConstVal<'tcx> { + if tcx.sess.opts.debugging_opts.miri { + /* + let inst = ty::Instance::new(def_id, substs); + let ptr = tcx + .interpret_interner + .borrow_mut() + .create_fn_alloc(inst); + let ptr = MemoryPointer::new(AllocId(ptr), 0); + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) + */ + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, substs) + } +} + fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) @@ -688,7 +712,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal { literal: Literal::Value { value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + val: const_fn(cx.tcx.global_tcx(), def_id, substs), ty: cx.tables().node_id_to_type(expr.hir_id) }), }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 44c41356117..7ebed0bbddb 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -17,7 +17,6 @@ use hair::*; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; -use rustc_const_eval::ConstContext; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; @@ -32,6 +31,7 @@ use syntax::symbol::Symbol; use rustc::hir; use rustc_const_math::{ConstInt, ConstUsize}; use rustc_data_structures::sync::Lrc; +use rustc::mir::interpret::{Value, PrimVal}; #[derive(Clone)] pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { @@ -119,7 +119,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { Ok(val) => { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(val)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))) + } else { + ConstVal::Integral(ConstInt::Usize(val)) + }, ty: self.tcx.types.usize }) } @@ -139,7 +143,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn true_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(true), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))) + } else { + ConstVal::Bool(true) + }, ty: self.tcx.types.bool }) } @@ -148,20 +156,161 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn false_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(false), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Bool(false) + }, ty: self.tcx.types.bool }) } } - pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> { + pub fn const_eval_literal( + &mut self, + lit: &'tcx ast::LitKind, + ty: Ty<'tcx>, + sp: Span, + neg: bool, + ) -> Literal<'tcx> { let tcx = self.tcx.global_tcx(); - let const_cx = ConstContext::new(tcx, - self.param_env.and(self.identity_substs), - self.tables()); - match const_cx.eval(tcx.hir.expect_expr(e.id)) { - Ok(value) => Literal::Value { value }, - Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") + + let mut repr_ty = ty; + if let ty::TyAdt(adt, _) = ty.sty { + if adt.is_enum() { + repr_ty = adt.repr.discr_type().to_ty(tcx) + } + } + + let parse_float = |num: &str, fty| -> ConstFloat { + ConstFloat::from_str(num, fty).unwrap_or_else(|_| { + // FIXME(#31407) this is only necessary because float parsing is buggy + tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)"); + }) + }; + + if tcx.sess.opts.debugging_opts.miri { + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = self.tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = self.tcx.allocate_cached(data); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)), + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty); + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty); + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + return Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: Value(lit), + ty, + }), + }; + } + + use syntax::ast::*; + use syntax::ast::LitIntType::*; + use rustc::middle::const_val::ConstVal::*; + use rustc_const_math::ConstInt::*; + use rustc::ty::util::IntTypeExt; + use rustc::middle::const_val::ByteArray; + use rustc_const_math::ConstFloat; + + let lit = match *lit { + LitKind::Str(ref s, _) => Ok(Str(s.as_str())), + LitKind::ByteStr(ref data) => { + let data: &'tcx [u8] = data; + Ok(ByteStr(ByteArray { data })) + }, + LitKind::Byte(n) => Ok(Integral(U8(n))), + LitKind::Int(n, hint) => { + match (&repr_ty.sty, hint) { + (&ty::TyInt(ity), _) | + (_, Signed(ity)) => { + let mut n = n as i128; + if neg { + n = n.overflowing_neg().0; + } + Ok(Integral(ConstInt::new_signed_truncating(n, + ity, tcx.sess.target.isize_ty))) + } + (&ty::TyUint(uty), _) | + (_, Unsigned(uty)) => { + Ok(Integral(ConstInt::new_unsigned_truncating(n, + uty, tcx.sess.target.usize_ty))) + } + _ => bug!() + } + } + LitKind::Float(n, fty) => { + let mut f = parse_float(&n.as_str(), fty); + if neg { + f = -f; + } + Ok(ConstVal::Float(f)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let mut f = parse_float(&n.as_str(), fty); + if neg { + f = -f; + } + Ok(ConstVal::Float(f)) + } + LitKind::Bool(b) => Ok(Bool(b)), + LitKind::Char(c) => Ok(Char(c)), + }; + + match lit { + Ok(value) => Literal::Value { value: self.tcx.mk_const(ty::Const { + val: value, + ty, + }) }, + Err(kind) => self.fatal_const_eval_err(&ConstEvalErr { + span: sp, + kind, + }, sp, "expression") } } @@ -203,7 +352,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { return (method_ty, Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Function(item.def_id, substs), + val: if self.tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(item.def_id, substs) + }, ty: method_ty }), }); diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index bc555368f0f..ec8215fb64c 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -13,14 +13,13 @@ use syntax::ast::Mutability; use syntax::codemap::Span; use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; -use super::{Place, EvalContext, StackPopCleanup, ValTy}; +use super::{Place, EvalContext, StackPopCleanup, ValTy, HasMemory}; use rustc_const_math::ConstInt; use std::fmt; use std::error::Error; - pub fn mk_eval_cx<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, @@ -45,7 +44,7 @@ pub fn eval_body<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> { +) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { debug!("eval_body: {:?}, {:?}", instance, param_env); let limits = super::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); @@ -82,7 +81,13 @@ pub fn eval_body<'a, 'tcx>( while ecx.step()? {} } let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); - Ok((MemoryPointer::new(alloc, 0).into(), instance_ty)) + let align = ecx.layout_of(instance_ty)?.align; + let ptr = MemoryPointer::new(alloc, 0).into(); + let value = match ecx.try_read_value(ptr, align, instance_ty)? { + Some(val) => val, + _ => Value::ByRef(ptr, align), + }; + Ok((value, ptr, instance_ty)) } pub fn eval_body_as_integer<'a, 'tcx>( @@ -90,11 +95,9 @@ pub fn eval_body_as_integer<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, instance: Instance<'tcx>, ) -> EvalResult<'tcx, ConstInt> { - let ptr_ty = eval_body(tcx, instance, param_env); - let (ptr, ty) = ptr_ty?; - let ecx = mk_eval_cx(tcx, instance, param_env)?; - let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? { - Some(Value::ByVal(prim)) => prim.to_bytes()?, + let (value, _, ty) = eval_body(tcx, instance, param_env)?; + let prim = match value { + Value::ByVal(prim) => prim.to_bytes()?, _ => return err!(TypeNotPrimitive(ty)), }; use syntax::ast::{IntTy, UintTy}; @@ -133,7 +136,7 @@ pub struct CompileTimeEvaluator; impl<'tcx> Into> for ConstEvalError { fn into(self) -> EvalError<'tcx> { - EvalErrorKind::MachineError(Box::new(self)).into() + EvalErrorKind::MachineError(self.to_string()).into() } } @@ -193,7 +196,6 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { let mir = match ecx.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - // some simple things like `malloc` might get accepted in the future return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -302,6 +304,70 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { } } +pub fn const_val_field<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, +) -> ::rustc::middle::const_val::EvalResult<'tcx> { + trace!("const_val_field: {:#?}", key); + match const_val_field_inner(tcx, key) { + Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(field), + ty, + })), + Err(err) => Err(ConstEvalErr { + span: tcx.def_span(key.value.0.def_id()), + kind: err.into(), + }), + } +} + +fn const_val_field_inner<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, +) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> { + trace!("const_val_field: {:#?}", key); + let (instance, field, value, ty) = key.value; + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let (mut field, ty) = match value { + Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"), + Value::ByRef(ptr, align) => { + let place = Place::from_primval_ptr(ptr, align); + let layout = ecx.layout_of(ty)?; + let (place, layout) = ecx.place_field(place, field, layout)?; + let (ptr, align) = place.to_ptr_align(); + (Value::ByRef(ptr, align), layout.ty) + } + }; + if let Value::ByRef(ptr, align) = field { + if let Some(val) = ecx.try_read_value(ptr, align, ty)? { + field = val; + } + } + Ok((field, ty)) +} + +pub fn const_discr<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, Value, Ty<'tcx>)>, +) -> EvalResult<'tcx, u128> { + trace!("const_discr: {:#?}", key); + let (instance, value, ty) = key.value; + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let (ptr, align) = match value { + Value::ByValPair(..) | Value::ByVal(_) => { + let layout = ecx.layout_of(ty)?; + use super::MemoryKind; + let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?; + let ptr: Pointer = ptr.into(); + ecx.write_value_to_ptr(value, ptr, layout.align, ty)?; + (ptr, layout.align) + }, + Value::ByRef(ptr, align) => (ptr, align), + }; + let place = Place::from_primval_ptr(ptr, align); + ecx.read_discriminant_value(place, ty) +} + pub fn const_eval_provider<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>, @@ -340,35 +406,48 @@ pub fn const_eval_provider<'a, 'tcx>( return Err(ConstEvalErr { span: body.value.span, kind: TypeckError }) } + + let instance = ty::Instance::new(def_id, substs); + if tcx.sess.opts.debugging_opts.miri { + return match ::interpret::eval_body(tcx, instance, key.param_env) { + Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(miri_value), + ty: miri_ty, + })), + Err(err) => { + Err(ConstEvalErr { span: body.value.span, kind: err.into() }) + } + }; + } + trace!("running old const eval"); let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value); trace!("old const eval produced {:?}", old_result); - if tcx.sess.opts.debugging_opts.miri { - let instance = ty::Instance::new(def_id, substs); - trace!("const eval instance: {:?}, {:?}", instance, key.param_env); - let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); - match (miri_result, old_result) { - (Err(err), Ok(ok)) => { - trace!("miri failed, ctfe returned {:?}", ok); - tcx.sess.span_warn( - tcx.def_span(key.value.0), - "miri failed to eval, while ctfe succeeded", - ); - let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let () = unwrap_miri(&ecx, Err(err)); - Ok(ok) - }, - (_, Err(err)) => Err(err), - (Ok((miri_val, miri_ty)), Ok(ctfe)) => { - let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let layout = ecx.layout_of(miri_ty).unwrap(); - let miri_place = Place::from_primval_ptr(miri_val, layout.align); - check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); - Ok(ctfe) - } + trace!("const eval instance: {:?}, {:?}", instance, key.param_env); + let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); + match (miri_result, old_result) { + (Err(err), Ok(ok)) => { + trace!("miri failed, ctfe returned {:?}", ok); + tcx.sess.span_warn( + tcx.def_span(key.value.0), + "miri failed to eval, while ctfe succeeded", + ); + let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let () = unwrap_miri(&ecx, Err(err)); + Ok(ok) + }, + (Ok((value, _, ty)), Err(_)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(value), + ty, + })), + (Err(_), Err(err)) => Err(err), + (Ok((_, miri_ptr, miri_ty)), Ok(ctfe)) => { + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let layout = ecx.layout_of(miri_ty).unwrap(); + let miri_place = Place::from_primval_ptr(miri_ptr, layout.align); + check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); + Ok(ctfe) } - } else { - old_result } } @@ -451,7 +530,7 @@ fn check_ctfe_against_miri<'a, 'tcx>( } }, TyArray(elem_ty, n) => { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe { ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| { (ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e9e8ccd03b1..f37fb3072b5 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -601,7 +601,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Repeat(ref operand, _) => { let (elem_ty, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()), + ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()), _ => { bug!( "tried to assign array-repeat to non-array type {:?}", @@ -1386,7 +1386,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let ptr = self.into_ptr(src)?; // u64 cast is from usize to u64, which is always good let valty = ValTy { - value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ), + value: ptr.to_value_with_len(length.val.unwrap_u64() ), ty: dest_ty, }; self.write_value(valty, dest) diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index fee62c8a82e..a6ebdd45968 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,6 +18,6 @@ pub use self::place::{Place, PlaceExtra}; pub use self::memory::{Memory, MemoryKind, HasMemory}; -pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider}; +pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, const_discr}; pub use self::machine::Machine; diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 6ab1aec38b8..b20540b00ce 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -248,10 +248,15 @@ pub fn unary_op<'tcx>( (Not, I64) => !(bytes as i64) as u128, (Not, I128) => !(bytes as i128) as u128, + (Neg, I8) if bytes == i8::min_value() as u128 => return err!(OverflowingMath), (Neg, I8) => -(bytes as i8) as u128, + (Neg, I16) if bytes == i16::min_value() as u128 => return err!(OverflowingMath), (Neg, I16) => -(bytes as i16) as u128, + (Neg, I32) if bytes == i32::min_value() as u128 => return err!(OverflowingMath), (Neg, I32) => -(bytes as i32) as u128, + (Neg, I64) if bytes == i64::min_value() as u128 => return err!(OverflowingMath), (Neg, I64) => -(bytes as i64) as u128, + (Neg, I128) if bytes == i128::min_value() as u128 => return err!(OverflowingMath), (Neg, I128) => -(bytes as i128) as u128, (Neg, F32) => (-bytes_to_f32(bytes)).bits, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 701b7a07ac9..c5e4eeab867 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -71,7 +71,7 @@ impl<'tcx> Place { pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { match ty.sty { - ty::TyArray(elem, n) => (elem, n.val.to_const_int().unwrap().to_u64().unwrap() as u64), + ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64), ty::TySlice(elem) => { match self { @@ -115,6 +115,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } + pub fn read_field( + &self, + base: Value, + field: mir::Field, + base_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> { + let base_layout = self.layout_of(base_ty)?; + let field_index = field.index(); + let field = base_layout.field(self, field_index)?; + let offset = base_layout.fields.offset(field_index); + match base { + // the field covers the entire type + Value::ByValPair(..) | + Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))), + // split fat pointers, 2 element tuples, ... + Value::ByValPair(a, b) if base_layout.fields.count() == 2 => { + let val = [a, b][field_index]; + Ok(Some((Value::ByVal(val), field.ty))) + }, + _ => Ok(None), + } + } + fn try_read_place_projection( &mut self, proj: &mir::PlaceProjection<'tcx>, @@ -126,23 +149,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }; let base_ty = self.place_ty(&proj.base); match proj.elem { - Field(field, _) => { - let base_layout = self.layout_of(base_ty)?; - let field_index = field.index(); - let field = base_layout.field(&self, field_index)?; - let offset = base_layout.fields.offset(field_index); - match base { - // the field covers the entire type - Value::ByValPair(..) | - Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some(base)), - // split fat pointers, 2 element tuples, ... - Value::ByValPair(a, b) if base_layout.fields.count() == 2 => { - let val = [a, b][field_index]; - Ok(Some(Value::ByVal(val))) - }, - _ => Ok(None), - } - }, + Field(field, _) => Ok(self.read_field(base, field, base_ty)?.map(|(f, _)| f)), // The NullablePointer cases should work fine, need to take care for normal enums Downcast(..) | Subslice { .. } | diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 606bda51edb..c18cf6d9f96 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -45,8 +45,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // Branch to the `otherwise` case by default, if no match is found. let mut target_block = targets[targets.len() - 1]; - for (index, const_int) in values.iter().enumerate() { - let prim = PrimVal::Bytes(const_int.to_u128_unchecked()); + for (index, &const_int) in values.iter().enumerate() { + let prim = PrimVal::Bytes(const_int); if discr_prim.to_bytes()? == prim.to_bytes()? { target_block = targets[index]; break; diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 38b8ffc6b9c..1f7f1237ba7 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -314,7 +314,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.push('['); self.push_type_name(inner_type, output); write!(output, "; {}", - len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap(); + len.val.unwrap_u64()).unwrap(); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index e6ebdd3d6c1..11dded1d3f0 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; use rustc_const_math::{ConstInt, ConstUsize}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -303,7 +304,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match self_ty.sty { _ if is_copy => builder.copy_shim(), ty::TyArray(ty, len) => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len = len.val.unwrap_u64(); builder.array_shim(dest, src, ty, len) } ty::TyClosure(def_id, substs) => { @@ -443,7 +444,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ty: func_ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(self.def_id, substs), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(self.def_id, substs) + }, ty: func_ty }), }, @@ -501,13 +507,20 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { } fn make_usize(&self, value: u64) -> Box> { - let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap(); box Constant { span: self.span, ty: self.tcx.types.usize, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(value)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))) + } else { + let value = ConstUsize::new( + value, + self.tcx.sess.target.usize_ty, + ).unwrap(); + ConstVal::Integral(ConstInt::Usize(value)) + }, ty: self.tcx.types.usize, }) } @@ -739,8 +752,12 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, - Substs::identity_for_item(tcx, def_id)), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, Substs::identity_for_item(tcx, def_id)) + }, ty }), }, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 04ebaa031fe..ec3edb1e068 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -80,6 +80,7 @@ use transform::simplify; use transform::no_landing_pads::no_landing_pads; use dataflow::{do_dataflow, DebugFormatted, state_for_location}; use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals}; +use rustc::mir::interpret::{Value, PrimVal}; pub struct StateTransform; @@ -181,7 +182,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { ty: self.tcx.types.u32, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U32(state_disc)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))) + } else { + ConstVal::Integral(ConstInt::U32(state_disc)) + }, ty: self.tcx.types.u32 }), }, @@ -534,7 +539,7 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let switch = TerminatorKind::SwitchInt { discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)), switch_ty: tcx.types.u32, - values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::>()), + values: Cow::from(cases.iter().map(|&(i, _)| i.into()).collect::>()), targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(), }; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 64c702b99cd..b8a0e0f8907 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -207,6 +207,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { return false; } + // Do not inline {u,i}128 lang items, trans const eval depends + // on detecting calls to these lang items and intercepting them + if tcx.is_binop_lang_item(callsite.callee).is_some() { + debug!(" not inlining 128bit integer lang item"); + return false; + } + let trans_fn_attrs = tcx.trans_fn_attrs(callsite.callee); let hinted = match trans_fn_attrs.inline { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8f5831270d6..88618122e4f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -690,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { _ => false } } else if let ty::TyArray(_, len) = ty.sty { - len.val.to_const_int().unwrap().to_u64().unwrap() == 0 && + len.val.unwrap_u64() == 0 && self.mode == Mode::Fn } else { false diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 41089f567bd..ca7f573b58a 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -40,10 +40,10 @@ impl MirPass for SimplifyBranches { TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant { literal: Literal::Value { ref value }, .. }), ref values, ref targets, .. } => { - if let Some(ref constint) = value.val.to_const_int() { + if let Some(constint) = value.val.to_u128() { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; - for (v, t) in values.iter().zip(targets.iter()) { + for (&v, t) in values.iter().zip(targets.iter()) { if v == constint { ret = TerminatorKind::Goto { target: *t }; break; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index e2feb0ed390..77ef2c20117 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -11,13 +11,14 @@ use std::fmt; use rustc::hir; use rustc::mir::*; -use rustc::middle::const_val::{ConstInt, ConstVal}; +use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Substs}; use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use util::patch::MirPatch; +use rustc::mir::interpret::{Value, PrimVal}; use std::{iter, u32}; @@ -425,7 +426,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> variant_path, &adt.variants[variant_index], substs); - values.push(discr); + values.push(discr.to_u128().unwrap()); if let Unwind::To(unwind) = unwind { // We can't use the half-ladder from the original // drop ladder, because this breaks the @@ -480,7 +481,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn adt_switch_block(&mut self, adt: &'tcx ty::AdtDef, blocks: Vec, - values: &[ConstInt], + values: &[u128], succ: BasicBlock, unwind: Unwind) -> BasicBlock { @@ -803,7 +804,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) } ty::TyArray(ety, size) => self.open_drop_for_array( - ety, size.val.to_const_int().and_then(|v| v.to_u64())), + ety, size.val.to_u128().map(|i| i as u64)), ty::TySlice(ety) => self.open_drop_for_array(ety, None), _ => bug!("open drop from non-ADT `{:?}`", ty) @@ -949,7 +950,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty: self.tcx().types.usize, literal: Literal::Value { value: self.tcx().mk_const(ty::Const { - val: ConstVal::Integral(self.tcx().const_usize(val)), + val: if self.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))) + } else { + ConstVal::Integral(self.tcx().const_usize(val)) + }, ty: self.tcx().types.usize }) } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b93b759fdf8..8153c3c8493 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -129,6 +129,9 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } fn check_const_eval(&self, expr: &'gcx hir::Expr) { + if self.tcx.sess.opts.debugging_opts.miri { + return; + } if let Err(err) = self.const_cx().eval(expr) { match err.kind { UnimplementedConstVal(_) => {} @@ -220,23 +223,24 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.check_const_eval(lit); } PatKind::Range(ref start, ref end, RangeEnd::Excluded) => { - match self.const_cx().compare_lit_exprs(p.span, start, end) { - Ok(Ordering::Less) => {} - Ok(Ordering::Equal) | - Ok(Ordering::Greater) => { + match self.const_cx().compare_lit_exprs(start, end) { + Ok(Some(Ordering::Less)) => {} + Ok(Some(Ordering::Equal)) | + Ok(Some(Ordering::Greater)) => { span_err!(self.tcx.sess, start.span, E0579, "lower range bound must be less than upper"); } + Ok(None) => bug!("ranges must be char or int"), Err(ErrorReported) => {} } } PatKind::Range(ref start, ref end, RangeEnd::Included) => { - match self.const_cx().compare_lit_exprs(p.span, start, end) { - Ok(Ordering::Less) | - Ok(Ordering::Equal) => {} - Ok(Ordering::Greater) => { + match self.const_cx().compare_lit_exprs(start, end) { + Ok(Some(Ordering::Less)) | + Ok(Some(Ordering::Equal)) => {} + Ok(Some(Ordering::Greater)) => { let mut err = struct_span_err!( self.tcx.sess, start.span, @@ -252,6 +256,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { } err.emit(); } + Ok(None) => bug!("ranges must be char or int"), Err(ErrorReported) => {} } } @@ -308,7 +313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.promotable = false; } - if self.in_fn && self.promotable { + if self.in_fn && self.promotable && !self.tcx.sess.opts.debugging_opts.miri { match self.const_cx().eval(ex) { Ok(_) => {} Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) | diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 3708f6f6ec4..314b8c59df5 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -195,7 +195,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, let (source, target) = cx.tcx.struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { (&ty::TyArray(_, len), &ty::TySlice(_)) => { - C_usize(cx, len.val.to_const_int().unwrap().to_u64().unwrap()) + C_usize(cx, len.val.unwrap_u64()) } (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { // For now, upcasts are limited to changes in marker diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 2c430d03c96..0fe425fb7ea 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -276,7 +276,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let upper_bound = match array_or_slice_type.sty { ty::TyArray(_, len) => { - len.val.to_const_int().unwrap().to_u64().unwrap() as c_longlong + len.val.unwrap_u64() as c_longlong } _ => -1 }; diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 6490d109f29..a88eb9ae354 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::TyArray(inner_type, len) => { output.push('['); push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap())); + output.push_str(&format!("; {}", len.val.unwrap_u64())); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index f683703ce6d..c88e39d7824 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir::{self, Location, TerminatorKind, Literal}; use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::mir::traversal; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty; use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; @@ -109,15 +110,26 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { - match *kind { + let check = match *kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(box mir::Constant { literal: Literal::Value { - value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, .. + value: &ty::Const { val, ty }, .. }, .. }), ref args, .. - } if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() => { + } => match val { + ConstVal::Function(def_id, _) => Some((def_id, args)), + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => match ty.sty { + ty::TyFnDef(did, _) => Some((did, args)), + _ => None, + }, + _ => None, + } + _ => None, + }; + if let Some((def_id, args)) = check { + if Some(def_id) == self.cx.ccx.tcx().lang_items().box_free_fn() { // box_free(x) shares with `drop x` the property that it // is not guaranteed to be statically dominated by the // definition of x, so x must always be in an alloca. @@ -125,7 +137,6 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { self.visit_place(place, PlaceContext::Drop, location); } } - _ => {} } self.super_terminator_kind(block, kind, location); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index bb2a7840fae..239300c1ecf 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -10,7 +10,7 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc::middle::lang_items; -use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind}; +use rustc::middle::const_val::{ConstEvalErr, ErrKind}; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; use rustc::traits; @@ -196,17 +196,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if switch_ty == bx.tcx().types.bool { let lltrue = llblock(self, targets[0]); let llfalse = llblock(self, targets[1]); - if let [ConstInt::U8(0)] = values[..] { + if let [0] = values[..] { bx.cond_br(discr.immediate(), llfalse, lltrue); } else { + assert_eq!(&values[..], &[1]); bx.cond_br(discr.immediate(), lltrue, llfalse); } } else { let (otherwise, targets) = targets.split_last().unwrap(); let switch = bx.switch(discr.immediate(), llblock(self, *otherwise), values.len()); - for (value, target) in values.iter().zip(targets) { - let val = Const::from_constint(bx.cx, value); + for (&value, target) in values.iter().zip(targets) { + let val = Const::from_bytes(bx.cx, value, switch_ty); let llbb = llblock(self, *target); bx.add_case(switch, val.llval, llbb) } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index c853230b15a..5bd5f19a57c 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -16,6 +16,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::traits; use rustc::mir; +use rustc::mir::interpret::{Value as MiriValue, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf, Size}; @@ -38,6 +39,7 @@ use value::Value; use syntax_pos::Span; use syntax::ast; +use syntax::symbol::Symbol; use std::fmt; use std::ptr; @@ -81,12 +83,46 @@ impl<'a, 'tcx> Const<'tcx> { Const { llval: llval, ty: ty } } + pub fn from_bytes(ccx: &CrateContext<'a, 'tcx>, b: u128, ty: Ty<'tcx>) -> Const<'tcx> { + let llval = match ty.sty { + ty::TyInt(ast::IntTy::I128) | + ty::TyUint(ast::UintTy::U128) => C_uint_big(Type::i128(ccx), b), + ty::TyInt(i) => C_int(Type::int_from_ty(ccx, i), b as i128 as i64), + ty::TyUint(u) => C_uint(Type::uint_from_ty(ccx, u), b as u64), + ty::TyBool => { + assert!(b <= 1); + C_bool(ccx, b == 1) + }, + ty::TyChar => { + assert_eq!(b as u32 as u128, b); + let c = b as u32; + assert!(::std::char::from_u32(c).is_some()); + C_uint(Type::char(ccx), c as u64) + }, + ty::TyFloat(fty) => { + let llty = ccx.layout_of(ty).llvm_type(ccx); + let bits = match fty { + ast::FloatTy::F32 => C_u32(ccx, b as u32), + ast::FloatTy::F64 => C_u64(ccx, b as u64), + }; + consts::bitcast(bits, llty) + }, + ty::TyAdt(adt, _) if adt.is_enum() => { + use rustc::ty::util::IntTypeExt; + Const::from_bytes(ccx, b, adt.repr.discr_type().to_ty(ccx.tcx())).llval + }, + _ => bug!("from_bytes({}, {})", b, ty), + }; + Const { llval, ty } + } + /// Translate ConstVal into a LLVM constant value. pub fn from_constval(cx: &CodegenCx<'a, 'tcx>, cv: &ConstVal, ty: Ty<'tcx>) -> Const<'tcx> { let llty = cx.layout_of(ty).llvm_type(cx); + trace!("from_constval: {:#?}: {}", cv, ty); let val = match *cv { ConstVal::Float(v) => { let bits = match v.ty { @@ -108,7 +144,41 @@ impl<'a, 'tcx> Const<'tcx> { ConstVal::Unevaluated(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } - ConstVal::Value(_) => unimplemented!(), + ConstVal::Value(MiriValue::ByRef(..)) => unimplemented!("{:#?}:{}", cv, ty), + ConstVal::Value(MiriValue::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) => { + match ty.sty { + ty::TyRef(_, ref tam) => match tam.ty.sty { + ty::TyStr => {}, + _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), + }, + _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), + } + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + C_str_slice(ccx, Symbol::intern(s).as_str()) + }, + ConstVal::Value(MiriValue::ByValPair(..)) => unimplemented!(), + ConstVal::Value(MiriValue::ByVal(PrimVal::Bytes(b))) => + return Const::from_bytes(ccx, b, ty), + ConstVal::Value(MiriValue::ByVal(PrimVal::Undef)) => C_undef(llty), + ConstVal::Value(MiriValue::ByVal(PrimVal::Ptr(ptr))) => { + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + let data = &alloc.bytes[(ptr.offset as usize)..]; + consts::addr_of(ccx, C_bytes(ccx, data), ccx.align_of(ty), "byte_str") + } }; assert!(!ty.has_erasable_regions()); @@ -239,7 +309,7 @@ impl<'tcx> ConstPlace<'tcx> { pub fn len<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef { match self.ty.sty { ty::TyArray(_, n) => { - C_usize(cx, n.val.to_const_int().unwrap().to_u64().unwrap()) + C_usize(cx, n.val.unwrap_u64()) } ty::TySlice(_) | ty::TyStr => { assert!(self.llextra != ptr::null_mut()); @@ -316,7 +386,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let tcx = self.cx.tcx; let mut bb = mir::START_BLOCK; - // Make sure to evaluate all statemenets to + // Make sure to evaluate all statements to // report as many errors as we possibly can. let mut failure = Ok(()); @@ -392,6 +462,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { _ => span_bug!(span, "calling {:?} (of type {}) in constant", func, fn_ty) }; + trace!("trans const fn call {:?}, {:?}, {:#?}", func, fn_ty, args); let mut arg_vals = IndexVec::with_capacity(args.len()); for arg in args { @@ -419,7 +490,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } _ => span_bug!(span, "{:?} in constant", terminator.kind) } - } else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) { + } else if let Some((op, is_checked)) = tcx.is_binop_lang_item(def_id) { (||{ assert_eq!(arg_vals.len(), 2); let rhs = arg_vals.pop().unwrap()?; @@ -470,37 +541,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } - fn is_binop_lang_item(&mut self, def_id: DefId) -> Option<(mir::BinOp, bool)> { - let tcx = self.cx.tcx; - let items = tcx.lang_items(); - let def_id = Some(def_id); - if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } - else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } - else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } - else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } - else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } - else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } - else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } - else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } - else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } - else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } - else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } - else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } - else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } - else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } - else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } - else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } - else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } - else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } - else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } - else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } - else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } - else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } - else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } - else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } - else { None } - } - fn store(&mut self, dest: &mir::Place<'tcx>, value: Result, ConstEvalErr<'tcx>>, diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 34ac44cec02..b0cb7de824e 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let mir::Place::Local(index) = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::TyArray(_, n) = op.layout.ty.sty { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); return common::C_usize(bx.cx, n); } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a261c12bcdd..eb02c05fd39 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -413,7 +413,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::TyArray(inner_ty, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let min_len = before.len() as u64 + after.len() as u64; if slice.is_none() { if min_len != size { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0f59973eab2..26b96493310 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4029,9 +4029,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Ok(count) = count { - let zero_or_one = count.val.to_const_int().and_then(|count| { - count.to_u64().map(|count| count <= 1) - }).unwrap_or(false); + let zero_or_one = count.val.to_u128().map_or(false, |count| count <= 1); if !zero_or_one { // For [foo, ..n] where n > 1, `foo` must have // Copy type: diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 12791107ebb..47a229cbd3b 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -447,10 +447,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiBitOr => ("bitor", lang.bitor_trait()), hir::BiShl => ("shl", lang.shl_trait()), hir::BiShr => ("shr", lang.shr_trait()), - hir::BiLt => ("lt", lang.ord_trait()), - hir::BiLe => ("le", lang.ord_trait()), - hir::BiGe => ("ge", lang.ord_trait()), - hir::BiGt => ("gt", lang.ord_trait()), + hir::BiLt => ("lt", lang.partial_ord_trait()), + hir::BiLe => ("le", lang.partial_ord_trait()), + hir::BiGe => ("ge", lang.partial_ord_trait()), + hir::BiGt => ("gt", lang.partial_ord_trait()), hir::BiEq => ("eq", lang.eq_trait()), hir::BiNe => ("ne", lang.eq_trait()), hir::BiAnd | hir::BiOr => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1a7d8bb5678..5ed35e8203c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -37,8 +37,8 @@ use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; -use rustc::util::nodemap::FxHashSet; -use util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc_const_math::ConstInt; @@ -534,6 +534,18 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match result { Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x), + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + use syntax::attr::IntType; + Some(match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }) + } _ => None } } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d9bd96b0d76..40385cabf56 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -86,6 +86,7 @@ This API is completely unstable and subject to change. #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] +#![feature(i128_type)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs index d6084d5a6da..3fb5621c8ae 100644 --- a/src/test/mir-opt/end_region_2.rs +++ b/src/test/mir-opt/end_region_2.rs @@ -49,7 +49,7 @@ fn main() { // _3 = &'23_1rs _2; // StorageLive(_5); // _5 = _2; -// switchInt(move _5) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _5) -> [false: bb5, otherwise: bb4]; // } // bb3: { // ... diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs index 46548f1cce9..070bde8e3c3 100644 --- a/src/test/mir-opt/end_region_3.rs +++ b/src/test/mir-opt/end_region_3.rs @@ -51,7 +51,7 @@ fn main() { // _3 = &'26_1rs _1; // StorageLive(_5); // _5 = _1; -// switchInt(move _5) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _5) -> [false: bb5, otherwise: bb4]; // } // bb3: { // ... diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs index 0f1d714cc6f..6d9a27eeeb4 100644 --- a/src/test/mir-opt/end_region_9.rs +++ b/src/test/mir-opt/end_region_9.rs @@ -72,7 +72,7 @@ fn main() { // bb4: { // StorageLive(_7); // _7 = _1; -// switchInt(move _7) -> [0u8: bb6, otherwise: bb5]; +// switchInt(move _7) -> [false: bb6, otherwise: bb5]; // } // bb5: { // _0 = (); diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 2a82e2675b6..83425a72f45 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -103,7 +103,7 @@ fn query() -> bool { true } // _11 = const query() -> [return: bb6, unwind: bb3]; // } // bb6: { -// switchInt(move _11) -> [0u8: bb8, otherwise: bb7]; +// switchInt(move _11) -> [false: bb8, otherwise: bb7]; // } // bb7: { // _0 = (); diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 3151c064307..a9eea26f466 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -36,7 +36,7 @@ fn main() { // bb3: { // StorageLive(_4); // _4 = _1; -// switchInt(move _4) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _4) -> [false: bb5, otherwise: bb4]; // } // bb4: { // _0 = (); diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index ba1b54d59f6..596bb4e115d 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -93,7 +93,7 @@ fn main() { // _7 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _7) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _7) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; @@ -157,7 +157,7 @@ fn main() { // _7 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _7) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _7) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb6, imaginary: bb5]; @@ -219,7 +219,7 @@ fn main() { // _9 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { //end of guard -// switchInt(move _9) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _9) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; @@ -239,8 +239,8 @@ fn main() { // _11 = const guard2(move _12) -> [return: bb14, unwind: bb1]; // } // bb14: { // end of guard2 -// StorageDead(_12); -// switchInt(move _11) -> [0u8: bb15, otherwise: bb3]; +// StorageDead(_11); +// switchInt(move _11) -> [false: bb15, otherwise: bb3]; // } // bb15: { // to pre_binding4 // falseEdges -> [real: bb7, imaginary: bb7]; diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index e9834305550..19d733d4f6b 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -41,7 +41,7 @@ fn main() { // | Live variables on entry to bb2[0]: [_1, _3] // _2 = &'_#2r _1[_3]; // | Live variables on entry to bb2[1]: [_2] -// switchInt(const true) -> [0u8: bb4, otherwise: bb3]; +// switchInt(const true) -> [false: bb4, otherwise: bb3]; // } // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index 35786643648..52d5892e656 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,7 +17,7 @@ fn main() { // END RUST SOURCE // START rustc.main.SimplifyBranches-initial.before.mir // bb0: { -// switchInt(const false) -> [0u8: bb3, otherwise: bb2]; +// switchInt(const false) -> [false: bb3, otherwise: bb2]; // } // END rustc.main.SimplifyBranches-initial.before.mir // START rustc.main.SimplifyBranches-initial.after.mir diff --git a/src/test/ui/const-eval-overflow-2.rs b/src/test/ui/const-eval-overflow-2.rs index 6b7f631ff4c..885edb55ed8 100644 --- a/src/test/ui/const-eval-overflow-2.rs +++ b/src/test/ui/const-eval-overflow-2.rs @@ -19,8 +19,7 @@ use std::{u8, u16, u32, u64, usize}; const NEG_128: i8 = -128; const NEG_NEG_128: i8 = -NEG_128; -//~^ ERROR constant evaluation error -//~| attempt to negate with overflow +//~^ ERROR E0080 fn main() { match -128i8 { diff --git a/src/test/ui/const-eval-overflow-4.rs b/src/test/ui/const-eval-overflow-4.rs index 4423fdec33a..a1b90f623cd 100644 --- a/src/test/ui/const-eval-overflow-4.rs +++ b/src/test/ui/const-eval-overflow-4.rs @@ -21,8 +21,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1i8) as usize] - //~^ ERROR constant evaluation error - //~| WARNING constant evaluation error + //~^ ERROR E0080 = [0; (i8::MAX as usize) + 1]; fn main() { diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs index 85ab2a00521..86c5e873df8 100644 --- a/src/test/ui/const-eval/issue-43197.rs +++ b/src/test/ui/const-eval/issue-43197.rs @@ -16,8 +16,6 @@ const fn foo(x: u32) -> u32 { fn main() { const X: u32 = 0-1; //~ ERROR constant evaluation error - //~^ WARN constant evaluation error const Y: u32 = foo(0-1); //~ ERROR constant evaluation error - //~^ WARN constant evaluation error println!("{} {}", X, Y); } diff --git a/src/test/ui/const-expr-addr-operator.rs b/src/test/ui/const-expr-addr-operator.rs index 24d4457f01d..bfd6a409064 100644 --- a/src/test/ui/const-expr-addr-operator.rs +++ b/src/test/ui/const-expr-addr-operator.rs @@ -9,10 +9,11 @@ // except according to those terms. // Encountered while testing #44614. +// must-compile-successfully pub fn main() { // Constant of generic type (int) - const X: &'static u32 = &22; //~ ERROR constant evaluation error + const X: &'static u32 = &22; assert_eq!(0, match &22 { X => 0, _ => 1, diff --git a/src/test/ui/const-fn-error.rs b/src/test/ui/const-fn-error.rs index ac1c2fe5432..dc1526a7079 100644 --- a/src/test/ui/const-fn-error.rs +++ b/src/test/ui/const-fn-error.rs @@ -13,17 +13,18 @@ const X : usize = 2; const fn f(x: usize) -> usize { - let mut sum = 0; //~ ERROR blocks in constant functions are limited - for i in 0..x { //~ ERROR calls in constant functions - //~| ERROR constant function contains unimplemented + let mut sum = 0; + //~^ ERROR E0016 + for i in 0..x { + //~^ ERROR E0015 + //~| ERROR E0019 sum += i; } - sum //~ ERROR E0080 - //~| non-constant path in constant + sum } #[allow(unused_variables)] fn main() { let a : [i32; f(X)]; - //~^ WARNING constant evaluation error: non-constant path + //~^ ERROR E0080 } diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index e738a5e4ff3..26c238992ab 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -1,3 +1,4 @@ +<<<<<<< HEAD warning: constant evaluation error: non-constant path in constant expression --> $DIR/const-fn-error.rs:27:19 | @@ -10,6 +11,12 @@ error[E0016]: blocks in constant functions are limited to items and tail express --> $DIR/const-fn-error.rs:16:19 | LL | let mut sum = 0; //~ ERROR blocks in constant functions are limited +======= +error[E0016]: blocks in constant functions are limited to items and tail expressions + --> $DIR/const-fn-error.rs:16:19 + | +16 | let mut sum = 0; +>>>>>>> Produce instead of pointers | ^ error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors @@ -25,6 +32,7 @@ LL | for i in 0..x { //~ ERROR calls in constant functions | ^^^^ error[E0080]: constant evaluation error +<<<<<<< HEAD --> $DIR/const-fn-error.rs:21:5 | LL | sum //~ ERROR E0080 @@ -35,6 +43,12 @@ note: for constant expression here | LL | let a : [i32; f(X)]; | ^^^^^^^^^^^ +======= + --> $DIR/const-fn-error.rs:28:19 + | +28 | let a : [i32; f(X)]; + | ^^^^ miri failed: machine error: Cannot evaluate within constants: "calling non-const fn `>::into_iter`" +>>>>>>> Produce instead of pointers error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.rs b/src/test/ui/const-len-underflow-separate-spans.rs index 823cc988947..7582d0efa81 100644 --- a/src/test/ui/const-len-underflow-separate-spans.rs +++ b/src/test/ui/const-len-underflow-separate-spans.rs @@ -15,9 +15,8 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ ERROR constant evaluation error [E0080] -//~| WARN attempt to subtract with overflow fn main() { let a: [i8; LEN] = unimplemented!(); +//~^ ERROR E0080 } diff --git a/src/test/ui/const-pattern-not-const-evaluable.rs b/src/test/ui/const-pattern-not-const-evaluable.rs index 263c0bdc64c..09b24d1ffa2 100644 --- a/src/test/ui/const-pattern-not-const-evaluable.rs +++ b/src/test/ui/const-pattern-not-const-evaluable.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + #![feature(const_fn)] #[derive(PartialEq, Eq)] @@ -20,8 +22,6 @@ use Cake::*; struct Pair(A, B); const BOO: Pair = Pair(Marmor, BlackForest); -//~^ ERROR: constant evaluation error [E0080] -//~| unimplemented constant expression: tuple struct constructors const FOO: Cake = BOO.1; const fn foo() -> Cake { diff --git a/src/test/ui/feature-gate-const-indexing.rs b/src/test/ui/feature-gate-const-indexing.rs index 0d61878cd80..eb5f746774c 100644 --- a/src/test/ui/feature-gate-const-indexing.rs +++ b/src/test/ui/feature-gate-const-indexing.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully fn main() { const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47]; const IDX: usize = 3; const VAL: i32 = ARR[IDX]; - const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; //~ ERROR constant evaluation error + const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; } diff --git a/src/test/ui/issue-38875/issue_38875.rs b/src/test/ui/issue-38875/issue_38875.rs index 42e3c05a38c..24cd20a84a9 100644 --- a/src/test/ui/issue-38875/issue_38875.rs +++ b/src/test/ui/issue-38875/issue_38875.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:issue_38875_b.rs +// must-compile-successfully extern crate issue_38875_b; diff --git a/src/test/ui/union/union-const-eval.rs b/src/test/ui/union/union-const-eval.rs index a4c969ba20c..aeafb45e6a5 100644 --- a/src/test/ui/union/union-const-eval.rs +++ b/src/test/ui/union/union-const-eval.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + union U { a: usize, b: usize, @@ -16,9 +18,6 @@ union U { const C: U = U { a: 10 }; fn main() { - unsafe { - let a: [u8; C.a]; // OK - let b: [u8; C.b]; //~ ERROR constant evaluation error - //~| WARNING constant evaluation error - } + let a: [u8; unsafe { C.a }]; + let b: [u8; unsafe { C.b }]; } -- cgit 1.4.1-3-g733a5 From 184fd32a0334a81315e7ad2cfc8139e2c7341a62 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Sun, 3 Dec 2017 14:21:23 +0100 Subject: Move PROFQ_CHAN to a Session field --- src/librustc/dep_graph/graph.rs | 37 ++++++------ src/librustc/ich/hcx.rs | 32 +++++++--- src/librustc/ich/mod.rs | 2 +- src/librustc/session/mod.rs | 8 ++- src/librustc/ty/maps/plumbing.rs | 4 +- src/librustc/util/common.rs | 62 +++++++++---------- src/librustc_data_structures/stable_hasher.rs | 23 ------- src/librustc_driver/driver.rs | 86 +++++++++++++-------------- src/librustc_driver/lib.rs | 2 +- src/librustc_driver/profile/mod.rs | 9 +-- src/librustc_incremental/persist/load.rs | 8 ++- src/librustc_incremental/persist/save.rs | 4 +- src/librustc_trans/back/link.rs | 4 +- src/librustc_trans/back/lto.rs | 8 +-- src/librustc_trans/back/write.rs | 21 +++++-- src/librustc_trans/base.rs | 13 ++-- src/librustc_trans/lib.rs | 4 +- src/librustc_typeck/lib.rs | 18 +++--- 18 files changed, 175 insertions(+), 170 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 07c6c85b89d..210bdd8d5dd 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -9,8 +9,7 @@ // except according to those terms. use errors::DiagnosticBuilder; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, - StableHashingContextProvider}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::sync::Lrc; @@ -20,7 +19,7 @@ use std::hash::Hash; use ty::TyCtxt; use util::common::{ProfileQueriesMsg, profq_msg}; -use ich::Fingerprint; +use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; use super::debug::EdgeFilter; use super::dep_node::{DepNode, DepKind, WorkProductId}; @@ -189,21 +188,21 @@ impl DepGraph { /// `arg` parameter. /// /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/incremental-compilation.html - pub fn with_task(&self, + pub fn with_task<'gcx, C, A, R>(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> (R, DepNodeIndex) - where C: DepGraphSafe + StableHashingContextProvider, - R: HashStable, + where C: DepGraphSafe + StableHashingContextProvider<'gcx>, + R: HashStable>, { self.with_task_impl(key, cx, arg, task, |data, key| data.borrow_mut().push_task(key), |data, key| data.borrow_mut().pop_task(key)) } - fn with_task_impl(&self, + fn with_task_impl<'gcx, C, A, R>(&self, key: DepNode, cx: C, arg: A, @@ -211,25 +210,27 @@ impl DepGraph { push: fn(&RefCell, DepNode), pop: fn(&RefCell, DepNode) -> DepNodeIndex) -> (R, DepNodeIndex) - where C: DepGraphSafe + StableHashingContextProvider, - R: HashStable, + where C: DepGraphSafe + StableHashingContextProvider<'gcx>, + R: HashStable>, { if let Some(ref data) = self.data { push(&data.current, key); - if cfg!(debug_assertions) { - profq_msg(ProfileQueriesMsg::TaskBegin(key.clone())) - }; // In incremental mode, hash the result of the task. We don't // do anything with the hash yet, but we are computing it // anyway so that // - we make sure that the infrastructure works and // - we can get an idea of the runtime cost. - let mut hcx = cx.create_stable_hashing_context(); + let mut hcx = cx.get_stable_hashing_context(); + + if cfg!(debug_assertions) { + profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone())) + }; let result = task(cx, arg); + if cfg!(debug_assertions) { - profq_msg(ProfileQueriesMsg::TaskEnd) + profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd) }; let dep_node_index = pop(&data.current, key); @@ -274,7 +275,7 @@ impl DepGraph { (result, dep_node_index) } else { if key.kind.fingerprint_needed_for_crate_hash() { - let mut hcx = cx.create_stable_hashing_context(); + let mut hcx = cx.get_stable_hashing_context(); let result = task(cx, arg); let mut stable_hasher = StableHasher::new(); result.hash_stable(&mut hcx, &mut stable_hasher); @@ -314,14 +315,14 @@ impl DepGraph { /// Execute something within an "eval-always" task which is a task // that runs whenever anything changes. - pub fn with_eval_always_task(&self, + pub fn with_eval_always_task<'gcx, C, A, R>(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> (R, DepNodeIndex) - where C: DepGraphSafe + StableHashingContextProvider, - R: HashStable, + where C: DepGraphSafe + StableHashingContextProvider<'gcx>, + R: HashStable>, { self.with_task_impl(key, cx, arg, task, |data, key| data.borrow_mut().push_eval_always_task(key), diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 6ae588b2a07..33e0d0e6944 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -30,7 +30,7 @@ use syntax::symbol::Symbol; use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::hygiene; -use rustc_data_structures::stable_hasher::{HashStable, StableHashingContextProvider, +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult, ToStableHashKey}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -192,17 +192,33 @@ impl<'a> StableHashingContext<'a> { } } -impl<'a, 'gcx, 'lcx> StableHashingContextProvider for TyCtxt<'a, 'gcx, 'lcx> { - type ContextType = StableHashingContext<'a>; - fn create_stable_hashing_context(&self) -> Self::ContextType { - (*self).create_stable_hashing_context() +/// Something that can provide a stable hashing context. +pub trait StableHashingContextProvider<'a> { + fn get_stable_hashing_context(&self) -> StableHashingContext<'a>; +} + +impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> +for &'b T { + fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { + (**self).get_stable_hashing_context() } } +impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> +for &'b mut T { + fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { + (**self).get_stable_hashing_context() + } +} + +impl<'a, 'gcx, 'lcx> StableHashingContextProvider<'a> for TyCtxt<'a, 'gcx, 'lcx> { + fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { + (*self).create_stable_hashing_context() + } +} -impl<'a> StableHashingContextProvider for StableHashingContext<'a> { - type ContextType = StableHashingContext<'a>; - fn create_stable_hashing_context(&self) -> Self::ContextType { +impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> { + fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { self.clone() } } diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index ce1bd07b14c..1b77a2e7c82 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -12,7 +12,7 @@ pub use self::fingerprint::Fingerprint; pub use self::caching_codemap_view::CachingCodemapView; -pub use self::hcx::{StableHashingContext, NodeIdHashingMode, +pub use self::hcx::{StableHashingContextProvider, StableHashingContext, NodeIdHashingMode, hash_stable_trait_impls, compute_ignored_attr_names}; mod fingerprint; mod caching_codemap_view; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index cdbbcf6a8dd..01e1037b622 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -24,8 +24,9 @@ use session::config::{DebugInfoLevel, OutputType}; use ty::tls; use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; +use util::common::ProfileQueriesMsg; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, Lock}; use syntax::ast::NodeId; use errors::{self, DiagnosticBuilder, DiagnosticId}; @@ -53,6 +54,7 @@ use std::io::Write; use std::path::{Path, PathBuf}; use std::sync::{Once, ONCE_INIT}; use std::time::Duration; +use std::sync::mpsc; mod code_stats; pub mod config; @@ -126,6 +128,9 @@ pub struct Session { /// A cache of attributes ignored by StableHashingContext pub ignored_attr_names: FxHashSet, + /// Used by -Z profile-queries in util::common + pub profile_channel: Lock>>, + /// Some measurements that are being gathered during compilation. pub perf_stats: PerfStats, @@ -1131,6 +1136,7 @@ pub fn build_session_( imported_macro_spans: RefCell::new(HashMap::new()), incr_comp_session: RefCell::new(IncrCompSession::NotInitialized), ignored_attr_names: ich::compute_ignored_attr_names(), + profile_channel: Lock::new(None), perf_stats: PerfStats { svh_time: Cell::new(Duration::from_secs(0)), incr_comp_hashes_time: Cell::new(Duration::from_secs(0)), diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index fcc69f3b2c3..68d10888902 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -164,8 +164,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { macro_rules! profq_msg { ($tcx:expr, $msg:expr) => { if cfg!(debug_assertions) { - if $tcx.sess.profile_queries() { - profq_msg($msg) + if $tcx.sess.profile_queries() { + profq_msg($tcx.sess, $msg) } } } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index bdb120ea59c..e1ae41f2472 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -26,6 +26,7 @@ use ty::maps::{QueryMsg}; use dep_graph::{DepNode}; use proc_macro; use lazy_static; +use session::Session; // The name of the associated type for `Fn` return types pub const FN_OUTPUT_NAME: &'static str = "Output"; @@ -55,9 +56,6 @@ pub fn install_panic_hook() { lazy_static::initialize(&DEFAULT_HOOK); } -/// Initialized for -Z profile-queries -thread_local!(static PROFQ_CHAN: RefCell>> = RefCell::new(None)); - /// Parameters to the `Dump` variant of type `ProfileQueriesMsg`. #[derive(Clone,Debug)] pub struct ProfQDumpParams { @@ -97,29 +95,23 @@ pub enum ProfileQueriesMsg { } /// If enabled, send a message to the profile-queries thread -pub fn profq_msg(msg: ProfileQueriesMsg) { - PROFQ_CHAN.with(|sender|{ - if let Some(s) = sender.borrow().as_ref() { - s.send(msg).unwrap() - } else { - // Do nothing. - // - // FIXME(matthewhammer): Multi-threaded translation phase triggers the panic below. - // From backtrace: rustc_trans::back::write::spawn_work::{{closure}}. - // - // panic!("no channel on which to send profq_msg: {:?}", msg) - } - }) +pub fn profq_msg(sess: &Session, msg: ProfileQueriesMsg) { + if let Some(s) = sess.profile_channel.borrow().as_ref() { + s.send(msg).unwrap() + } else { + // Do nothing + } } /// Set channel for profile queries channel -pub fn profq_set_chan(s: Sender) -> bool { - PROFQ_CHAN.with(|chan|{ - if chan.borrow().is_none() { - *chan.borrow_mut() = Some(s); - true - } else { false } - }) +pub fn profq_set_chan(sess: &Session, s: Sender) -> bool { + let mut channel = sess.profile_channel.borrow_mut(); + if channel.is_none() { + *channel = Some(s); + true + } else { + false + } } /// Read the current depth of `time()` calls. This is used to @@ -135,7 +127,13 @@ pub fn set_time_depth(depth: usize) { TIME_DEPTH.with(|slot| slot.set(depth)); } -pub fn time(do_it: bool, what: &str, f: F) -> T where +pub fn time(sess: &Session, what: &str, f: F) -> T where + F: FnOnce() -> T, +{ + time_ext(sess.time_passes(), Some(sess), what, f) +} + +pub fn time_ext(do_it: bool, sess: Option<&Session>, what: &str, f: F) -> T where F: FnOnce() -> T, { if !do_it { return f(); } @@ -146,15 +144,19 @@ pub fn time(do_it: bool, what: &str, f: F) -> T where r }); - if cfg!(debug_assertions) { - profq_msg(ProfileQueriesMsg::TimeBegin(what.to_string())) - }; + if let Some(sess) = sess { + if cfg!(debug_assertions) { + profq_msg(sess, ProfileQueriesMsg::TimeBegin(what.to_string())) + } + } let start = Instant::now(); let rv = f(); let dur = start.elapsed(); - if cfg!(debug_assertions) { - profq_msg(ProfileQueriesMsg::TimeEnd) - }; + if let Some(sess) = sess { + if cfg!(debug_assertions) { + profq_msg(sess, ProfileQueriesMsg::TimeEnd) + } + } print_time_passes_entry_internal(what, dur); diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 70733bc6aed..a8f689e5c81 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -165,29 +165,6 @@ impl Hasher for StableHasher { } } - -/// Something that can provide a stable hashing context. -pub trait StableHashingContextProvider { - type ContextType; - fn create_stable_hashing_context(&self) -> Self::ContextType; -} - -impl<'a, T: StableHashingContextProvider> StableHashingContextProvider for &'a T { - type ContextType = T::ContextType; - - fn create_stable_hashing_context(&self) -> Self::ContextType { - (**self).create_stable_hashing_context() - } -} - -impl<'a, T: StableHashingContextProvider> StableHashingContextProvider for &'a mut T { - type ContextType = T::ContextType; - - fn create_stable_hashing_context(&self) -> Self::ContextType { - (**self).create_stable_hashing_context() - } -} - /// Something that implements `HashStable` can be hashed in a way that is /// stable across multiple compilation sessions. pub trait HashStable { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f020f86b686..485ee1130d3 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -89,7 +89,7 @@ pub fn compile_input(trans: Box, } if sess.profile_queries() { - profile::begin(); + profile::begin(sess); } // We need nested scopes here, because the intermediate results can keep @@ -181,7 +181,7 @@ pub fn compile_input(trans: Box, let arenas = AllArenas::new(); // Construct the HIR map - let hir_map = time(sess.time_passes(), + let hir_map = time(sess, "indexing hir", || hir_map::map_crate(sess, cstore, &mut hir_forest, &defs)); @@ -517,10 +517,10 @@ pub fn phase_1_parse_input<'a>(control: &CompileController, sess.diagnostic().set_continue_after_error(control.continue_parse_after_error); if sess.profile_queries() { - profile::begin(); + profile::begin(sess); } - let krate = time(sess.time_passes(), "parsing", || { + let krate = time(sess, "parsing", || { match *input { Input::File(ref file) => { parse::parse_crate_from_file(file, &sess.parse_sess) @@ -645,8 +645,6 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, -> Result, CompileIncomplete> where F: FnOnce(&ast::Crate) -> CompileResult, { - let time_passes = sess.time_passes(); - let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test, sess.opts.debugging_opts.epoch); @@ -664,7 +662,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, ); if sess.opts.incremental.is_some() { - time(time_passes, "garbage collect incremental cache directory", || { + time(sess, "garbage collect incremental cache directory", || { if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { warn!("Error while trying to garbage collect incremental \ compilation cache directory: {}", e); @@ -674,22 +672,22 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, // If necessary, compute the dependency graph (in the background). let future_dep_graph = if sess.opts.build_dep_graph() { - Some(rustc_incremental::load_dep_graph(sess, time_passes)) + Some(rustc_incremental::load_dep_graph(sess)) } else { None }; - time(time_passes, "recursion limit", || { + time(sess, "recursion limit", || { middle::recursion_limit::update_limits(sess, &krate); }); - krate = time(time_passes, "crate injection", || { + krate = time(sess, "crate injection", || { let alt_std_name = sess.opts.alt_std_name.clone(); syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name) }); let mut addl_plugins = Some(addl_plugins); - let registrars = time(time_passes, "plugin loading", || { + let registrars = time(sess, "plugin loading", || { plugin::load::load_plugins(sess, &cstore, &krate, @@ -699,7 +697,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut registry = registry.unwrap_or(Registry::new(sess, krate.span)); - time(time_passes, "plugin registration", || { + time(sess, "plugin registration", || { if sess.features_untracked().rustc_diagnostic_macros { registry.register_macro("__diagnostic_used", diagnostics::plugin::expand_diagnostic_used); @@ -752,7 +750,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote); - krate = time(time_passes, "expansion", || { + krate = time(sess, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their // dependencies. It's up to us to tell the system where to find all the // dependent dlls. Note that this uses cfg!(windows) as opposed to @@ -814,7 +812,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, krate }); - krate = time(time_passes, "maybe building test harness", || { + krate = time(sess, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, &mut resolver, sess.opts.test, @@ -833,7 +831,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, // bunch of checks in the `modify` function below. For now just skip this // step entirely if we're rustdoc as it's not too useful anyway. if !sess.opts.actually_rustdoc { - krate = time(time_passes, "maybe creating a macro crate", || { + krate = time(sess, "maybe creating a macro crate", || { let crate_types = sess.crate_types.borrow(); let num_crate_types = crate_types.len(); let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro); @@ -848,7 +846,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, }); } - krate = time(time_passes, "creating allocators", || { + krate = time(sess, "creating allocators", || { allocator::expand::modify(&sess.parse_sess, &mut resolver, krate, @@ -869,11 +867,11 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, println!("{}", json::as_json(&krate)); } - time(time_passes, + time(sess, "AST validation", || ast_validation::check_crate(sess, &krate)); - time(time_passes, "name resolution", || -> CompileResult { + time(sess, "name resolution", || -> CompileResult { resolver.resolve_crate(&krate); Ok(()) })?; @@ -883,7 +881,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, } // Needs to go *after* expansion to be able to check the results of macro expansion. - time(time_passes, "complete gated feature checking", || { + time(sess, "complete gated feature checking", || { sess.track_errors(|| { syntax::feature_gate::check_crate(&krate, &sess.parse_sess, @@ -898,7 +896,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let dep_graph = match future_dep_graph { None => DepGraph::new_disabled(), Some(future) => { - let prev_graph = time(time_passes, "blocked while dep-graph loading finishes", || { + let prev_graph = time(sess, "blocked while dep-graph loading finishes", || { future.open() .expect("Could not join with background dep_graph thread") .open(sess) @@ -906,7 +904,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, DepGraph::new(prev_graph) } }; - let hir_forest = time(time_passes, "lowering ast -> hir", || { + let hir_forest = time(sess, "lowering ast -> hir", || { let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver); if sess.opts.debugging_opts.hir_stats { @@ -916,7 +914,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, hir_map::Forest::new(hir_crate, &dep_graph) }); - time(time_passes, + time(sess, "early lint checks", || lint::check_ast_crate(sess, &krate)); @@ -973,22 +971,20 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, mpsc::Receiver>, CompileResult) -> R { - let time_passes = sess.time_passes(); - - let query_result_on_disk_cache = time(time_passes, + let query_result_on_disk_cache = time(sess, "load query result cache", || rustc_incremental::load_query_result_cache(sess)); - time(time_passes, + time(sess, "looking for entry point", || middle::entry::find_entry_point(sess, &hir_map)); - sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || { + sess.plugin_registrar_fn.set(time(sess, "looking for plugin registrar", || { plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map) })); sess.derive_registrar_fn.set(derive_registrar::find(&hir_map)); - time(time_passes, + time(sess, "loop checking", || loops::check_crate(sess, &hir_map)); @@ -1020,11 +1016,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, // tcx available. rustc_incremental::dep_graph_tcx_init(tcx); - time(sess.time_passes(), "attribute checking", || { + time(sess, "attribute checking", || { hir::check_attr::check_crate(tcx) }); - time(time_passes, + time(sess, "stability checking", || stability::check_unstable_api_usage(tcx)); @@ -1037,18 +1033,18 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, } } - time(time_passes, + time(sess, "rvalue promotion", || rvalue_promotion::check_crate(tcx)); analysis.access_levels = - time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx)); + time(sess, "privacy checking", || rustc_privacy::check_crate(tcx)); - time(time_passes, + time(sess, "intrinsic checking", || middle::intrinsicck::check_crate(tcx)); - time(time_passes, + time(sess, "match checking", || mir::matchck_crate(tcx)); @@ -1056,19 +1052,19 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, // "not all control paths return a value" is reported here. // // maybe move the check to a MIR pass? - time(time_passes, + time(sess, "liveness checking", || middle::liveness::check_crate(tcx)); - time(time_passes, + time(sess, "borrow checking", || borrowck::check_crate(tcx)); - time(time_passes, + time(sess, "MIR borrow checking", || for def_id in tcx.body_owners() { tcx.mir_borrowck(def_id); }); - time(time_passes, + time(sess, "MIR effect checking", || for def_id in tcx.body_owners() { mir::transform::check_unsafety::check_unsafety(tcx, def_id) @@ -1083,13 +1079,13 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, return Ok(f(tcx, analysis, rx, sess.compile_status())); } - time(time_passes, "death checking", || middle::dead::check_crate(tcx)); + time(sess, "death checking", || middle::dead::check_crate(tcx)); - time(time_passes, "unused lib feature checking", || { + time(sess, "unused lib feature checking", || { stability::check_unused_or_stable_features(tcx) }); - time(time_passes, "lint checking", || lint::check_crate(tcx)); + time(sess, "lint checking", || lint::check_crate(tcx)); return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); }) @@ -1101,18 +1097,16 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(trans: &TransCrate, tcx: TyCtxt<'a, 'tcx, 'tcx>, rx: mpsc::Receiver>) -> Box { - let time_passes = tcx.sess.time_passes(); - - time(time_passes, + time(tcx.sess, "resolving dependency formats", || ::rustc::middle::dependency_format::calculate(tcx)); let translation = - time(time_passes, "translation", move || { + time(tcx.sess, "translation", move || { trans.trans_crate(tcx, rx) }); if tcx.sess.profile_queries() { - profile::dump("profile_queries".to_string()) + profile::dump(&tcx.sess, "profile_queries".to_string()) } translation diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 8c0e89716cf..f6aa58213fc 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -914,7 +914,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { pub fn enable_save_analysis(control: &mut CompileController) { control.keep_ast = true; control.after_analysis.callback = box |state| { - time(state.session.time_passes(), "save analysis", || { + time(state.session, "save analysis", || { save::process_crate(state.tcx.unwrap(), state.expanded_crate.unwrap(), state.analysis.unwrap(), diff --git a/src/librustc_driver/profile/mod.rs b/src/librustc_driver/profile/mod.rs index 061077d05a4..a362556717b 100644 --- a/src/librustc_driver/profile/mod.rs +++ b/src/librustc_driver/profile/mod.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::session::Session; use rustc::util::common::{ProfQDumpParams, ProfileQueriesMsg, profq_msg, profq_set_chan}; use std::sync::mpsc::{Receiver}; use std::io::{Write}; @@ -17,11 +18,11 @@ use std::time::{Duration, Instant}; pub mod trace; /// begin a profile thread, if not already running -pub fn begin() { +pub fn begin(sess: &Session) { use std::thread; use std::sync::mpsc::{channel}; let (tx, rx) = channel(); - if profq_set_chan(tx) { + if profq_set_chan(sess, tx) { thread::spawn(move||profile_queries_thread(rx)); } } @@ -30,7 +31,7 @@ pub fn begin() { /// wait for this dump to complete. /// /// wraps the RPC (send/recv channel logic) of requesting a dump. -pub fn dump(path:String) { +pub fn dump(sess: &Session, path: String) { use std::sync::mpsc::{channel}; let (tx, rx) = channel(); let params = ProfQDumpParams{ @@ -39,7 +40,7 @@ pub fn dump(path:String) { // is written; false for now dump_profq_msg_log:true, }; - profq_msg(ProfileQueriesMsg::Dump(params)); + profq_msg(sess, ProfileQueriesMsg::Dump(params)); let _ = rx.recv().unwrap(); } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 0e6d328d947..38468e29427 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -14,7 +14,7 @@ use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph}; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::ty::maps::OnDiskCache; -use rustc::util::common::time; +use rustc::util::common::time_ext; use rustc_serialize::Decodable as RustcDecodable; use rustc_serialize::opaque::Decoder; use std::path::Path; @@ -147,12 +147,14 @@ impl MaybeAsync { } /// Launch a thread and load the dependency graph in the background. -pub fn load_dep_graph(sess: &Session, time_passes: bool) -> +pub fn load_dep_graph(sess: &Session) -> MaybeAsync> { // Since `sess` isn't `Sync`, we perform all accesses to `sess` // before we fire the background thread. + let time_passes = sess.time_passes(); + if sess.opts.incremental.is_none() { // No incremental compilation. return MaybeAsync::Sync(LoadResult::Ok { @@ -167,7 +169,7 @@ pub fn load_dep_graph(sess: &Session, time_passes: bool) -> let expected_hash = sess.opts.dep_tracking_hash(); MaybeAsync::Async(std::thread::spawn(move || { - time(time_passes, "background load prev dep-graph", move || { + time_ext(time_passes, None, "background load prev dep-graph", move || { match load_data(report_incremental_info, &path) { LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, LoadResult::Error { message } => LoadResult::Error { message }, diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index d44d1d6f260..ca1e3563089 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -33,14 +33,14 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { return; } - time(sess.time_passes(), "persist query result cache", || { + time(sess, "persist query result cache", || { save_in(sess, query_cache_path(sess), |e| encode_query_cache(tcx, e)); }); if tcx.sess.opts.debugging_opts.incremental_queries { - time(sess.time_passes(), "persist dep-graph", || { + time(sess, "persist dep-graph", || { save_in(sess, dep_graph_path(sess), |e| encode_dep_graph(tcx, e)); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 636b3984117..8984a6bfd60 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -690,7 +690,7 @@ fn link_natively(sess: &Session, let mut i = 0; loop { i += 1; - prog = time(sess.time_passes(), "running linker", || { + prog = time(sess, "running linker", || { exec_linker(sess, &mut cmd, tmpdir) }); let output = match prog { @@ -1317,7 +1317,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, let name = cratepath.file_name().unwrap().to_str().unwrap(); let name = &name[3..name.len() - 5]; // chop off lib/.rlib - time(sess.time_passes(), &format!("altering {}.rlib", name), || { + time(sess, &format!("altering {}.rlib", name), || { let cfg = archive_config(sess, &dst, Some(cratepath)); let mut archive = ArchiveBuilder::new(cfg); archive.update_symbols(); diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index f79651cef3e..2a473f1ecbc 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -19,7 +19,7 @@ use llvm; use rustc::hir::def_id::LOCAL_CRATE; use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config::{self, Lto}; -use rustc::util::common::time; +use rustc::util::common::time_ext; use time_graph::Timeline; use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource}; @@ -172,7 +172,7 @@ pub(crate) fn run(cgcx: &CodegenContext, info!("adding bytecode {}", name); let bc_encoded = data.data(); - let (bc, id) = time(cgcx.time_passes, &format!("decode {}", name), || { + let (bc, id) = time_ext(cgcx.time_passes, None, &format!("decode {}", name), || { match DecodedBytecode::new(bc_encoded) { Ok(b) => Ok((b.bytecode(), b.identifier().to_string())), Err(e) => Err(diag_handler.fatal(&e)), @@ -253,7 +253,7 @@ fn fat_lto(cgcx: &CodegenContext, let mut linker = Linker::new(llmod); for (bc_decoded, name) in serialized_modules { info!("linking {:?}", name); - time(cgcx.time_passes, &format!("ll link {:?}", name), || { + time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || { let data = bc_decoded.data(); linker.add(&data).map_err(|()| { let msg = format!("failed to load bc of {:?}", name); @@ -498,7 +498,7 @@ fn run_pass_manager(cgcx: &CodegenContext, assert!(!pass.is_null()); llvm::LLVMRustAddPass(pm, pass); - time(cgcx.time_passes, "LTO passes", || + time_ext(cgcx.time_passes, None, "LTO passes", || llvm::LLVMRunPassManager(pm, llmod)); llvm::LLVMDisposePassManager(pm); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index c0561ff0c17..7651a8e748e 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -31,7 +31,8 @@ use {CrateTranslation, ModuleSource, ModuleTranslation, CompiledModule, ModuleKi use CrateInfo; use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::ty::TyCtxt; -use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry}; +use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passes_entry}; +use rustc::util::common::path2cstr; use rustc::util::fs::{link_or_copy}; use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; use errors::emitter::{Emitter}; @@ -563,11 +564,19 @@ unsafe fn optimize(cgcx: &CodegenContext, diag_handler.abort_if_errors(); // Finally, run the actual optimization passes - time(config.time_passes, &format!("llvm function passes [{}]", module_name.unwrap()), || - llvm::LLVMRustRunFunctionPassManager(fpm, llmod)); + time_ext(config.time_passes, + None, + &format!("llvm function passes [{}]", module_name.unwrap()), + || { + llvm::LLVMRustRunFunctionPassManager(fpm, llmod) + }); timeline.record("fpm"); - time(config.time_passes, &format!("llvm module passes [{}]", module_name.unwrap()), || - llvm::LLVMRunPassManager(mpm, llmod)); + time_ext(config.time_passes, + None, + &format!("llvm module passes [{}]", module_name.unwrap()), + || { + llvm::LLVMRunPassManager(mpm, llmod) + }); // Deallocate managers that we're now done with llvm::LLVMDisposePassManager(fpm); @@ -682,7 +691,7 @@ unsafe fn codegen(cgcx: &CodegenContext, } } - time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()), + time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), || -> Result<(), FatalError> { if config.emit_ir { let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 49a5b7ac8b9..76e05ae7dcb 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -712,7 +712,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Translate the metadata. let llmod_id = "metadata"; let (metadata_llcx, metadata_llmod, metadata) = - time(tcx.sess.time_passes(), "write metadata", || { + time(tcx.sess, "write metadata", || { write_metadata(tcx, llmod_id, &link_meta) }); @@ -790,7 +790,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, llcx, tm: create_target_machine(tcx.sess), }; - time(tcx.sess.time_passes(), "write allocator module", || { + time(tcx.sess, "write allocator module", || { allocator::trans(tcx, &modules, kind) }); @@ -924,11 +924,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - time(tcx.sess.time_passes(), + time(tcx.sess, "assert dep graph", || rustc_incremental::assert_dep_graph(tcx)); - time(tcx.sess.time_passes(), + time(tcx.sess, "serialize dep graph", || rustc_incremental::save_dep_graph(tcx)); } @@ -939,7 +939,6 @@ fn collect_and_partition_translation_items<'a, 'tcx>( ) -> (Arc, Arc>>>) { assert_eq!(cnum, LOCAL_CRATE); - let time_passes = tcx.sess.time_passes(); let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items { Some(ref s) => { @@ -968,7 +967,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( }; let (items, inlining_map) = - time(time_passes, "translation item collection", || { + time(tcx.sess, "translation item collection", || { collector::collect_crate_mono_items(tcx, collection_mode) }); @@ -982,7 +981,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units()) }; - let codegen_units = time(time_passes, "codegen unit partitioning", || { + let codegen_units = time(tcx.sess, "codegen unit partitioning", || { partitioning::partition(tcx, items.iter().cloned(), strategy, diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 74df5127269..39eb38658fe 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -238,7 +238,7 @@ impl TransCrate for LlvmTransCrate { back::write::dump_incremental_data(&trans); } - time(sess.time_passes(), + time(sess, "serialize work products", move || rustc_incremental::save_work_products(sess, &dep_graph)); @@ -251,7 +251,7 @@ impl TransCrate for LlvmTransCrate { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - time(sess.time_passes(), "linking", || { + time(sess, "linking", || { back::link::link_binary(sess, &trans, outputs, &trans.crate_name.as_str()); }); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 40385cabf56..49a23f14338 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -315,41 +315,39 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Result<(), CompileIncomplete> { - let time_passes = tcx.sess.time_passes(); - // this ensures that later parts of type checking can assume that items // have valid types and not error tcx.sess.track_errors(|| { - time(time_passes, "type collecting", || + time(tcx.sess, "type collecting", || collect::collect_item_types(tcx)); })?; tcx.sess.track_errors(|| { - time(time_passes, "outlives testing", || + time(tcx.sess, "outlives testing", || outlives::test::test_inferred_outlives(tcx)); })?; tcx.sess.track_errors(|| { - time(time_passes, "impl wf inference", || + time(tcx.sess, "impl wf inference", || impl_wf_check::impl_wf_check(tcx)); })?; tcx.sess.track_errors(|| { - time(time_passes, "coherence checking", || + time(tcx.sess, "coherence checking", || coherence::check_coherence(tcx)); })?; tcx.sess.track_errors(|| { - time(time_passes, "variance testing", || + time(tcx.sess, "variance testing", || variance::test::test_variance(tcx)); })?; - time(time_passes, "wf checking", || check::check_wf_new(tcx))?; + time(tcx.sess, "wf checking", || check::check_wf_new(tcx))?; - time(time_passes, "item-types checking", || check::check_item_types(tcx))?; + time(tcx.sess, "item-types checking", || check::check_item_types(tcx))?; - time(time_passes, "item-bodies checking", || check::check_item_bodies(tcx))?; + time(tcx.sess, "item-bodies checking", || check::check_item_bodies(tcx))?; check_unused::check_crate(tcx); check_for_entry_fn(tcx); -- cgit 1.4.1-3-g733a5 From 993c1488cc4b0826c3f1076393bf50eef09ba467 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 9 Feb 2018 10:39:36 -0500 Subject: add `canonicalize` method to `InferCtxt` [VIC] --- src/librustc/ich/impls_ty.rs | 59 +- src/librustc/infer/canonical.rs | 928 +++++++++++++++++++++ src/librustc/infer/combine.rs | 1 + src/librustc/infer/error_reporting/mod.rs | 1 + src/librustc/infer/freshen.rs | 6 +- src/librustc/infer/lexical_region_resolve/mod.rs | 2 + src/librustc/infer/mod.rs | 8 +- src/librustc/lib.rs | 2 +- src/librustc/macros.rs | 19 + src/librustc/session/mod.rs | 5 + src/librustc/traits/select.rs | 15 +- src/librustc/ty/context.rs | 33 + src/librustc/ty/error.rs | 1 + src/librustc/ty/flags.rs | 12 +- src/librustc/ty/mod.rs | 9 +- src/librustc/ty/sty.rs | 12 + src/librustc/ty/subst.rs | 1 + src/librustc/ty/util.rs | 3 + src/librustc/util/ppaux.rs | 9 + src/librustc_borrowck/borrowck/check_loans.rs | 1 + src/librustc_borrowck/borrowck/gather_loans/mod.rs | 1 + src/librustc_const_eval/lib.rs | 1 + src/librustc_data_structures/indexed_vec.rs | 2 +- src/librustc_metadata/lib.rs | 2 + src/librustc_mir/borrow_check/error_reporting.rs | 1 + src/librustc_save_analysis/lib.rs | 1 + src/librustc_typeck/variance/constraints.rs | 1 + src/librustdoc/clean/mod.rs | 1 + 28 files changed, 1121 insertions(+), 16 deletions(-) create mode 100644 src/librustc/infer/canonical.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index d927a151610..ae67d592ba3 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -19,6 +19,7 @@ use std::cell::RefCell; use std::hash as std_hash; use std::mem; use middle::region; +use infer; use traits; use ty; use mir; @@ -85,6 +86,9 @@ for ty::RegionKind { ty::ReEmpty => { // No variant fields to hash for these ... } + ty::ReCanonical(c) => { + c.hash_stable(hcx, hasher); + } ty::ReLateBound(db, ty::BrAnon(i)) => { db.depth.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher); @@ -130,6 +134,16 @@ impl<'a> HashStable> for ty::RegionVid { } } +impl<'gcx> HashStable> for ty::CanonicalVar { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + impl<'a, 'gcx> HashStable> for ty::adjustment::AutoBorrow<'gcx> { fn hash_stable(&self, @@ -1229,11 +1243,52 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable HashStable> +impl<'a> HashStable> for ty::UniverseIndex { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.depth().hash_stable(hcx, hasher); } } + +impl_stable_hash_for!( + impl<'tcx, V> for struct infer::canonical::Canonical<'tcx, V> { + variables, value + } +); + +impl_stable_hash_for!( + impl<'tcx> for struct infer::canonical::CanonicalVarValues<'tcx> { + var_values + } +); + +impl_stable_hash_for!(struct infer::canonical::CanonicalVarInfo { + kind +}); + +impl_stable_hash_for!(enum infer::canonical::CanonicalVarKind { + Ty(k), + Region +}); + +impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind { + General, + Int, + Float +}); + +impl_stable_hash_for!( + impl<'tcx, R> for struct infer::canonical::QueryResult<'tcx, R> { + var_values, region_constraints, certainty, value + } +); + +impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> { + region_outlives, ty_outlives +}); + +impl_stable_hash_for!(enum infer::canonical::Certainty { + Proven, Ambiguous +}); diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs new file mode 100644 index 00000000000..c1c7337860e --- /dev/null +++ b/src/librustc/infer/canonical.rs @@ -0,0 +1,928 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! **Canonicalization** is the key to constructing a query in the +//! middle of type inference. Ordinarily, it is not possible to store +//! types from type inference in query keys, because they contain +//! references to inference variables whose lifetimes are too short +//! and so forth. Canonicalizing a value T1 using `canonicalize_query` +//! produces two things: +//! +//! - a value T2 where each unbound inference variable has been +//! replaced with a **canonical variable**; +//! - a map M (of type `CanonicalVarValues`) from those canonical +//! variables back to the original. +//! +//! We can then do queries using T2. These will give back constriants +//! on the canonical variables which can be translated, using the map +//! M, into constraints in our source context. This process of +//! translating the results back is done by the +//! `instantiate_query_result` method. + +use infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TypeVariableOrigin}; +use rustc_data_structures::indexed_vec::Idx; +use std::fmt::Debug; +use syntax::codemap::Span; +use traits::{Obligation, ObligationCause, PredicateObligation}; +use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags}; +use ty::subst::{Kind, UnpackedKind}; +use ty::fold::{TypeFoldable, TypeFolder}; +use util::common::CellUsizeExt; + +use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::fx::FxHashMap; + +/// A "canonicalized" type `V` is one where all free inference +/// variables have been rewriten to "canonical vars". These are +/// numbered starting from 0 in order of first appearance. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Canonical<'gcx, V> { + pub variables: CanonicalVarInfos<'gcx>, + pub value: V, +} + +pub type CanonicalVarInfos<'gcx> = &'gcx Slice; + +/// A set of values corresponding to the canonical variables from some +/// `Canonical`. You can give these values to +/// `canonical_value.substitute` to substitute them into the canonical +/// value at the right places. +/// +/// When you canonicalize a value `V`, you get back one of these +/// vectors with the original values that were replaced by canonical +/// variables. +/// +/// You can also use `infcx.fresh_inference_vars_for_canonical_vars` +/// to get back a `CanonicalVarValues` containing fresh inference +/// variables. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct CanonicalVarValues<'tcx> { + pub var_values: IndexVec>, +} + +/// Information about a canonical variable that is included with the +/// canonical value. This is sufficient information for code to create +/// a copy of the canonical value in some other inference context, +/// with fresh inference variables replacing the canonical values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct CanonicalVarInfo { + pub kind: CanonicalVarKind, +} + +/// Describes the "kind" of the canonical variable. This is a "kind" +/// in the type-theory sense of the term -- i.e., a "meta" type system +/// that analyzes type-like values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CanonicalVarKind { + /// Some kind of type inference variable. + Ty(CanonicalTyVarKind), + + /// Region variable `'?R`. + Region, +} + +/// Rust actually has more than one category of type variables; +/// notably, the type variables we create for literals (e.g., 22 or +/// 22.) can only be instantiated with integral/float types (e.g., +/// usize or f32). In order to faithfully reproduce a type, we need to +/// know what set of types a given type variable can be unified with. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CanonicalTyVarKind { + /// General type variable `?T` that can be unified with arbitrary types. + General, + + /// Integral type variable `?I` (that can only be unified with integral types). + Int, + + /// Floating-point type variable `?F` (that can only be unified with float types). + Float, +} + +/// After we execute a query with a canonicalized key, we get back a +/// `Canonical>`. You can use +/// `instantiate_query_result` to access the data in this result. +#[derive(Clone, Debug)] +pub struct QueryResult<'tcx, R> { + pub var_values: CanonicalVarValues<'tcx>, + pub region_constraints: QueryRegionConstraints<'tcx>, + pub certainty: Certainty, + pub value: R, +} + +/// Indicates whether or not we were able to prove the query to be +/// true. +#[derive(Copy, Clone, Debug)] +pub enum Certainty { + /// The query is known to be true, presuming that you apply the + /// given `var_values` and the region-constraints are satisfied. + Proven, + + /// The query is not known to be true, but also not known to be + /// false. The `var_values` represent *either* values that must + /// hold in order for the query to be true, or helpful tips that + /// *might* make it true. Currently rustc's trait solver cannot + /// distinguish the two (e.g., due to our preference for where + /// clauses over impls). + /// + /// After some unifiations and things have been done, it makes + /// sense to try and prove again -- of course, at that point, the + /// canonical form will be different, making this a distinct + /// query. + Ambiguous, +} + +impl Certainty { + pub fn is_proven(&self) -> bool { + match self { + Certainty::Proven => true, + Certainty::Ambiguous => false, + } + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, R> QueryResult<'tcx, R> { + pub fn is_proven(&self) -> bool { + self.certainty.is_proven() + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> { + pub fn is_proven(&self) -> bool { + self.value.is_proven() + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +/// Subset of `RegionConstraintData` produced by trait query. +#[derive(Clone, Debug, Default)] +pub struct QueryRegionConstraints<'tcx> { + pub region_outlives: Vec<(Region<'tcx>, Region<'tcx>)>, + pub ty_outlives: Vec<(Ty<'tcx>, Region<'tcx>)>, +} + +/// Trait implemented by values that can be canonicalized. It mainly +/// serves to identify the interning table we will use. +pub trait Canonicalize<'gcx: 'tcx, 'tcx>: TypeFoldable<'tcx> + Lift<'gcx> { + type Canonicalized: 'gcx + Debug; + + /// After a value has been fully canonicalized and lifted, this + /// method will allocate it in a global arena. + fn intern( + gcx: TyCtxt<'_, 'gcx, 'gcx>, + value: Canonical<'gcx, Self::Lifted>, + ) -> Self::Canonicalized; +} + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// Creates a substitution S for the canonical value with fresh + /// inference variables and applies it to the canonical value. + /// Returns both the instantiated result *and* the substitution S. + /// + /// This is useful at the start of a query: it basically brings + /// the canonical value "into scope" within your new infcx. At the + /// end of processing, the substitution S (once canonicalized) + /// then represents the values that you computed for each of the + /// canonical inputs to your query. + pub fn instantiate_canonical_with_fresh_inference_vars( + &self, + span: Span, + canonical: &Canonical<'tcx, T>, + ) -> (T, CanonicalVarValues<'tcx>) + where + T: TypeFoldable<'tcx>, + { + let canonical_inference_vars = + self.fresh_inference_vars_for_canonical_vars(span, canonical.variables); + let result = canonical.substitute(self.tcx, &canonical_inference_vars); + (result, canonical_inference_vars) + } + + /// Given the "infos" about the canonical variables from some + /// canonical, creates fresh inference variables with the same + /// characteristics. You can then use `substitute` to instantiate + /// the canonical variable with these inference variables. + pub fn fresh_inference_vars_for_canonical_vars( + &self, + span: Span, + variables: &Slice, + ) -> CanonicalVarValues<'tcx> { + let var_values: IndexVec> = variables + .iter() + .map(|info| self.fresh_inference_var_for_canonical_var(span, *info)) + .collect(); + + CanonicalVarValues { var_values } + } + + /// Given the "info" about a canonical variable, creates a fresh + /// inference variable with the same characteristics. + pub fn fresh_inference_var_for_canonical_var( + &self, + span: Span, + cv_info: CanonicalVarInfo, + ) -> Kind<'tcx> { + match cv_info.kind { + CanonicalVarKind::Ty(ty_kind) => { + let ty = match ty_kind { + CanonicalTyVarKind::General => { + self.next_ty_var( + // FIXME(#48696) this handling of universes is not right. + ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(span), + ) + } + + CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()), + + CanonicalTyVarKind::Float => self.tcx.mk_float_var(self.next_float_var_id()), + }; + Kind::from(ty) + } + + CanonicalVarKind::Region => { + Kind::from(self.next_region_var(RegionVariableOrigin::MiscVariable(span))) + } + } + } + + /// Given the (canonicalized) result to a canonical query, + /// instantiates the result so it can be used, plugging in the + /// values from the canonical query. (Note that the result may + /// have been ambiguous; you should check the certainty level of + /// the query before applying this function.) + /// + /// It's easiest to explain what is happening here by + /// example. Imagine we start out with the query `?A: Foo<'static, + /// ?B>`. We would canonicalize that by introducing two variables: + /// + /// ?0: Foo<'?1, ?2> + /// + /// (Note that all regions get replaced with variables always, + /// even "known" regions like `'static`.) After canonicalization, + /// we also get back an array with the "original values" for each + /// canonicalized variable: + /// + /// [?A, 'static, ?B] + /// + /// Now we do the query and get back some result R. As part of that + /// result, we'll have an array of values for the canonical inputs. + /// For example, the canonical result might be: + /// + /// ``` + /// for<2> { + /// values = [ Vec, '1, ?0 ] + /// ^^ ^^ ^^ these are variables in the result! + /// ... + /// } + /// ``` + /// + /// Note that this result is itself canonical and may include some + /// variables (in this case, `?0`). + /// + /// What we want to do conceptually is to (a) instantiate each of the + /// canonical variables in the result with a fresh inference variable + /// and then (b) unify the values in the result with the original values. + /// Doing step (a) would yield a result of + /// + /// ``` + /// { + /// values = [ Vec, '?X, ?C ] + /// ^^ ^^^ fresh inference variables in `self` + /// .. + /// } + /// ``` + /// + /// Step (b) would then unify: + /// + /// ``` + /// ?A with Vec + /// 'static with '?X + /// ?B with ?C + /// ``` + /// + /// But what we actually do is a mildly optimized variant of + /// that. Rather than eagerly instantiating all of the canonical + /// values in the result with variables, we instead walk the + /// vector of values, looking for cases where the value is just a + /// canonical variable. In our example, `values[2]` is `?C`, so + /// that we means we can deduce that `?C := ?B and `'?X := + /// 'static`. This gives us a partial set of values. Anything for + /// which we do not find a value, we create an inference variable + /// for. **Then** we unify. + pub fn instantiate_query_result( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + original_values: &CanonicalVarValues<'tcx>, + query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + ) -> InferResult<'tcx, R> + where + R: Debug + TypeFoldable<'tcx>, + { + debug!( + "instantiate_query_result(original_values={:#?}, query_result={:#?})", + original_values, query_result, + ); + + // Every canonical query result includes values for each of + // the inputs to the query. Therefore, we begin by unifying + // these values with the original inputs that were + // canonicalized. + let result_values = &query_result.value.var_values; + assert_eq!(original_values.len(), result_values.len()); + + // Quickly try to find initial values for the canonical + // variables in the result in terms of the query. We do this + // by iterating down the values that the query gave to each of + // the canonical inputs. If we find that one of those values + // is directly equal to one of the canonical variables in the + // result, then we can type the corresponding value from the + // input. See the example above. + let mut opt_values: IndexVec>> = + IndexVec::from_elem_n(None, query_result.variables.len()); + + // In terms of our example above, we are iterating over pairs like: + // [(?A, Vec), ('static, '?1), (?B, ?0)] + for (original_value, result_value) in original_values.iter().zip(result_values) { + match result_value.unpack() { + UnpackedKind::Type(result_value) => { + // e.g., here `result_value` might be `?0` in the example above... + if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty { + // in which case we would set `canonical_vars[0]` to `Some(?U)`. + opt_values[index] = Some(original_value); + } + } + UnpackedKind::Lifetime(result_value) => { + // e.g., here `result_value` might be `'?1` in the example above... + if let &ty::RegionKind::ReCanonical(index) = result_value { + // in which case we would set `canonical_vars[0]` to `Some('static)`. + opt_values[index] = Some(original_value); + } + } + } + } + + // Create a result substitution: if we found a value for a + // given variable in the loop above, use that. Otherwise, use + // a fresh inference variable. + let result_subst = &CanonicalVarValues { + var_values: query_result + .variables + .iter() + .enumerate() + .map(|(index, info)| match opt_values[CanonicalVar::new(index)] { + Some(k) => k, + None => self.fresh_inference_var_for_canonical_var(cause.span, *info), + }) + .collect(), + }; + + // Apply the result substitution to the query. + let QueryResult { + var_values: query_values, + region_constraints: query_region_constraints, + certainty: _, + value: user_result, + } = query_result.substitute(self.tcx, result_subst); + + // Unify the original values for the canonical variables in + // the input with the value found in the query + // post-substitution. Often, but not always, this is a no-op, + // because we already found the mapping in the first step. + let mut obligations = + self.unify_canonical_vars(cause, param_env, original_values, &query_values)? + .into_obligations(); + + obligations.extend(self.query_region_constraints_into_obligations( + cause, + param_env, + query_region_constraints, + )); + + Ok(InferOk { + value: user_result, + obligations, + }) + } + + /// Converts the region constraints resulting from a query into an + /// iterator of obligations. + fn query_region_constraints_into_obligations<'a>( + &self, + cause: &'a ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + query_region_constraints: QueryRegionConstraints<'tcx>, + ) -> impl Iterator> + 'a { + let QueryRegionConstraints { + region_outlives, + ty_outlives, + } = query_region_constraints; + + let region_obligations = region_outlives.into_iter().map(move |(r1, r2)| { + Obligation::new( + cause.clone(), + param_env, + ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))), + ) + }); + + let ty_obligations = ty_outlives.into_iter().map(move |(t1, r2)| { + Obligation::new( + cause.clone(), + param_env, + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))), + ) + }); + + region_obligations.chain(ty_obligations) + } + + /// Given two sets of values for the same set of canonical variables, unify them. + pub fn unify_canonical_vars( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + variables1: &CanonicalVarValues<'tcx>, + variables2: &CanonicalVarValues<'tcx>, + ) -> InferResult<'tcx, ()> { + assert_eq!(variables1.var_values.len(), variables2.var_values.len()); + self.commit_if_ok(|_| { + let mut obligations = vec![]; + for (value1, value2) in variables1.var_values.iter().zip(&variables2.var_values) { + match (value1.unpack(), value2.unpack()) { + (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { + obligations + .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); + } + ( + UnpackedKind::Lifetime(ty::ReErased), + UnpackedKind::Lifetime(ty::ReErased), + ) => { + // no action needed + } + (UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => { + obligations + .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); + } + _ => { + bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); + } + } + } + Ok(InferOk { + value: (), + obligations, + }) + }) + } + + /// Canonicalizes a query value `V`. When we canonicalize a query, + /// we not only canonicalize unbound inference variables, but we + /// *also* replace all free regions whatsoever. So for example a + /// query like `T: Trait<'static>` would be canonicalized to + /// + /// T: Trait<'?0> + /// + /// with a mapping M that maps `'?0` to `'static`. + pub fn canonicalize_query(&self, value: &V) -> (V::Canonicalized, CanonicalVarValues<'tcx>) + where + V: Canonicalize<'gcx, 'tcx>, + { + self.tcx.sess.perf_stats.queries_canonicalized.increment(); + + Canonicalizer::canonicalize( + value, + Some(self), + self.tcx, + CanonicalizeAllFreeRegions(true), + ) + } + + /// Canonicalizes a query *response* `V`. When we canonicalize a + /// query response, we only canonicalize unbound inference + /// variables, and we leave other free regions alone. So, + /// continuing with the example from `canonicalize_query`, if + /// there was an input query `T: Trait<'static>`, it would have + /// been canonicalized to + /// + /// T: Trait<'?0> + /// + /// with a mapping M that maps `'?0` to `'static`. But if we found that there + /// exists only one possible impl of `Trait`, and it looks like + /// + /// impl Trait<'static> for T { .. } + /// + /// then we would prepare a query result R that (among other + /// things) includes a mapping to `'?0 := 'static`. When + /// canonicalizing this query result R, we would leave this + /// reference to `'static` alone. + pub fn canonicalize_response( + &self, + value: &V, + ) -> (V::Canonicalized, CanonicalVarValues<'tcx>) + where + V: Canonicalize<'gcx, 'tcx>, + { + Canonicalizer::canonicalize( + value, + Some(self), + self.tcx, + CanonicalizeAllFreeRegions(false), + ) + } +} + +impl<'cx, 'gcx> TyCtxt<'cx, 'gcx, 'gcx> { + /// Canonicalize a value that doesn't have any inference variables + /// or other things (and we know it). + pub fn canonicalize_global(self, value: &V) -> (V::Canonicalized, CanonicalVarValues<'gcx>) + where + V: Canonicalize<'gcx, 'gcx>, + { + Canonicalizer::canonicalize(value, None, self, CanonicalizeAllFreeRegions(false)) + } +} + +/// If this flag is true, then all free regions will be replaced with +/// a canonical var. This is used to make queries as generic as +/// possible. For example, the query `F: Foo<'static>` would be +/// canonicalized to `F: Foo<'0>`. +struct CanonicalizeAllFreeRegions(bool); + +struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + variables: IndexVec, + indices: FxHashMap, CanonicalVar>, + var_values: IndexVec>, + canonicalize_all_free_regions: CanonicalizeAllFreeRegions, + needs_canonical_flags: TypeFlags, +} + +impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + ty::ReLateBound(..) => { + // leave bound regions alone + r + } + + ty::ReVar(vid) => { + let r = self.infcx + .unwrap() + .borrow_region_constraints() + .opportunistic_resolve_var(self.tcx, vid); + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + }; + debug!( + "canonical: region var found with vid {:?}, \ + opportunistically resolved to {:?}", + vid, r + ); + let cvar = self.canonical_var(info, Kind::from(r)); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } + + ty::ReStatic + | ty::ReEarlyBound(..) + | ty::ReFree(_) + | ty::ReScope(_) + | ty::ReSkolemized(..) + | ty::ReEmpty + | ty::ReErased => { + if self.canonicalize_all_free_regions.0 { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + }; + let cvar = self.canonical_var(info, Kind::from(r)); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } else { + r + } + } + + ty::ReClosureBound(..) | ty::ReCanonical(_) => { + bug!("canonical region encountered during canonicalization") + } + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.sty { + ty::TyInfer(ty::TyVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::General, t), + + ty::TyInfer(ty::IntVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Int, t), + + ty::TyInfer(ty::FloatVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Float, t), + + ty::TyInfer(ty::FreshTy(_)) + | ty::TyInfer(ty::FreshIntTy(_)) + | ty::TyInfer(ty::FreshFloatTy(_)) => { + bug!("encountered a fresh type during canonicalization") + } + + ty::TyInfer(ty::CanonicalTy(_)) => { + bug!("encountered a canonical type during canonicalization") + } + + // Replace a `()` that "would've fallen back" to `!` with just `()`. + ty::TyTuple(ref tys, true) => { + assert!(tys.is_empty()); + self.tcx().mk_nil() + } + + ty::TyClosure(..) + | ty::TyGenerator(..) + | ty::TyGeneratorWitness(..) + | ty::TyBool + | ty::TyChar + | ty::TyInt(..) + | ty::TyUint(..) + | ty::TyFloat(..) + | ty::TyAdt(..) + | ty::TyStr + | ty::TyError + | ty::TyArray(..) + | ty::TySlice(..) + | ty::TyRawPtr(..) + | ty::TyRef(..) + | ty::TyFnDef(..) + | ty::TyFnPtr(_) + | ty::TyDynamic(..) + | ty::TyNever + | ty::TyTuple(_, false) + | ty::TyProjection(..) + | ty::TyForeign(..) + | ty::TyParam(..) + | ty::TyAnon(..) => { + if t.flags.intersects(self.needs_canonical_flags) { + t.super_fold_with(self) + } else { + t + } + } + } + } +} + +impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { + /// The main `canonicalize` method, shared impl of + /// `canonicalize_query` and `canonicalize_response`. + fn canonicalize( + value: &V, + infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + canonicalize_all_free_regions: CanonicalizeAllFreeRegions, + ) -> (V::Canonicalized, CanonicalVarValues<'tcx>) + where + V: Canonicalize<'gcx, 'tcx>, + { + debug_assert!( + !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS), + "canonicalizing a canonical value: {:?}", + value, + ); + + let needs_canonical_flags = if canonicalize_all_free_regions.0 { + TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX + } else { + TypeFlags::KEEP_IN_LOCAL_TCX + }; + + let gcx = tcx.global_tcx(); + + // Fast path: nothing that needs to be canonicalized. + if !value.has_type_flags(needs_canonical_flags) { + let out_value = gcx.lift(value).unwrap(); + let canon_value = V::intern( + gcx, + Canonical { + variables: Slice::empty(), + value: out_value, + }, + ); + let values = CanonicalVarValues { var_values: IndexVec::default() }; + return (canon_value, values); + } + + let mut canonicalizer = Canonicalizer { + infcx, + tcx, + canonicalize_all_free_regions, + needs_canonical_flags, + variables: IndexVec::default(), + indices: FxHashMap::default(), + var_values: IndexVec::default(), + }; + let out_value = value.fold_with(&mut canonicalizer); + + // Once we have canonicalized `out_value`, it should not + // contain anything that ties it to this inference context + // anymore, so it should live in the global arena. + let out_value = gcx.lift(&out_value).unwrap_or_else(|| { + bug!( + "failed to lift `{:?}`, canonicalized from `{:?}`", + out_value, + value + ) + }); + + let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables.raw); + + let canonical_value = V::intern( + gcx, + Canonical { + variables: canonical_variables, + value: out_value, + }, + ); + let canonical_var_values = CanonicalVarValues { + var_values: canonicalizer.var_values, + }; + (canonical_value, canonical_var_values) + } + + /// Creates a canonical variable replacing `kind` from the input, + /// or returns an existing variable if `kind` has already been + /// seen. `kind` is expected to be an unbound variable (or + /// potentially a free region). + fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> CanonicalVar { + let Canonicalizer { + indices, + variables, + var_values, + .. + } = self; + + indices + .entry(kind) + .or_insert_with(|| { + let cvar1 = variables.push(info); + let cvar2 = var_values.push(kind); + assert_eq!(cvar1, cvar2); + cvar1 + }) + .clone() + } + + /// Given a type variable `ty_var` of the given kind, first check + /// if `ty_var` is bound to anything; if so, canonicalize + /// *that*. Otherwise, create a new canonical variable for + /// `ty_var`. + fn canonicalize_ty_var(&mut self, ty_kind: CanonicalTyVarKind, ty_var: Ty<'tcx>) -> Ty<'tcx> { + let infcx = self.infcx.expect("encountered ty-var without infcx"); + let bound_to = infcx.shallow_resolve(ty_var); + if bound_to != ty_var { + self.fold_ty(bound_to) + } else { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Ty(ty_kind), + }; + let cvar = self.canonical_var(info, Kind::from(ty_var)); + self.tcx().mk_infer(ty::InferTy::CanonicalTy(cvar)) + } + } +} + +impl<'tcx, V> Canonical<'tcx, V> { + /// Instantiate the wrapped value, replacing each canonical value + /// with the value given in `var_values`. + pub fn substitute(&self, tcx: TyCtxt<'_, '_, 'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V + where + V: TypeFoldable<'tcx>, + { + assert_eq!(self.variables.len(), var_values.var_values.len()); + self.value + .fold_with(&mut CanonicalVarValuesSubst { tcx, var_values }) + } +} + +struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + var_values: &'cx CanonicalVarValues<'tcx>, +} + +impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.sty { + ty::TyInfer(ty::InferTy::CanonicalTy(c)) => { + match self.var_values.var_values[c].unpack() { + UnpackedKind::Type(ty) => ty, + r => bug!("{:?} is a type but value is {:?}", c, r), + } + } + _ => t.super_fold_with(self), + } + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match r { + ty::RegionKind::ReCanonical(c) => match self.var_values.var_values[*c].unpack() { + UnpackedKind::Lifetime(l) => l, + r => bug!("{:?} is a region but value is {:?}", c, r), + }, + _ => r.super_fold_with(self), + } + } +} + +CloneTypeFoldableAndLiftImpls! { + for <'tcx> { + ::infer::canonical::Certainty, + ::infer::canonical::CanonicalVarInfo, + ::infer::canonical::CanonicalVarInfos<'tcx>, + ::infer::canonical::CanonicalVarKind, + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx, C> TypeFoldable<'tcx> for Canonical<'tcx, C> { + variables, + value, + } where C: TypeFoldable<'tcx> +} + +impl<'tcx> CanonicalVarValues<'tcx> { + fn iter<'a>(&'a self) -> impl Iterator> + 'a { + self.var_values.iter().cloned() + } + + fn len(&self) -> usize { + self.var_values.len() + } +} + +impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { + type Item = Kind<'tcx>; + type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, Kind<'tcx>>>; + + fn into_iter(self) -> Self::IntoIter { + self.var_values.iter().cloned() + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for CanonicalVarValues<'a> { + type Lifted = CanonicalVarValues<'tcx>; + var_values, + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for CanonicalVarValues<'tcx> { + var_values, + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> { + region_outlives, ty_outlives + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> { + type Lifted = QueryRegionConstraints<'tcx>; + region_outlives, ty_outlives + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> { + var_values, region_constraints, certainty, value + } where R: TypeFoldable<'tcx>, +} + +BraceStructLiftImpl! { + impl<'a, 'tcx, R> Lift<'tcx> for QueryResult<'a, R> { + type Lifted = QueryResult<'tcx, R::Lifted>; + var_values, region_constraints, certainty, value + } where R: Lift<'tcx> +} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 469cb459112..1c581c44464 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -476,6 +476,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' } } + ty::ReCanonical(..) | ty::ReClosureBound(..) => { span_bug!( self.span, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 07551c4ebd3..96c23098821 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -154,6 +154,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We shouldn't encounter an error message with ReClosureBound. + ty::ReCanonical(..) | ty::ReClosureBound(..) => { bug!("encountered unexpected ReClosureBound: {:?}", region,); } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index ee0921f4b07..6074bfd083d 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -114,9 +114,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { self.tcx().types.re_erased } + ty::ReCanonical(..) | ty::ReClosureBound(..) => { bug!( - "encountered unexpected ReClosureBound: {:?}", + "encountered unexpected region: {:?}", r, ); } @@ -170,6 +171,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { t } + ty::TyInfer(ty::CanonicalTy(..)) => + bug!("encountered canonical ty during freshening"), + ty::TyGenerator(..) | ty::TyBool | ty::TyChar | diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 3ac4ec5bee4..00b2ac7449f 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -258,6 +258,8 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { let tcx = self.region_rels.tcx; match (a, b) { + (&ty::ReCanonical(..), _) | + (_, &ty::ReCanonical(..)) | (&ty::ReClosureBound(..), _) | (_, &ty::ReClosureBound(..)) | (&ReLateBound(..), _) | diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 5f0c2d1e76b..5127807bf70 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -50,6 +50,7 @@ use self::unify_key::ToType; pub mod anon_types; pub mod at; +pub mod canonical; mod combine; mod equate; pub mod error_reporting; @@ -473,6 +474,12 @@ impl<'tcx, T> InferOk<'tcx, T> { } } +impl<'tcx> InferOk<'tcx, ()> { + pub fn into_obligations(self) -> PredicateObligations<'tcx> { + self.obligations + } +} + #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx:'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, @@ -1644,4 +1651,3 @@ impl<'tcx> fmt::Debug for RegionObligation<'tcx> { self.sup_type) } } - diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 2cf17603629..77b3a87c0ed 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -57,9 +57,9 @@ #![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![cfg_attr(windows, feature(libc))] +#![feature(match_default_bindings)] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] -#![feature(match_default_bindings)] #![feature(never_type)] #![feature(non_exhaustive)] #![feature(nonzero)] diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 6013e3aef81..d8a723e184d 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -119,6 +119,25 @@ macro_rules! impl_stable_hash_for { } } }; + + (impl<$tcx:lifetime $(, $T:ident)*> for struct $struct_name:path { + $($field:ident),* $(,)* + }) => { + impl<'a, $tcx, $($T,)*> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name + where $($T: ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>>),* + { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name { + $(ref $field),* + } = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; } #[macro_export] diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 01e1037b622..7b4211e487a 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -173,6 +173,8 @@ pub struct PerfStats { pub symbol_hash_time: Cell, /// The accumulated time spent decoding def path tables from metadata pub decode_def_path_tables_time: Cell, + /// Total number of values canonicalized queries constructed. + pub queries_canonicalized: Cell, } /// Enum to support dispatch of one-time diagnostics (in Session.diag_once) @@ -858,6 +860,8 @@ impl Session { "Total time spent decoding DefPath tables: {}", duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()) ); + println!("Total queries canonicalized: {}", + self.perf_stats.queries_canonicalized.get()); } /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. @@ -1144,6 +1148,7 @@ pub fn build_session_( incr_comp_bytes_hashed: Cell::new(0), symbol_hash_time: Cell::new(Duration::from_secs(0)), decode_def_path_tables_time: Cell::new(Duration::from_secs(0)), + queries_canonicalized: Cell::new(0), }, code_stats: RefCell::new(CodeStats::new()), optimization_fuel_crate, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 728702ef61f..f2f54dcedfd 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2083,9 +2083,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, ty::TyInfer(ty::TyVar(_)) => Ambiguous, - ty::TyInfer(ty::FreshTy(_)) - | ty::TyInfer(ty::FreshIntTy(_)) - | ty::TyInfer(ty::FreshFloatTy(_)) => { + ty::TyInfer(ty::CanonicalTy(_)) | + ty::TyInfer(ty::FreshTy(_)) | + ty::TyInfer(ty::FreshIntTy(_)) | + ty::TyInfer(ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } @@ -2154,9 +2155,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ambiguous } - ty::TyInfer(ty::FreshTy(_)) - | ty::TyInfer(ty::FreshIntTy(_)) - | ty::TyInfer(ty::FreshFloatTy(_)) => { + ty::TyInfer(ty::CanonicalTy(_)) | + ty::TyInfer(ty::FreshTy(_)) | + ty::TyInfer(ty::FreshIntTy(_)) | + ty::TyInfer(ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } @@ -2195,6 +2197,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyParam(..) | ty::TyForeign(..) | ty::TyProjection(..) | + ty::TyInfer(ty::CanonicalTy(_)) | ty::TyInfer(ty::TyVar(_)) | ty::TyInfer(ty::FreshTy(_)) | ty::TyInfer(ty::FreshIntTy(_)) | diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e7d6bdd3383..24d3b37f804 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -23,6 +23,7 @@ use hir::map as hir_map; use hir::map::DefPathHash; use lint::{self, Lint}; use ich::{StableHashingContext, NodeIdHashingMode}; +use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use infer::outlives::free_region_map::FreeRegionMap; use middle::const_val::ConstVal; use middle::cstore::{CrateStore, LinkMeta}; @@ -131,6 +132,7 @@ pub struct CtxtInterners<'tcx> { type_: RefCell>>>, type_list: RefCell>>>>, substs: RefCell>>>, + canonical_var_infos: RefCell>>>, region: RefCell>>, existential_predicates: RefCell>>>>, predicates: RefCell>>>>, @@ -146,6 +148,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { substs: RefCell::new(FxHashSet()), region: RefCell::new(FxHashSet()), existential_predicates: RefCell::new(FxHashSet()), + canonical_var_infos: RefCell::new(FxHashSet()), predicates: RefCell::new(FxHashSet()), const_: RefCell::new(FxHashSet()), } @@ -1838,6 +1841,12 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, Slice>> { } } +impl<'tcx: 'lcx, 'lcx> Borrow<[CanonicalVarInfo]> for Interned<'tcx, Slice> { + fn borrow<'a>(&'a self) -> &'a [CanonicalVarInfo] { + &self.0[..] + } +} + impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> { fn borrow<'a>(&'a self) -> &'a [Kind<'lcx>] { &self.0[..] @@ -1970,6 +1979,22 @@ slice_interners!( substs: _intern_substs(Kind) ); +// This isn't a perfect fit: CanonicalVarInfo slices are always +// allocated in the global arena, so this `intern_method!` macro is +// overly general. But we just return false for the code that checks +// whether they belong in the thread-local arena, so no harm done, and +// seems better than open-coding the rest. +intern_method! { + 'tcx, + canonical_var_infos: _intern_canonical_var_infos( + &[CanonicalVarInfo], + alloc_slice, + Deref::deref, + |xs: &[CanonicalVarInfo]| -> &Slice { unsafe { mem::transmute(xs) } }, + |_xs: &[CanonicalVarInfo]| -> bool { false } + ) -> Slice +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Given a `fn` type, returns an equivalent `unsafe fn` type; /// that is, a `fn` type that is equivalent in every way for being @@ -2257,6 +2282,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'gcx> { + if ts.len() == 0 { + Slice::empty() + } else { + self.global_tcx()._intern_canonical_var_infos(ts) + } + } + pub fn mk_fn_sig(self, inputs: I, output: I::Item, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index dcb70a8f86a..8a0253ed2f1 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -220,6 +220,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(), ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(), + ty::TyInfer(ty::CanonicalTy(_)) | ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(), ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(), ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(), diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index f067789771c..cae64fd4c95 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -112,8 +112,16 @@ impl FlagComputation { match infer { ty::FreshTy(_) | ty::FreshIntTy(_) | - ty::FreshFloatTy(_) => {} - _ => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX) + ty::FreshFloatTy(_) | + ty::CanonicalTy(_) => { + self.add_flags(TypeFlags::HAS_CANONICAL_VARS); + } + + ty::TyVar(_) | + ty::IntVar(_) | + ty::FloatVar(_) => { + self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX) + } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e3405e0c3b3..93d1585cdc8 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -60,7 +60,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, use hir; -pub use self::sty::{Binder, DebruijnIndex}; +pub use self::sty::{Binder, CanonicalVar, DebruijnIndex}; pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut}; @@ -452,6 +452,10 @@ bitflags! { // Currently we can't normalize projections w/ bound regions. const HAS_NORMALIZABLE_PROJECTION = 1 << 12; + // Set if this includes a "canonical" type or region var -- + // ought to be true only for the results of canonicalization. + const HAS_CANONICAL_VARS = 1 << 13; + const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_SELF.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; @@ -470,7 +474,8 @@ bitflags! { TypeFlags::HAS_PROJECTION.bits | TypeFlags::HAS_TY_CLOSURE.bits | TypeFlags::HAS_LOCAL_NAMES.bits | - TypeFlags::KEEP_IN_LOCAL_TCX.bits; + TypeFlags::KEEP_IN_LOCAL_TCX.bits | + TypeFlags::HAS_CANONICAL_VARS.bits; } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7bcc816b5f0..109422564c8 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1047,6 +1047,9 @@ pub enum RegionKind { /// `ClosureRegionRequirements` that are produced by MIR borrowck. /// See `ClosureRegionRequirements` for more details. ReClosureBound(RegionVid), + + /// Canonicalized region, used only when preparing a trait query. + ReCanonical(CanonicalVar), } impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {} @@ -1091,8 +1094,13 @@ pub enum InferTy { FreshTy(u32), FreshIntTy(u32), FreshFloatTy(u32), + + /// Canonicalized type variable, used only when preparing a trait query. + CanonicalTy(CanonicalVar), } +newtype_index!(CanonicalVar); + /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExistentialProjection<'tcx> { @@ -1213,6 +1221,10 @@ impl RegionKind { } ty::ReErased => { } + ty::ReCanonical(..) => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_CANONICAL_VARS; + } ty::ReClosureBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index e70c72335aa..a301049fe1c 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -40,6 +40,7 @@ const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; +#[derive(Debug)] pub enum UnpackedKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index a7ee8579fb9..e8ce49d39d2 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -834,6 +834,9 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> ty::ReEmpty => { // No variant fields to hash for these ... } + ty::ReCanonical(c) => { + self.hash(c); + } ty::ReLateBound(db, ty::BrAnon(i)) => { self.hash(db.depth); self.hash(i); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 5e2792ee641..efa53c775ae 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -721,6 +721,9 @@ define_print! { ty::ReEarlyBound(ref data) => { write!(f, "{}", data.name) } + ty::ReCanonical(_) => { + write!(f, "'_") + } ty::ReLateBound(_, br) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::ReSkolemized(_, br) => { @@ -785,6 +788,10 @@ define_print! { write!(f, "{:?}", vid) } + ty::ReCanonical(c) => { + write!(f, "'?{}", c.index()) + } + ty::ReSkolemized(id, ref bound_region) => { write!(f, "ReSkolemized({:?}, {:?})", id, bound_region) } @@ -888,6 +895,7 @@ define_print! { ty::TyVar(_) => write!(f, "_"), ty::IntVar(_) => write!(f, "{}", "{integer}"), ty::FloatVar(_) => write!(f, "{}", "{float}"), + ty::CanonicalTy(_) => write!(f, "_"), ty::FreshTy(v) => write!(f, "FreshTy({})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) @@ -899,6 +907,7 @@ define_print! { ty::TyVar(ref v) => write!(f, "{:?}", v), ty::IntVar(ref v) => write!(f, "{:?}", v), ty::FloatVar(ref v) => write!(f, "{:?}", v), + ty::CanonicalTy(v) => write!(f, "?{:?}", v.index()), ty::FreshTy(v) => write!(f, "FreshTy({:?})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v) diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 9888b2fffc7..a01b3cbf47b 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -427,6 +427,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // These cannot exist in borrowck RegionKind::ReVar(..) | + RegionKind::ReCanonical(..) | RegionKind::ReSkolemized(..) | RegionKind::ReClosureBound(..) | RegionKind::ReErased => span_bug!(borrow_span, diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 5cbe2822e5c..49234f4ed7f 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -366,6 +366,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { ty::ReStatic => self.item_ub, + ty::ReCanonical(_) | ty::ReEmpty | ty::ReClosureBound(..) | ty::ReLateBound(..) | diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 9d636b48bd0..459aa9ea488 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -23,6 +23,7 @@ #![feature(slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(macro_lifetime_matcher)] #![feature(i128_type)] #![feature(from_ref)] diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 11c2bd73687..a5b1a7e57ab 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -330,7 +330,7 @@ macro_rules! newtype_index { ); } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct IndexVec { pub raw: Vec, _marker: PhantomData diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index da0da622d52..f77c22bd895 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -18,7 +18,9 @@ #![feature(fs_read_write)] #![feature(i128_type)] #![feature(libc)] +#![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] +#![feature(macro_lifetime_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(specialization)] diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 7ab52e98a0e..84ba1367450 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -457,6 +457,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (RegionKind::ReLateBound(_, _), _) | (RegionKind::ReSkolemized(_, _), _) | (RegionKind::ReClosureBound(_), _) + | (RegionKind::ReCanonical(_), _) | (RegionKind::ReErased, _) => { span_bug!(drop_span, "region does not make sense in this context"); } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 490dc4e5ac4..95374775651 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -13,6 +13,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] #![feature(custom_attribute)] +#![feature(macro_lifetime_matcher)] #![allow(unused_attributes)] #[macro_use] diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 44ac7a10e82..2a4e92034de 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -423,6 +423,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // way early-bound regions do, so we skip them here. } + ty::ReCanonical(_) | ty::ReFree(..) | ty::ReClosureBound(..) | ty::ReScope(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5d4addce2c4..ff281a53ab7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1490,6 +1490,7 @@ impl Clean> for ty::RegionKind { ty::ReSkolemized(..) | ty::ReEmpty | ty::ReClosureBound(_) | + ty::ReCanonical(_) | ty::ReErased => None } } -- cgit 1.4.1-3-g733a5 From 1dbc84d0066c4689a1e3de21f5a22d87e74a2ac1 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Wed, 7 Mar 2018 02:43:50 +0100 Subject: Remove rustc_global! --- src/librustc_data_structures/sync.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index d7cd459e577..f066ea98f91 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -26,11 +26,6 @@ //! //! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false. //! -//! `rustc_global!` gives us a way to declare variables which are intended to be -//! global for the current rustc session. This currently maps to thread-locals, -//! since rustdoc uses the rustc libraries in multiple threads. -//! These globals should eventually be moved into the `Session` structure. -//! //! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync //! depending on the value of cfg!(parallel_queries). @@ -228,31 +223,6 @@ pub fn assert_sync() {} pub fn assert_send_val(_t: &T) {} pub fn assert_send_sync_val(_t: &T) {} -#[macro_export] -#[allow_internal_unstable] -macro_rules! rustc_global { - // empty (base case for the recursion) - () => {}; - - // process multiple declarations - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - thread_local!($(#[$attr])* $vis static $name: $t = $init); - rustc_global!($($rest)*); - ); - - // handle a single declaration - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( - thread_local!($(#[$attr])* $vis static $name: $t = $init); - ); -} - -#[macro_export] -macro_rules! rustc_access_global { - ($name:path, $callback:expr) => { - $name.with($callback) - } -} - impl Debug for LockCell { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("LockCell") -- cgit 1.4.1-3-g733a5 From 8e5eb025a2b438eaaf609894ed910458078cc899 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Wed, 14 Mar 2018 20:13:42 +0100 Subject: Add an Default impl for Lock --- src/librustc_data_structures/sync.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index f066ea98f91..184ef136976 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -333,6 +333,13 @@ impl Lock { } } +impl Default for Lock { + #[inline] + fn default() -> Self { + Lock::new(T::default()) + } +} + // FIXME: Probably a bad idea impl Clone for Lock { #[inline] -- cgit 1.4.1-3-g733a5 From 37f9c7ff8281696545c72fc4f24e61d72b9e8df4 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Thu, 15 Mar 2018 10:38:12 +0100 Subject: Add OnDrop --- src/librustc_data_structures/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 81246aea1b5..bf0b3726bb3 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -76,6 +76,14 @@ pub mod flock; pub mod sync; pub mod owning_ref; +pub struct OnDrop(pub F); + +impl Drop for OnDrop { + fn drop(&mut self) { + (self.0)(); + } +} + // See comments in src/librustc/lib.rs #[doc(hidden)] pub fn __noop_fix_for_27438() {} -- cgit 1.4.1-3-g733a5 From 67f46ce1122121849890ad51c35f0eb6ded14b6f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 16 Feb 2018 11:02:06 +0100 Subject: Use num::NonZero* instead of NonZero<_> in rustc and tests --- src/libcore/tests/nonzero.rs | 14 +++++----- src/librustc/ty/subst.rs | 6 ++--- .../obligation_forest/node_index.rs | 6 ++--- src/librustc_mir/dataflow/move_paths/mod.rs | 6 ++--- src/test/run-pass/enum-null-pointer-opt.rs | 9 +++---- src/test/run-pass/issue-23433.rs | 2 +- src/test/ui/print_type_sizes/niche-filling.rs | 31 ++++++++-------------- src/test/ui/print_type_sizes/niche-filling.stdout | 10 ++++--- 8 files changed, 38 insertions(+), 46 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index a795dd57504..9eaf7529dd3 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::nonzero::NonZero; +use core::num::NonZeroU32; use core::option::Option; use core::option::Option::{Some, None}; use std::mem::size_of; @@ -16,28 +16,28 @@ use std::mem::size_of; #[test] fn test_create_nonzero_instance() { let _a = unsafe { - NonZero::new_unchecked(21) + NonZeroU32::new_unchecked(21) }; } #[test] fn test_size_nonzero_in_option() { - assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::(), size_of::>()); } #[test] fn test_match_on_nonzero_option() { let a = Some(unsafe { - NonZero::new_unchecked(42) + NonZeroU32::new_unchecked(42) }); match a { Some(val) => assert_eq!(val.get(), 42), - None => panic!("unexpected None while matching on Some(NonZero(_))") + None => panic!("unexpected None while matching on Some(NonZeroU32(_))") } - match unsafe { Some(NonZero::new_unchecked(43)) } { + match unsafe { Some(NonZeroU32::new_unchecked(43)) } { Some(val) => assert_eq!(val.get(), 43), - None => panic!("unexpected None while matching on Some(NonZero(_))") + None => panic!("unexpected None while matching on Some(NonZeroU32(_))") } } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index a301049fe1c..e7b58ae1564 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -19,11 +19,11 @@ use syntax_pos::{Span, DUMMY_SP}; use rustc_data_structures::accumulate_vec::AccumulateVec; use core::intrinsics; -use core::nonzero::NonZero; use std::fmt; use std::iter; use std::marker::PhantomData; use std::mem; +use std::num::NonZeroUsize; /// An entity in the Rust typesystem, which can be one of /// several kinds (only types and lifetimes for now). @@ -32,7 +32,7 @@ use std::mem; /// indicate the type (`Ty` or `Region`) it points to. #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct Kind<'tcx> { - ptr: NonZero, + ptr: NonZeroUsize, marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)> } @@ -63,7 +63,7 @@ impl<'tcx> UnpackedKind<'tcx> { Kind { ptr: unsafe { - NonZero::new_unchecked(ptr | tag) + NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs index a72cc6b57ea..37512e4bcd5 100644 --- a/src/librustc_data_structures/obligation_forest/node_index.rs +++ b/src/librustc_data_structures/obligation_forest/node_index.rs @@ -8,18 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::nonzero::NonZero; +use std::num::NonZeroU32; use std::u32; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct NodeIndex { - index: NonZero, + index: NonZeroU32, } impl NodeIndex { pub fn new(value: usize) -> NodeIndex { assert!(value < (u32::MAX as usize)); - NodeIndex { index: NonZero::new((value as u32) + 1).unwrap() } + NodeIndex { index: NonZeroU32::new((value as u32) + 1).unwrap() } } pub fn get(self) -> usize { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 7b6ebc6fba8..9f6cf8c036e 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -29,17 +29,17 @@ mod abs_domain; // (which is likely to yield a subtle off-by-one error). pub(crate) mod indexes { use std::fmt; - use core::nonzero::NonZero; + use std::num::NonZeroUsize; use rustc_data_structures::indexed_vec::Idx; macro_rules! new_index { ($Index:ident, $debug_name:expr) => { #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub struct $Index(NonZero); + pub struct $Index(NonZeroUsize); impl Idx for $Index { fn new(idx: usize) -> Self { - $Index(NonZero::new(idx + 1).unwrap()) + $Index(NonZeroUsize::new(idx + 1).unwrap()) } fn index(self) -> usize { self.0.get() - 1 diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index e296aff2782..12f17a1575e 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -10,10 +10,9 @@ #![feature(nonzero, core)] -extern crate core; - -use core::nonzero::NonZero; use std::mem::size_of; +use std::num::NonZeroUsize; +use std::ptr::NonNull; use std::rc::Rc; use std::sync::Arc; @@ -59,8 +58,8 @@ fn main() { assert_eq!(size_of::<[Box; 1]>(), size_of::; 1]>>()); // Should apply to NonZero - assert_eq!(size_of::>(), size_of::>>()); - assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::(), size_of::>()); + assert_eq!(size_of::>(), size_of::>>()); // Should apply to types that use NonZero internally assert_eq!(size_of::>(), size_of::>>()); diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index 7af732f561d..9547b2f08a6 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Don't fail if we encounter a NonZero<*T> where T is an unsized type +// Don't fail if we encounter a NonNull where T is an unsized type use std::ptr::NonNull; diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index 7f234e243e9..875883a2cca 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -14,7 +14,7 @@ // This file illustrates how niche-filling enums are handled, // modelled after cases like `Option<&u32>`, `Option` and such. // -// It uses NonZero directly, rather than `&_` or `Unique<_>`, because +// It uses NonZeroU32 rather than `&_` or `Unique<_>`, because // the test is not set up to deal with target-dependent pointer width. // // It avoids using u64/i64 because on some targets that is only 4-byte @@ -25,8 +25,7 @@ #![feature(nonzero)] #![allow(dead_code)] -extern crate core; -use core::nonzero::{NonZero, Zeroable}; +use std::num::NonZeroU32; pub enum MyOption { None, Some(T) } @@ -36,7 +35,7 @@ impl Default for MyOption { pub enum EmbeddedDiscr { None, - Record { pre: u8, val: NonZero, post: u16 }, + Record { pre: u8, val: NonZeroU32, post: u16 }, } impl Default for EmbeddedDiscr { @@ -44,32 +43,24 @@ impl Default for EmbeddedDiscr { } #[derive(Default)] -pub struct IndirectNonZero { +pub struct IndirectNonZero { pre: u8, - nested: NestedNonZero, + nested: NestedNonZero, post: u16, } -pub struct NestedNonZero { +pub struct NestedNonZero { pre: u8, - val: NonZero, + val: NonZeroU32, post: u16, } -impl Default for NestedNonZero { +impl Default for NestedNonZero { fn default() -> Self { - NestedNonZero { pre: 0, val: NonZero::new(T::one()).unwrap(), post: 0 } + NestedNonZero { pre: 0, val: NonZeroU32::new(1).unwrap(), post: 0 } } } -pub trait One { - fn one() -> Self; -} - -impl One for u32 { - fn one() -> Self { 1 } -} - pub enum Enum4 { One(A), Two(B), @@ -79,9 +70,9 @@ pub enum Enum4 { #[start] fn start(_: isize, _: *const *const u8) -> isize { - let _x: MyOption> = Default::default(); + let _x: MyOption = Default::default(); let _y: EmbeddedDiscr = Default::default(); - let _z: MyOption> = Default::default(); + let _z: MyOption = Default::default(); let _a: MyOption = Default::default(); let _b: MyOption = Default::default(); let _c: MyOption = Default::default(); diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout index 0f53e7722dd..79f9ef5a231 100644 --- a/src/test/ui/print_type_sizes/niche-filling.stdout +++ b/src/test/ui/print_type_sizes/niche-filling.stdout @@ -1,9 +1,9 @@ -print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes +print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes print-type-size field `.nested`: 8 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes -print-type-size type: `MyOption>`: 12 bytes, alignment: 4 bytes +print-type-size type: `MyOption`: 12 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 12 bytes print-type-size field `.0`: 12 bytes @@ -14,7 +14,7 @@ print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes -print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes +print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes @@ -32,12 +32,14 @@ print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes -print-type-size type: `MyOption>`: 4 bytes, alignment: 4 bytes +print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `core::nonzero::NonZero`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes +print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes +print-type-size field `.0`: 4 bytes print-type-size type: `Enum4<(), (), (), MyOption>`: 2 bytes, alignment: 1 bytes print-type-size variant `One`: 0 bytes print-type-size field `.0`: 0 bytes -- cgit 1.4.1-3-g733a5 From c43b1a09e034f978317bf087214f8f4cde80ba40 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 15 Mar 2018 18:56:20 -0400 Subject: Convert SerializedDepGraph to be a struct-of-arrays Fixes #47326 --- src/librustc/dep_graph/graph.rs | 7 +++---- src/librustc/dep_graph/prev.rs | 8 ++++---- src/librustc/dep_graph/serialized.rs | 6 +++++- src/librustc_data_structures/indexed_vec.rs | 7 +++++++ src/librustc_incremental/persist/save.rs | 2 +- 5 files changed, 20 insertions(+), 10 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 0ad79eacd2b..d60c22064d3 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -476,10 +476,8 @@ impl DepGraph { fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::ZERO); } - let nodes: IndexVec<_, (DepNode, Fingerprint)> = - current_dep_graph.nodes.iter_enumerated().map(|(idx, &dep_node)| { - (dep_node, fingerprints[idx]) - }).collect(); + let fingerprints = fingerprints.clone().convert_index_type(); + let nodes = current_dep_graph.nodes.clone().convert_index_type(); let total_edge_count: usize = current_dep_graph.edges.iter() .map(|v| v.len()) @@ -503,6 +501,7 @@ impl DepGraph { SerializedDepGraph { nodes, + fingerprints, edge_list_indices, edge_list_data, } diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs index 504b60e763e..669a99019aa 100644 --- a/src/librustc/dep_graph/prev.rs +++ b/src/librustc/dep_graph/prev.rs @@ -23,7 +23,7 @@ impl PreviousDepGraph { pub fn new(data: SerializedDepGraph) -> PreviousDepGraph { let index: FxHashMap<_, _> = data.nodes .iter_enumerated() - .map(|(idx, &(dep_node, _))| (dep_node, idx)) + .map(|(idx, &dep_node)| (dep_node, idx)) .collect(); PreviousDepGraph { data, index } } @@ -41,7 +41,7 @@ impl PreviousDepGraph { #[inline] pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { - self.data.nodes[dep_node_index].0 + self.data.nodes[dep_node_index] } #[inline] @@ -58,14 +58,14 @@ impl PreviousDepGraph { pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { self.index .get(dep_node) - .map(|&node_index| self.data.nodes[node_index].1) + .map(|&node_index| self.data.fingerprints[node_index]) } #[inline] pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint { - self.data.nodes[dep_node_index].1 + self.data.fingerprints[dep_node_index] } pub fn node_count(&self) -> usize { diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs index c96040ab9b6..60fc813a25d 100644 --- a/src/librustc/dep_graph/serialized.rs +++ b/src/librustc/dep_graph/serialized.rs @@ -20,7 +20,10 @@ newtype_index!(SerializedDepNodeIndex); #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedDepGraph { /// The set of all DepNodes in the graph - pub nodes: IndexVec, + pub nodes: IndexVec, + /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to + /// the DepNode at the same index in the nodes vector. + pub fingerprints: IndexVec, /// For each DepNode, stores the list of edges originating from that /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, /// which holds the actual DepNodeIndices of the target nodes. @@ -35,6 +38,7 @@ impl SerializedDepGraph { pub fn new() -> SerializedDepGraph { SerializedDepGraph { nodes: IndexVec::new(), + fingerprints: IndexVec::new(), edge_list_indices: IndexVec::new(), edge_list_data: Vec::new(), } diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index a5b1a7e57ab..cbb3ff51715 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -503,6 +503,13 @@ impl IndexVec { (c1, c2) } } + + pub fn convert_index_type(self) -> IndexVec { + IndexVec { + raw: self.raw, + _marker: PhantomData, + } + } } impl IndexVec { diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index ca1e3563089..a5bc1106ba0 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -162,7 +162,7 @@ fn encode_dep_graph(tcx: TyCtxt, let mut counts: FxHashMap<_, Stat> = FxHashMap(); - for (i, &(node, _)) in serialized_graph.nodes.iter_enumerated() { + for (i, &node) in serialized_graph.nodes.iter_enumerated() { let stat = counts.entry(node.kind).or_insert(Stat { kind: node.kind, node_counter: 0, -- cgit 1.4.1-3-g733a5 From 619003d1d414167630331efffe83702f74413be6 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Tue, 20 Mar 2018 05:33:59 -0400 Subject: Implement some trivial size_hints for various iterators This also implements ExactSizeIterator where applicable. Addresses most of the Iterator traits mentioned in #23708. --- src/libcore/char.rs | 5 +++++ src/libcore/iter/traits.rs | 4 ++++ src/libcore/option.rs | 5 +++++ src/librustc/hir/pat_util.rs | 4 ++++ src/librustc/mir/traversal.rs | 26 ++++++++++++++++++++++++++ src/librustc/session/search_paths.rs | 7 +++++++ src/librustc/traits/util.rs | 5 +++++ src/librustc_data_structures/bitvec.rs | 5 +++++ src/librustc_data_structures/graph/mod.rs | 13 +++++++++++++ src/librustc_driver/pretty.rs | 7 +++++++ src/librustc_typeck/check/method/suggest.rs | 7 +++++++ src/librustdoc/clean/mod.rs | 5 +++++ src/libsyntax_ext/format_foreign.rs | 9 +++++++++ 13 files changed, 102 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 1638f9710f5..2f56238a463 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -902,6 +902,11 @@ impl> Iterator for DecodeUtf8 { } }) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } } #[unstable(feature = "decode_utf8", issue = "33906")] diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 0267fcd3754..5e4622f804a 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -901,6 +901,10 @@ impl Iterator for ResultShunt None => None, } } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } #[stable(feature = "iter_arith_traits_result", since="1.16.0")] diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 570f745f833..1ca69f3f503 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1188,6 +1188,11 @@ impl> FromIterator> for Option { None => None, } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } let mut adapter = Adapter { iter: iter.into_iter(), found_none: false }; diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 2bec224362e..1f00a3ab1f5 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -31,6 +31,10 @@ impl Iterator for EnumerateAndAdjust where I: Iterator { (if i < self.gap_pos { i } else { i + self.gap_len }, elem) }) } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } } pub trait EnumerateAndAdjustIterator { diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 74c3408c4c2..666ca5eabe8 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -77,8 +77,18 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { None } + + fn size_hint(&self) -> (usize, Option) { + // All the blocks, minus the number of blocks we've visited. + let remaining = self.mir.basic_blocks().len() - self.visited.count(); + + // We will visit all remaining blocks exactly once. + (remaining, Some(remaining)) + } } +impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {} + /// Postorder traversal of a graph. /// /// Postorder traversal is when each node is visited after all of it's @@ -210,8 +220,18 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { next.map(|(bb, _)| (bb, &self.mir[bb])) } + + fn size_hint(&self) -> (usize, Option) { + // All the blocks, minus the number of blocks we've visited. + let remaining = self.mir.basic_blocks().len() - self.visited.count(); + + // We will visit all remaining blocks exactly once. + (remaining, Some(remaining)) + } } +impl<'a, 'tcx> ExactSizeIterator for Postorder<'a, 'tcx> {} + /// Reverse postorder traversal of a graph /// /// Reverse postorder is the reverse order of a postorder traversal. @@ -276,4 +296,10 @@ impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> { self.blocks.get(self.idx).map(|&bb| (bb, &self.mir[bb])) } + + fn size_hint(&self) -> (usize, Option) { + (self.idx, Some(self.idx)) + } } + +impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {} diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs index 5bbc6841693..d2dca9f6084 100644 --- a/src/librustc/session/search_paths.rs +++ b/src/librustc/session/search_paths.rs @@ -78,4 +78,11 @@ impl<'a> Iterator for Iter<'a> { } } } + + fn size_hint(&self) -> (usize, Option) { + // This iterator will never return more elements than the base iterator; + // but it can ignore all the remaining elements. + let (_, upper) = self.iter.size_hint(); + (0, upper) + } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 8f7a2405747..9e38911f53c 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -347,6 +347,11 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { } } } + + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.base_iterator.size_hint(); + (0, upper) + } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 54565afa4c6..28e3180063c 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -132,6 +132,11 @@ impl<'a> Iterator for BitVectorIter<'a> { self.idx += offset + 1; return Some(self.idx - 1); } + + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } } impl FromIterator for BitVector { diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 1945b82c031..e2b393071ff 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -334,6 +334,11 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { self.next = edge.next_edge[self.direction.repr]; Some((edge_index, edge)) } + + fn size_hint(&self) -> (usize, Option) { + // At most, all the edges in the graph. + (0, Some(self.graph.len_edges())) + } } pub struct DepthFirstTraversal<'g, N, E> @@ -383,8 +388,16 @@ impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { } next } + + fn size_hint(&self) -> (usize, Option) { + // We will visit every node in the graph exactly once. + let remaining = self.graph.len_nodes() - self.visited.count(); + (remaining, Some(remaining)) + } } +impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} + impl Edge { pub fn source(&self) -> NodeIndex { self.source diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 4ae6a93d698..c5e7fdb30d3 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -584,6 +584,13 @@ impl<'a, 'hir> Iterator for NodesMatchingUII<'a, 'hir> { &mut NodesMatchingSuffix(ref mut iter) => iter.next(), } } + + fn size_hint(&self) -> (usize, Option) { + match self { + &NodesMatchingDirect(ref iter) => iter.size_hint(), + &NodesMatchingSuffix(ref iter) => iter.size_hint(), + } + } } impl UserIdentifiedItem { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 61afac97d64..a7536980503 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -718,8 +718,15 @@ impl<'a> Iterator for AllTraits<'a> { TraitInfo::new(*info) }) } + + fn size_hint(&self) -> (usize, Option) { + let len = self.borrow.as_ref().unwrap().len() - self.idx; + (len, Some(len)) + } } +impl<'a> ExactSizeIterator for AllTraits<'a> {} + struct UsePlacementFinder<'a, 'tcx: 'a, 'gcx: 'tcx> { target_module: ast::NodeId, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 904c24815cb..a2a0e878fd8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -602,6 +602,11 @@ impl<'a> Iterator for ListAttributesIter<'a> { None } + + fn size_hint(&self) -> (usize, Option) { + let lower = self.current_list.len(); + (lower, None) + } } pub trait AttributesExt { diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index 0476d7d4fcc..e95c6f2e124 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -272,6 +272,11 @@ pub mod printf { self.s = tail; Some(sub) } + + fn size_hint(&self) -> (usize, Option) { + // Substitutions are at least 2 characters long. + (0, Some(self.s.len() / 2)) + } } enum State { @@ -782,6 +787,10 @@ pub mod shell { None => None, } } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.s.len())) + } } /// Parse the next substitution from the input string. -- cgit 1.4.1-3-g733a5 From c393db67baf3a15ec61351ffb0e3811e07b8a467 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 21 Mar 2018 17:44:21 -0700 Subject: Stabilize universal_impl_trait --- .../src/language-features/universal-impl-trait.md | 32 ---------------------- src/librustc/hir/lowering.rs | 11 -------- src/librustc/lib.rs | 2 +- src/librustc_data_structures/lib.rs | 2 +- src/librustc_typeck/diagnostics.rs | 1 - src/libsyntax/feature_gate.rs | 5 ++-- .../impl-trait/impl-generic-mismatch-ab.rs | 1 - .../impl-trait/impl-generic-mismatch.rs | 1 - src/test/compile-fail/impl-trait/where-allowed.rs | 2 +- src/test/run-pass/impl-trait/example-calendar.rs | 1 - src/test/run-pass/impl-trait/lifetimes.rs | 2 +- .../run-pass/impl-trait/universal_hrtb_anon.rs | 2 -- .../run-pass/impl-trait/universal_hrtb_named.rs | 2 -- .../impl-trait/universal_in_adt_in_parameters.rs | 1 - .../universal_in_impl_trait_in_parameters.rs | 1 - .../universal_in_trait_defn_parameters.rs | 2 -- .../impl-trait/universal_multiple_bounds.rs | 2 -- src/test/run-pass/in-band-lifetimes.rs | 2 +- src/test/run-pass/issue-46959.rs | 1 - src/test/rustdoc/issue-46976.rs | 1 - src/test/ui/feature-gate-universal.rs | 16 ----------- src/test/ui/feature-gate-universal.stderr | 11 -------- .../ui/impl-trait/universal-mismatched-type.rs | 2 -- .../ui/impl-trait/universal-mismatched-type.stderr | 2 +- .../ui/impl-trait/universal-two-impl-traits.rs | 2 -- .../ui/impl-trait/universal-two-impl-traits.stderr | 2 +- src/test/ui/impl-trait/universal_wrong_bounds.rs | 2 -- .../ui/impl-trait/universal_wrong_bounds.stderr | 6 ++-- src/test/ui/impl_trait_projections.rs | 2 +- src/test/ui/in-band-lifetimes/E0687_where.rs | 2 +- src/test/ui/nested_impl_trait.rs | 2 +- 31 files changed, 15 insertions(+), 108 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/universal-impl-trait.md delete mode 100644 src/test/ui/feature-gate-universal.rs delete mode 100644 src/test/ui/feature-gate-universal.stderr (limited to 'src/librustc_data_structures') diff --git a/src/doc/unstable-book/src/language-features/universal-impl-trait.md b/src/doc/unstable-book/src/language-features/universal-impl-trait.md deleted file mode 100644 index 6b3c5e92720..00000000000 --- a/src/doc/unstable-book/src/language-features/universal-impl-trait.md +++ /dev/null @@ -1,32 +0,0 @@ -# `universal_impl_trait` - -The tracking issue for this feature is: [#34511]. - -[#34511]: https://github.com/rust-lang/rust/issues/34511 - --------------------- - -The `universal_impl_trait` feature extends the [`conservative_impl_trait`] -feature allowing the `impl Trait` syntax in arguments (universal -quantification). - -[`conservative_impl_trait`]: ./language-features/conservative-impl-trait.html - -## Examples - -```rust -#![feature(universal_impl_trait)] -use std::ops::Not; - -fn any_zero(values: impl IntoIterator) -> bool { - for val in values { if val == 0 { return true; } } - false -} - -fn main() { - let test1 = -5..; - let test2 = vec![1, 8, 42, -87, 60]; - assert!(any_zero(test1)); - assert!(bool::not(any_zero(test2))); -} -``` diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ad848949f62..2ae102fbef0 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1143,17 +1143,6 @@ impl<'a> LoweringContext<'a> { ) } ImplTraitContext::Universal(def_id) => { - let has_feature = self.sess.features_untracked().universal_impl_trait; - if !t.span.allows_unstable() && !has_feature { - emit_feature_err( - &self.sess.parse_sess, - "universal_impl_trait", - t.span, - GateIssue::Language, - "`impl Trait` in argument position is experimental", - ); - } - let def_node_id = self.next_id().node_id; // Add a definition for the in-band TyParam diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a759ce59cb6..d133352de07 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -70,7 +70,7 @@ #![feature(specialization)] #![feature(unboxed_closures)] #![feature(underscore_lifetimes)] -#![feature(universal_impl_trait)] +#![cfg_attr(stage0, feature(universal_impl_trait))] #![feature(trace_macros)] #![feature(trusted_len)] #![feature(catch_expr)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index bf0b3726bb3..05bd3ae845f 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -34,7 +34,7 @@ #![feature(underscore_lifetimes)] #![feature(macro_vis_matcher)] #![feature(allow_internal_unstable)] -#![feature(universal_impl_trait)] +#![cfg_attr(stage0, feature(universal_impl_trait))] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f5337118e30..1f882676f61 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4600,7 +4600,6 @@ This error indicates that there is a mismatch between generic parameters and impl Trait parameters in a trait declaration versus its impl. ```compile_fail,E0643 -#![feature(universal_impl_trait)] trait Foo { fn foo(&self, _: &impl Iterator); } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e69dace0c70..db900ed6e35 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -279,9 +279,6 @@ declare_features! ( // Allows `impl Trait` in function return types. (active, conservative_impl_trait, "1.12.0", Some(34511), None), - // Allows `impl Trait` in function arguments. - (active, universal_impl_trait, "1.23.0", Some(34511), None), - // Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", None, None), @@ -566,6 +563,8 @@ declare_features! ( // Copy/Clone closures (RFC 2132) (accepted, clone_closures, "1.26.0", Some(44490), None), (accepted, copy_closures, "1.26.0", Some(44490), None), + // Allows `impl Trait` in function arguments. + (accepted, universal_impl_trait, "1.26.0", Some(34511), None), ); // If you change this, please modify src/doc/unstable-book as well. You must diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs index 43b47e9e915..23549918ff1 100644 --- a/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs +++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] use std::fmt::Debug; trait Foo { diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs index a95da61aa4c..eea7ca20957 100644 --- a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs +++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] use std::fmt::Debug; trait Foo { diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index 52c5471681d..c93bcf7f390 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -10,7 +10,7 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait -#![feature(conservative_impl_trait, universal_impl_trait, dyn_trait)] +#![feature(conservative_impl_trait, dyn_trait)] use std::fmt::Debug; // Allowed diff --git a/src/test/run-pass/impl-trait/example-calendar.rs b/src/test/run-pass/impl-trait/example-calendar.rs index aca100591dd..d1e2b471d9a 100644 --- a/src/test/run-pass/impl-trait/example-calendar.rs +++ b/src/test/run-pass/impl-trait/example-calendar.rs @@ -12,7 +12,6 @@ //[nll] compile-flags: -Znll -Zborrowck=mir #![feature(conservative_impl_trait, - universal_impl_trait, fn_traits, step_trait, unboxed_closures, diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index fcad23926fc..c589e23f950 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait)] +#![feature(conservative_impl_trait, underscore_lifetimes)] #![allow(warnings)] use std::fmt::Debug; diff --git a/src/test/run-pass/impl-trait/universal_hrtb_anon.rs b/src/test/run-pass/impl-trait/universal_hrtb_anon.rs index 48874ef41de..9fc74757da0 100644 --- a/src/test/run-pass/impl-trait/universal_hrtb_anon.rs +++ b/src/test/run-pass/impl-trait/universal_hrtb_anon.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] - fn hrtb(f: impl Fn(&u32) -> u32) -> u32 { f(&22) + f(&44) } diff --git a/src/test/run-pass/impl-trait/universal_hrtb_named.rs b/src/test/run-pass/impl-trait/universal_hrtb_named.rs index 95147a54200..3aefc79ebf7 100644 --- a/src/test/run-pass/impl-trait/universal_hrtb_named.rs +++ b/src/test/run-pass/impl-trait/universal_hrtb_named.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] - fn hrtb(f: impl for<'a> Fn(&'a u32) -> &'a u32) -> u32 { f(&22) + f(&44) } diff --git a/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs b/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs index d0f18575297..57452a2e475 100644 --- a/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs +++ b/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] use std::fmt::Display; fn check_display_eq(iter: &Vec) { diff --git a/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs b/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs index ccf24b77a6b..fea946f1258 100644 --- a/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs +++ b/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] use std::fmt::Display; fn check_display_eq(iter: impl IntoIterator) { diff --git a/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs b/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs index af0201b5f87..d3611e02e02 100644 --- a/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs +++ b/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] - use std::fmt::Debug; trait InTraitDefnParameters { diff --git a/src/test/run-pass/impl-trait/universal_multiple_bounds.rs b/src/test/run-pass/impl-trait/universal_multiple_bounds.rs index bb332c0c96c..594207feb09 100644 --- a/src/test/run-pass/impl-trait/universal_multiple_bounds.rs +++ b/src/test/run-pass/impl-trait/universal_multiple_bounds.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] - use std::fmt::Display; fn foo(f: impl Display + Clone) -> String { diff --git a/src/test/run-pass/in-band-lifetimes.rs b/src/test/run-pass/in-band-lifetimes.rs index 95cc3c3759e..b5b73675ca7 100644 --- a/src/test/run-pass/in-band-lifetimes.rs +++ b/src/test/run-pass/in-band-lifetimes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(warnings)] -#![feature(in_band_lifetimes, universal_impl_trait, conservative_impl_trait)] +#![feature(in_band_lifetimes, conservative_impl_trait)] fn foo(x: &'x u8) -> &'x u8 { x } fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x } diff --git a/src/test/run-pass/issue-46959.rs b/src/test/run-pass/issue-46959.rs index 0826f5e4923..876b8c0a1d3 100644 --- a/src/test/run-pass/issue-46959.rs +++ b/src/test/run-pass/issue-46959.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] #![feature(conservative_impl_trait)] #![deny(non_camel_case_types)] diff --git a/src/test/rustdoc/issue-46976.rs b/src/test/rustdoc/issue-46976.rs index 0df80fe3bd7..ce09f62a552 100644 --- a/src/test/rustdoc/issue-46976.rs +++ b/src/test/rustdoc/issue-46976.rs @@ -8,5 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] pub fn ice(f: impl Fn()) {} diff --git a/src/test/ui/feature-gate-universal.rs b/src/test/ui/feature-gate-universal.rs deleted file mode 100644 index e5bdf3a42eb..00000000000 --- a/src/test/ui/feature-gate-universal.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 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. - -// gate-test-universal_impl_trait - -fn foo(x: impl std::fmt::Debug) { print!("{:?}", x); } -//~^ ERROR `impl Trait` in argument position is experimental - -fn main() {} diff --git a/src/test/ui/feature-gate-universal.stderr b/src/test/ui/feature-gate-universal.stderr deleted file mode 100644 index dc1a6b29c72..00000000000 --- a/src/test/ui/feature-gate-universal.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: `impl Trait` in argument position is experimental (see issue #34511) - --> $DIR/feature-gate-universal.rs:13:11 - | -LL | fn foo(x: impl std::fmt::Debug) { print!("{:?}", x); } - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(universal_impl_trait)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/impl-trait/universal-mismatched-type.rs b/src/test/ui/impl-trait/universal-mismatched-type.rs index 00fc22ff0d8..6a62eb36c30 100644 --- a/src/test/ui/impl-trait/universal-mismatched-type.rs +++ b/src/test/ui/impl-trait/universal-mismatched-type.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] - use std::fmt::Debug; fn foo(x: impl Debug) -> String { diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr index 64f1aff13bd..031db511ff3 100644 --- a/src/test/ui/impl-trait/universal-mismatched-type.stderr +++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/universal-mismatched-type.rs:16:5 + --> $DIR/universal-mismatched-type.rs:14:5 | LL | fn foo(x: impl Debug) -> String { | ------ expected `std::string::String` because of return type diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.rs b/src/test/ui/impl-trait/universal-two-impl-traits.rs index 9a4847b5606..5ecef1fee65 100644 --- a/src/test/ui/impl-trait/universal-two-impl-traits.rs +++ b/src/test/ui/impl-trait/universal-two-impl-traits.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] - use std::fmt::Debug; fn foo(x: impl Debug, y: impl Debug) -> String { diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.stderr b/src/test/ui/impl-trait/universal-two-impl-traits.stderr index 61f52ff25fb..ed406895fc6 100644 --- a/src/test/ui/impl-trait/universal-two-impl-traits.stderr +++ b/src/test/ui/impl-trait/universal-two-impl-traits.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/universal-two-impl-traits.rs:17:9 + --> $DIR/universal-two-impl-traits.rs:15:9 | LL | a = y; //~ ERROR mismatched | ^ expected type parameter, found a different type parameter diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.rs b/src/test/ui/impl-trait/universal_wrong_bounds.rs index 36d9f615c5f..a5e948223fb 100644 --- a/src/test/ui/impl-trait/universal_wrong_bounds.rs +++ b/src/test/ui/impl-trait/universal_wrong_bounds.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(universal_impl_trait)] - use std::fmt::Display; fn foo(f: impl Display + Clone) -> String { diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.stderr b/src/test/ui/impl-trait/universal_wrong_bounds.stderr index 3cc0bebe816..02ac4707bc5 100644 --- a/src/test/ui/impl-trait/universal_wrong_bounds.stderr +++ b/src/test/ui/impl-trait/universal_wrong_bounds.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find function `wants_clone` in this scope - --> $DIR/universal_wrong_bounds.rs:18:5 + --> $DIR/universal_wrong_bounds.rs:16:5 | LL | wants_clone(f); //~ ERROR cannot find | ^^^^^^^^^^^ did you mean `wants_cone`? error[E0405]: cannot find trait `Debug` in this scope - --> $DIR/universal_wrong_bounds.rs:21:24 + --> $DIR/universal_wrong_bounds.rs:19:24 | LL | fn wants_debug(g: impl Debug) { } //~ ERROR cannot find | ^^^^^ not found in this scope @@ -15,7 +15,7 @@ LL | use std::fmt::Debug; | error[E0405]: cannot find trait `Debug` in this scope - --> $DIR/universal_wrong_bounds.rs:22:26 + --> $DIR/universal_wrong_bounds.rs:20:26 | LL | fn wants_display(g: impl Debug) { } //~ ERROR cannot find | ^^^^^ not found in this scope diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs index f69a78b1450..05e88bf848d 100644 --- a/src/test/ui/impl_trait_projections.rs +++ b/src/test/ui/impl_trait_projections.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dyn_trait, conservative_impl_trait, universal_impl_trait)] +#![feature(dyn_trait, conservative_impl_trait)] use std::fmt::Debug; use std::option; diff --git a/src/test/ui/in-band-lifetimes/E0687_where.rs b/src/test/ui/in-band-lifetimes/E0687_where.rs index ac675587720..c1b268eac70 100644 --- a/src/test/ui/in-band-lifetimes/E0687_where.rs +++ b/src/test/ui/in-band-lifetimes/E0687_where.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(warnings)] -#![feature(in_band_lifetimes, universal_impl_trait)] +#![feature(in_band_lifetimes)] fn bar(x: &F) where F: Fn(&'a u32) {} //~ ERROR must be explicitly diff --git a/src/test/ui/nested_impl_trait.rs b/src/test/ui/nested_impl_trait.rs index f6302c0f3b3..0fb1222d797 100644 --- a/src/test/ui/nested_impl_trait.rs +++ b/src/test/ui/nested_impl_trait.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, universal_impl_trait)] +#![feature(conservative_impl_trait)] use std::fmt::Debug; -- cgit 1.4.1-3-g733a5 From 0f5b52e4a8d3004ef2d69b2ec7f410d4b2c9494c Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 21 Mar 2018 18:32:44 -0700 Subject: Stabilize conservative_impl_trait --- src/Cargo.lock | 27 +-------- .../language-features/conservative-impl-trait.md | 66 ---------------------- src/libcore/tests/lib.rs | 2 +- src/librustc/diagnostics.rs | 8 --- src/librustc/hir/lowering.rs | 11 ---- src/librustc/lib.rs | 2 +- src/librustc_data_structures/lib.rs | 2 +- src/librustc_errors/lib.rs | 2 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_metadata/lib.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_trans/lib.rs | 2 +- src/librustc_trans_utils/lib.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 5 +- src/test/compile-fail/conservative_impl_trait.rs | 1 - .../impl-trait/infinite-impl-trait-issue-38064.rs | 2 - .../must_outlive_least_region_or_bound.rs | 2 - .../impl-trait/needs_least_region_or_bound.rs | 2 - src/test/compile-fail/impl-trait/no-trait.rs | 2 - .../impl-trait/type_parameters_captured.rs | 2 - src/test/compile-fail/impl-trait/where-allowed.rs | 2 +- src/test/compile-fail/issue-32995-2.rs | 1 - src/test/compile-fail/issue-35668.rs | 2 - src/test/compile-fail/issue-36379.rs | 2 +- src/test/compile-fail/private-inferred-type.rs | 1 - src/test/compile-fail/private-type-in-interface.rs | 1 - src/test/incremental/hashes/function_interfaces.rs | 1 - src/test/run-pass/conservative_impl_trait.rs | 2 - .../generator/auxiliary/xcrate-reachable.rs | 2 +- src/test/run-pass/generator/auxiliary/xcrate.rs | 2 +- src/test/run-pass/generator/issue-44197.rs | 2 +- src/test/run-pass/generator/iterator-count.rs | 2 +- src/test/run-pass/generator/xcrate-reachable.rs | 2 +- src/test/run-pass/impl-trait/auto-trait-leak.rs | 2 - src/test/run-pass/impl-trait/auxiliary/xcrate.rs | 2 - src/test/run-pass/impl-trait/equality.rs | 2 +- src/test/run-pass/impl-trait/example-calendar.rs | 3 +- src/test/run-pass/impl-trait/example-st.rs | 2 - src/test/run-pass/impl-trait/issue-42479.rs | 2 - src/test/run-pass/impl-trait/lifetimes.rs | 2 +- src/test/run-pass/in-band-lifetimes.rs | 2 +- src/test/run-pass/issue-36792.rs | 1 - src/test/run-pass/issue-46959.rs | 1 - src/test/rustdoc/issue-43869.rs | 2 - src/test/ui/casts-differing-anon.rs | 2 - src/test/ui/casts-differing-anon.stderr | 2 +- src/test/ui/error-codes/E0657.rs | 1 - src/test/ui/error-codes/E0657.stderr | 4 +- .../ui/feature-gate-conservative_impl_trait.rs | 14 ----- .../ui/feature-gate-conservative_impl_trait.stderr | 11 ---- src/test/ui/impl-trait/auto-trait-leak.rs | 2 - src/test/ui/impl-trait/auto-trait-leak.stderr | 22 ++++---- src/test/ui/impl-trait/equality.rs | 2 +- ...egion-escape-via-bound-contravariant-closure.rs | 1 - .../region-escape-via-bound-contravariant.rs | 1 - src/test/ui/impl-trait/region-escape-via-bound.rs | 1 - .../ui/impl-trait/region-escape-via-bound.stderr | 6 +- src/test/ui/impl_trait_projections.rs | 2 +- src/test/ui/issue-35869.rs | 2 - src/test/ui/issue-35869.stderr | 8 +-- src/test/ui/nested_impl_trait.rs | 2 - src/test/ui/nested_impl_trait.stderr | 12 ++-- src/test/ui/nll/ty-outlives/impl-trait-captures.rs | 1 - .../ui/nll/ty-outlives/impl-trait-captures.stderr | 4 +- src/test/ui/nll/ty-outlives/impl-trait-outlives.rs | 1 - .../ui/nll/ty-outlives/impl-trait-outlives.stderr | 8 +-- src/tools/clippy | 2 +- 68 files changed, 62 insertions(+), 240 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/conservative-impl-trait.md delete mode 100644 src/test/ui/feature-gate-conservative_impl_trait.rs delete mode 100644 src/test/ui/feature-gate-conservative_impl_trait.stderr (limited to 'src/librustc_data_structures') diff --git a/src/Cargo.lock b/src/Cargo.lock index 371e505e9be..c45f18360b9 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -271,11 +271,11 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.188" +version = "0.0.189" dependencies = [ "cargo_metadata 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.188", + "clippy_lints 0.0.189", "compiletest_rs 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -289,29 +289,9 @@ dependencies = [ name = "clippy-mini-macro-test" version = "0.2.0" -[[package]] -name = "clippy_lints" -version = "0.0.188" -dependencies = [ - "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "clippy_lints" version = "0.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1419,7 +1399,7 @@ version = "0.126.0" dependencies = [ "cargo 0.27.0", "cargo_metadata 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.189 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.189", "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2638,7 +2618,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum clippy_lints 0.0.189 (registry+https://github.com/rust-lang/crates.io-index)" = "fef652630bbf8c5e89601220abd000f5057e8fa9db608484b5ebaad98e9bce53" "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" diff --git a/src/doc/unstable-book/src/language-features/conservative-impl-trait.md b/src/doc/unstable-book/src/language-features/conservative-impl-trait.md deleted file mode 100644 index 0be6a321103..00000000000 --- a/src/doc/unstable-book/src/language-features/conservative-impl-trait.md +++ /dev/null @@ -1,66 +0,0 @@ -# `conservative_impl_trait` - -The tracking issue for this feature is: [#34511] - -[#34511]: https://github.com/rust-lang/rust/issues/34511 - ------------------------- - -The `conservative_impl_trait` feature allows a conservative form of abstract -return types. - -Abstract return types allow a function to hide a concrete return type behind a -trait interface similar to trait objects, while still generating the same -statically dispatched code as with concrete types. - -## Examples - -```rust -#![feature(conservative_impl_trait)] - -fn even_iter() -> impl Iterator { - (0..).map(|n| n * 2) -} - -fn main() { - let first_four_even_numbers = even_iter().take(4).collect::>(); - assert_eq!(first_four_even_numbers, vec![0, 2, 4, 6]); -} -``` - -## Background - -In today's Rust, you can write function signatures like: - -````rust,ignore -fn consume_iter_static>(iter: I) { } - -fn consume_iter_dynamic(iter: Box>) { } -```` - -In both cases, the function does not depend on the exact type of the argument. -The type held is "abstract", and is assumed only to satisfy a trait bound. - -* In the `_static` version using generics, each use of the function is - specialized to a concrete, statically-known type, giving static dispatch, - inline layout, and other performance wins. -* In the `_dynamic` version using trait objects, the concrete argument type is - only known at runtime using a vtable. - -On the other hand, while you can write: - -````rust,ignore -fn produce_iter_dynamic() -> Box> { } -```` - -...but you _cannot_ write something like: - -````rust,ignore -fn produce_iter_static() -> Iterator { } -```` - -That is, in today's Rust, abstract return types can only be written using trait -objects, which can be a significant performance penalty. This RFC proposes -"unboxed abstract types" as a way of achieving signatures like -`produce_iter_static`. Like generics, unboxed abstract types guarantee static -dispatch and inline data layout. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e9a8113ef10..1c71669abb1 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,7 +27,7 @@ #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(iter_rfind)] #![feature(iter_rfold)] #![feature(iterator_repeat_with)] diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index e22e2b55703..f95c355012a 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1789,8 +1789,6 @@ allowed as function return types. Erroneous code example: ```compile_fail,E0562 -#![feature(conservative_impl_trait)] - fn main() { let count_to_ten: impl Iterator = 0..10; // error: `impl Trait` not allowed outside of function and inherent method @@ -1804,8 +1802,6 @@ fn main() { Make sure `impl Trait` only appears in return-type position. ``` -#![feature(conservative_impl_trait)] - fn count_to_n(n: usize) -> impl Iterator { 0..n } @@ -2081,8 +2077,6 @@ appear within the `impl Trait` itself. Erroneous code example: ```compile-fail,E0909 -#![feature(conservative_impl_trait)] - use std::cell::Cell; trait Trait<'a> { } @@ -2109,8 +2103,6 @@ type. For example, changing the return type to `impl Trait<'y> + 'x` would work: ``` -#![feature(conservative_impl_trait)] - use std::cell::Cell; trait Trait<'a> { } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ae102fbef0..536d682566a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1108,20 +1108,9 @@ impl<'a> LoweringContext<'a> { hir::TyTraitObject(bounds, lifetime_bound) } TyKind::ImplTrait(ref bounds) => { - use syntax::feature_gate::{emit_feature_err, GateIssue}; let span = t.span; match itctx { ImplTraitContext::Existential => { - let has_feature = self.sess.features_untracked().conservative_impl_trait; - if !t.span.allows_unstable() && !has_feature { - emit_feature_err( - &self.sess.parse_sess, - "conservative_impl_trait", - t.span, - GateIssue::Language, - "`impl Trait` in return position is experimental", - ); - } let def_index = self.resolver.definitions().opt_def_index(t.id).unwrap(); let hir_bounds = self.lower_bounds(bounds, itctx); let (lifetimes, lifetime_defs) = diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d133352de07..1bb903c0627 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -43,7 +43,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] #![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(core_intrinsics)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 05bd3ae845f..ff869072871 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -28,7 +28,7 @@ #![feature(unsize)] #![feature(i128_type)] #![feature(i128)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(specialization)] #![feature(optin_builtin_traits)] #![feature(underscore_lifetimes)] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index dcbea793ba6..1152c9c574e 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -17,7 +17,7 @@ #![allow(unused_attributes)] #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(i128_type)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index d7ccf9d5562..6adb950fe4e 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -15,7 +15,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] #![feature(i128_type)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 85099667449..902dd87c574 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -14,7 +14,7 @@ #![deny(warnings)] #![feature(box_patterns)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] #![feature(i128_type)] #![feature(libc)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index ff35412ea5b..750839f8b00 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -21,7 +21,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] #![feature(catch_expr)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 9f654c8ab29..38adc603628 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -31,7 +31,7 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![cfg_attr(stage0, feature(slice_patterns))] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 0af5f467934..9e4addd1ed1 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -24,7 +24,7 @@ #![feature(i128_type)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] extern crate ar; extern crate flate2; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 5a7de6b56b5..e466ef39234 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -75,7 +75,7 @@ This API is completely unstable and subject to change. #![cfg_attr(stage0, feature(advanced_slice_patterns))] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(crate_visibility_modifier)] #![feature(from_ref)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index db900ed6e35..1bb369b551d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -276,9 +276,6 @@ declare_features! ( // Allows cfg(target_has_atomic = "..."). (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - // Allows `impl Trait` in function return types. - (active, conservative_impl_trait, "1.12.0", Some(34511), None), - // Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", None, None), @@ -565,6 +562,8 @@ declare_features! ( (accepted, copy_closures, "1.26.0", Some(44490), None), // Allows `impl Trait` in function arguments. (accepted, universal_impl_trait, "1.26.0", Some(34511), None), + // Allows `impl Trait` in function return types. + (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), ); // If you change this, please modify src/doc/unstable-book as well. You must diff --git a/src/test/compile-fail/conservative_impl_trait.rs b/src/test/compile-fail/conservative_impl_trait.rs index 7fb0ec52f29..30895bce357 100644 --- a/src/test/compile-fail/conservative_impl_trait.rs +++ b/src/test/compile-fail/conservative_impl_trait.rs @@ -10,7 +10,6 @@ // #39872, #39553 -#![feature(conservative_impl_trait)] fn will_ice(something: &u32) -> impl Iterator { //~^ ERROR the trait bound `(): std::iter::Iterator` is not satisfied [E0277] } diff --git a/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs b/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs index abde9689bd6..653ef1723e0 100644 --- a/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs +++ b/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs @@ -15,8 +15,6 @@ // error-pattern:overflow evaluating the requirement `impl Quux` -#![feature(conservative_impl_trait)] - trait Quux {} fn foo() -> impl Quux { diff --git a/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs index 0eb99ca0fc3..537fc975bcf 100644 --- a/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt::Debug; fn elided(x: &i32) -> impl Copy { x } diff --git a/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs b/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs index 2a06580fe60..6c0a0b800ce 100644 --- a/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs +++ b/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt::Debug; trait MultiRegionTrait<'a, 'b> {} diff --git a/src/test/compile-fail/impl-trait/no-trait.rs b/src/test/compile-fail/impl-trait/no-trait.rs index ce61c5bf63d..5299ba297d0 100644 --- a/src/test/compile-fail/impl-trait/no-trait.rs +++ b/src/test/compile-fail/impl-trait/no-trait.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - fn f() -> impl 'static {} //~ ERROR at least one trait must be specified fn main() {} diff --git a/src/test/compile-fail/impl-trait/type_parameters_captured.rs b/src/test/compile-fail/impl-trait/type_parameters_captured.rs index c6ff762b905..7c3430ab90e 100644 --- a/src/test/compile-fail/impl-trait/type_parameters_captured.rs +++ b/src/test/compile-fail/impl-trait/type_parameters_captured.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt::Debug; trait Any {} diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index c93bcf7f390..038eacaf110 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -10,7 +10,7 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait -#![feature(conservative_impl_trait, dyn_trait)] +#![feature(dyn_trait)] use std::fmt::Debug; // Allowed diff --git a/src/test/compile-fail/issue-32995-2.rs b/src/test/compile-fail/issue-32995-2.rs index 0e917ad95d9..18424fcc9e0 100644 --- a/src/test/compile-fail/issue-32995-2.rs +++ b/src/test/compile-fail/issue-32995-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] #![allow(unused)] fn main() { diff --git a/src/test/compile-fail/issue-35668.rs b/src/test/compile-fail/issue-35668.rs index c9323db054c..17fd77b6df3 100644 --- a/src/test/compile-fail/issue-35668.rs +++ b/src/test/compile-fail/issue-35668.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - fn func<'a, T>(a: &'a [T]) -> impl Iterator { a.iter().map(|a| a*a) //~^ ERROR binary operation `*` cannot be applied to type `&T` diff --git a/src/test/compile-fail/issue-36379.rs b/src/test/compile-fail/issue-36379.rs index 2f513b034c3..b20765815e0 100644 --- a/src/test/compile-fail/issue-36379.rs +++ b/src/test/compile-fail/issue-36379.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, rustc_attrs)] +#![feature(rustc_attrs)] fn _test() -> impl Default { } diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs index 351dc6b776b..5af8b063c16 100644 --- a/src/test/compile-fail/private-inferred-type.rs +++ b/src/test/compile-fail/private-inferred-type.rs @@ -9,7 +9,6 @@ // except according to those terms. #![feature(associated_consts)] -#![feature(conservative_impl_trait)] #![feature(decl_macro)] #![allow(private_in_public)] diff --git a/src/test/compile-fail/private-type-in-interface.rs b/src/test/compile-fail/private-type-in-interface.rs index eb8c40a7dd5..1842790a140 100644 --- a/src/test/compile-fail/private-type-in-interface.rs +++ b/src/test/compile-fail/private-type-in-interface.rs @@ -10,7 +10,6 @@ // aux-build:private-inferred-type.rs -#![feature(conservative_impl_trait)] #![allow(warnings)] extern crate private_inferred_type as ext; diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index abe0586efcd..6c4e11be1e4 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -22,7 +22,6 @@ #![allow(warnings)] -#![feature(conservative_impl_trait)] #![feature(intrinsics)] #![feature(linkage)] #![feature(rustc_attrs)] diff --git a/src/test/run-pass/conservative_impl_trait.rs b/src/test/run-pass/conservative_impl_trait.rs index 30090018e29..14e1ca612c0 100644 --- a/src/test/run-pass/conservative_impl_trait.rs +++ b/src/test/run-pass/conservative_impl_trait.rs @@ -10,8 +10,6 @@ // #39665 -#![feature(conservative_impl_trait)] - fn batches(n: &u32) -> impl Iterator { std::iter::once(n) } diff --git a/src/test/run-pass/generator/auxiliary/xcrate-reachable.rs b/src/test/run-pass/generator/auxiliary/xcrate-reachable.rs index a6a2a2d081e..91e43537cc2 100644 --- a/src/test/run-pass/generator/auxiliary/xcrate-reachable.rs +++ b/src/test/run-pass/generator/auxiliary/xcrate-reachable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, generators, generator_trait)] +#![feature(generators, generator_trait)] use std::ops::Generator; diff --git a/src/test/run-pass/generator/auxiliary/xcrate.rs b/src/test/run-pass/generator/auxiliary/xcrate.rs index f6878e64fbf..fcfe0b754b6 100644 --- a/src/test/run-pass/generator/auxiliary/xcrate.rs +++ b/src/test/run-pass/generator/auxiliary/xcrate.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait, conservative_impl_trait)] +#![feature(generators, generator_trait)] use std::ops::Generator; diff --git a/src/test/run-pass/generator/issue-44197.rs b/src/test/run-pass/generator/issue-44197.rs index 8ce4fc6affa..272b7eb7bfd 100644 --- a/src/test/run-pass/generator/issue-44197.rs +++ b/src/test/run-pass/generator/issue-44197.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, generators, generator_trait)] +#![feature(generators, generator_trait)] use std::ops::{ Generator, GeneratorState }; diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 654b18928c0..3564ddaa806 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait, conservative_impl_trait)] +#![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; diff --git a/src/test/run-pass/generator/xcrate-reachable.rs b/src/test/run-pass/generator/xcrate-reachable.rs index 8eeb0133144..2fc39ba1869 100644 --- a/src/test/run-pass/generator/xcrate-reachable.rs +++ b/src/test/run-pass/generator/xcrate-reachable.rs @@ -10,7 +10,7 @@ // aux-build:xcrate-reachable.rs -#![feature(conservative_impl_trait, generator_trait)] +#![feature(generator_trait)] extern crate xcrate_reachable as foo; diff --git a/src/test/run-pass/impl-trait/auto-trait-leak.rs b/src/test/run-pass/impl-trait/auto-trait-leak.rs index 011d910c5a5..62fbae7b40c 100644 --- a/src/test/run-pass/impl-trait/auto-trait-leak.rs +++ b/src/test/run-pass/impl-trait/auto-trait-leak.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - // Fast path, main can see the concrete type returned. fn before() -> impl FnMut(i32) { let mut p = Box::new(0); diff --git a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs index e4f525a9826..c27a2dd89d5 100644 --- a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs +++ b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - // NOTE commented out due to issue #45994 //pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 { // move |b| move |c| move |d| a + b + c + d diff --git a/src/test/run-pass/impl-trait/equality.rs b/src/test/run-pass/impl-trait/equality.rs index ceed454e5ad..034d3d7c80f 100644 --- a/src/test/run-pass/impl-trait/equality.rs +++ b/src/test/run-pass/impl-trait/equality.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, specialization)] +#![feature(specialization)] trait Foo: std::fmt::Debug + Eq {} diff --git a/src/test/run-pass/impl-trait/example-calendar.rs b/src/test/run-pass/impl-trait/example-calendar.rs index d1e2b471d9a..b1db2030717 100644 --- a/src/test/run-pass/impl-trait/example-calendar.rs +++ b/src/test/run-pass/impl-trait/example-calendar.rs @@ -11,8 +11,7 @@ // revisions: normal nll //[nll] compile-flags: -Znll -Zborrowck=mir -#![feature(conservative_impl_trait, - fn_traits, +#![feature(fn_traits, step_trait, unboxed_closures, copy_closures, diff --git a/src/test/run-pass/impl-trait/example-st.rs b/src/test/run-pass/impl-trait/example-st.rs index e9326ed286a..a06bde7f532 100644 --- a/src/test/run-pass/impl-trait/example-st.rs +++ b/src/test/run-pass/impl-trait/example-st.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - struct State; type Error = (); diff --git a/src/test/run-pass/impl-trait/issue-42479.rs b/src/test/run-pass/impl-trait/issue-42479.rs index 629948a5dc4..df7a6c13092 100644 --- a/src/test/run-pass/impl-trait/issue-42479.rs +++ b/src/test/run-pass/impl-trait/issue-42479.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::iter::once; struct Foo { diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index c589e23f950..1b50ceefbe1 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, underscore_lifetimes)] +#![feature(underscore_lifetimes)] #![allow(warnings)] use std::fmt::Debug; diff --git a/src/test/run-pass/in-band-lifetimes.rs b/src/test/run-pass/in-band-lifetimes.rs index b5b73675ca7..6edd0d686ef 100644 --- a/src/test/run-pass/in-band-lifetimes.rs +++ b/src/test/run-pass/in-band-lifetimes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(warnings)] -#![feature(in_band_lifetimes, conservative_impl_trait)] +#![feature(in_band_lifetimes)] fn foo(x: &'x u8) -> &'x u8 { x } fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x } diff --git a/src/test/run-pass/issue-36792.rs b/src/test/run-pass/issue-36792.rs index faf983f6ecb..f2755ec3f84 100644 --- a/src/test/run-pass/issue-36792.rs +++ b/src/test/run-pass/issue-36792.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] fn foo() -> impl Copy { foo } diff --git a/src/test/run-pass/issue-46959.rs b/src/test/run-pass/issue-46959.rs index 876b8c0a1d3..7f050c055b0 100644 --- a/src/test/run-pass/issue-46959.rs +++ b/src/test/run-pass/issue-46959.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] #![deny(non_camel_case_types)] #[allow(dead_code)] diff --git a/src/test/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs index 554c71500cc..a5ed3d892ce 100644 --- a/src/test/rustdoc/issue-43869.rs +++ b/src/test/rustdoc/issue-43869.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - pub fn g() -> impl Iterator { Some(1u8).into_iter() } diff --git a/src/test/ui/casts-differing-anon.rs b/src/test/ui/casts-differing-anon.rs index 74c8ff370f9..05a03d3b179 100644 --- a/src/test/ui/casts-differing-anon.rs +++ b/src/test/ui/casts-differing-anon.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt; fn foo() -> Box { diff --git a/src/test/ui/casts-differing-anon.stderr b/src/test/ui/casts-differing-anon.stderr index acbff4f73c3..dac24af671c 100644 --- a/src/test/ui/casts-differing-anon.stderr +++ b/src/test/ui/casts-differing-anon.stderr @@ -1,5 +1,5 @@ error[E0606]: casting `*mut impl std::fmt::Debug+?Sized` as `*mut impl std::fmt::Debug+?Sized` is invalid - --> $DIR/casts-differing-anon.rs:33:13 + --> $DIR/casts-differing-anon.rs:31:13 | LL | b_raw = f_raw as *mut _; //~ ERROR is invalid | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/error-codes/E0657.rs b/src/test/ui/error-codes/E0657.rs index 31b3acd86ef..c23aa40ee37 100644 --- a/src/test/ui/error-codes/E0657.rs +++ b/src/test/ui/error-codes/E0657.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(warnings)] -#![feature(conservative_impl_trait)] trait Id {} trait Lt<'a> {} diff --git a/src/test/ui/error-codes/E0657.stderr b/src/test/ui/error-codes/E0657.stderr index f0529142023..737ae3a163a 100644 --- a/src/test/ui/error-codes/E0657.stderr +++ b/src/test/ui/error-codes/E0657.stderr @@ -1,11 +1,11 @@ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:20:31 + --> $DIR/E0657.rs:19:31 | LL | -> Box Id>> | ^^ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:29:35 + --> $DIR/E0657.rs:28:35 | LL | -> Box Id>> | ^^ diff --git a/src/test/ui/feature-gate-conservative_impl_trait.rs b/src/test/ui/feature-gate-conservative_impl_trait.rs deleted file mode 100644 index 7a3ae639bfc..00000000000 --- a/src/test/ui/feature-gate-conservative_impl_trait.rs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -fn foo() -> impl Fn() { || {} } -//~^ ERROR `impl Trait` in return position is experimental - -fn main() {} diff --git a/src/test/ui/feature-gate-conservative_impl_trait.stderr b/src/test/ui/feature-gate-conservative_impl_trait.stderr deleted file mode 100644 index 5400226450b..00000000000 --- a/src/test/ui/feature-gate-conservative_impl_trait.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: `impl Trait` in return position is experimental (see issue #34511) - --> $DIR/feature-gate-conservative_impl_trait.rs:11:13 - | -LL | fn foo() -> impl Fn() { || {} } - | ^^^^^^^^^ - | - = help: add #![feature(conservative_impl_trait)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index 5a6aac43ec7..99a7dd5e785 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -10,8 +10,6 @@ // ignore-tidy-linelength -#![feature(conservative_impl_trait)] - use std::cell::Cell; use std::rc::Rc; diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 71ca8675db4..ca639f1076d 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,56 +1,56 @@ error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` - --> $DIR/auto-trait-leak.rs:27:5 + --> $DIR/auto-trait-leak.rs:25:5 | LL | send(before()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:21:5: 21:22 p:std::rc::Rc>]` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:19:5: 19:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` note: required by `send` - --> $DIR/auto-trait-leak.rs:24:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` - --> $DIR/auto-trait-leak.rs:30:5 + --> $DIR/auto-trait-leak.rs:28:5 | LL | send(after()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:38:5: 38:22 p:std::rc::Rc>]` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:36:5: 36:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` note: required by `send` - --> $DIR/auto-trait-leak.rs:24:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0391]: cyclic dependency detected - --> $DIR/auto-trait-leak.rs:44:1 + --> $DIR/auto-trait-leak.rs:42:1 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic reference | note: the cycle begins when processing `cycle1`... - --> $DIR/auto-trait-leak.rs:44:1 + --> $DIR/auto-trait-leak.rs:42:1 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which then requires processing `cycle2::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:52:16 + --> $DIR/auto-trait-leak.rs:50:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which then requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:52:1 + --> $DIR/auto-trait-leak.rs:50:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which then requires processing `cycle1::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:44:16 + --> $DIR/auto-trait-leak.rs:42:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/equality.rs b/src/test/ui/impl-trait/equality.rs index 9d9d4cef311..b65e477f21f 100644 --- a/src/test/ui/impl-trait/equality.rs +++ b/src/test/ui/impl-trait/equality.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, specialization)] +#![feature(specialization)] trait Foo: Copy + ToString {} diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs index f554efe9036..78ae922c751 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs @@ -18,7 +18,6 @@ // run-pass #![allow(dead_code)] -#![feature(conservative_impl_trait)] #![feature(in_band_lifetimes)] #![feature(nll)] diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs index 416bdae5178..972461c2ffd 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs @@ -18,7 +18,6 @@ // run-pass #![allow(dead_code)] -#![feature(conservative_impl_trait)] #![feature(in_band_lifetimes)] #![feature(nll)] diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs index 38c18ce6104..e73f15606dc 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound.rs @@ -14,7 +14,6 @@ // See https://github.com/rust-lang/rust/issues/46541 for more details. #![allow(dead_code)] -#![feature(conservative_impl_trait)] #![feature(in_band_lifetimes)] #![feature(nll)] diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr index 5659fee9bed..4281a4c10ad 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -1,11 +1,11 @@ error[E0909]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/region-escape-via-bound.rs:27:29 + --> $DIR/region-escape-via-bound.rs:26:29 | LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> | ^^^^^^^^^^^^^^ | -note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 27:1 - --> $DIR/region-escape-via-bound.rs:27:1 +note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 26:1 + --> $DIR/region-escape-via-bound.rs:26:1 | LL | / fn foo(x: Cell<&'x u32>) -> impl Trait<'y> LL | | //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0909] diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs index 05e88bf848d..6a727942271 100644 --- a/src/test/ui/impl_trait_projections.rs +++ b/src/test/ui/impl_trait_projections.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dyn_trait, conservative_impl_trait)] +#![feature(dyn_trait)] use std::fmt::Debug; use std::option; diff --git a/src/test/ui/issue-35869.rs b/src/test/ui/issue-35869.rs index 17ee62aed1b..7bab22edcf6 100644 --- a/src/test/ui/issue-35869.rs +++ b/src/test/ui/issue-35869.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - trait Foo { fn foo(_: fn(u8) -> ()); fn bar(_: Option); diff --git a/src/test/ui/issue-35869.stderr b/src/test/ui/issue-35869.stderr index fa971c111a4..1930dd5bbcb 100644 --- a/src/test/ui/issue-35869.stderr +++ b/src/test/ui/issue-35869.stderr @@ -1,5 +1,5 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/issue-35869.rs:23:15 + --> $DIR/issue-35869.rs:21:15 | LL | fn foo(_: fn(u8) -> ()); | ------------ type in trait @@ -11,7 +11,7 @@ LL | fn foo(_: fn(u16) -> ()) {} found type `fn(fn(u16))` error[E0053]: method `bar` has an incompatible type for trait - --> $DIR/issue-35869.rs:25:15 + --> $DIR/issue-35869.rs:23:15 | LL | fn bar(_: Option); | ---------- type in trait @@ -23,7 +23,7 @@ LL | fn bar(_: Option) {} found type `fn(std::option::Option)` error[E0053]: method `baz` has an incompatible type for trait - --> $DIR/issue-35869.rs:27:15 + --> $DIR/issue-35869.rs:25:15 | LL | fn baz(_: (u8, u16)); | --------- type in trait @@ -35,7 +35,7 @@ LL | fn baz(_: (u16, u16)) {} found type `fn((u16, u16))` error[E0053]: method `qux` has an incompatible type for trait - --> $DIR/issue-35869.rs:29:17 + --> $DIR/issue-35869.rs:27:17 | LL | fn qux() -> u8; | -- type in trait diff --git a/src/test/ui/nested_impl_trait.rs b/src/test/ui/nested_impl_trait.rs index 0fb1222d797..be0454472dd 100644 --- a/src/test/ui/nested_impl_trait.rs +++ b/src/test/ui/nested_impl_trait.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt::Debug; fn fine(x: impl Into) -> impl Into { x } diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr index 10d767db8d3..ee53194e2b4 100644 --- a/src/test/ui/nested_impl_trait.stderr +++ b/src/test/ui/nested_impl_trait.stderr @@ -1,5 +1,5 @@ error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:16:56 + --> $DIR/nested_impl_trait.rs:14:56 | LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- @@ -8,7 +8,7 @@ LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:19:42 + --> $DIR/nested_impl_trait.rs:17:42 | LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | ----------^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:23:37 + --> $DIR/nested_impl_trait.rs:21:37 | LL | fn bad_in_arg_position(_: impl Into) { } | ----------^^^^^^^^^^- @@ -26,7 +26,7 @@ LL | fn bad_in_arg_position(_: impl Into) { } | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:28:44 + --> $DIR/nested_impl_trait.rs:26:44 | LL | fn bad(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- @@ -35,13 +35,13 @@ LL | fn bad(x: impl Into) -> impl Into { x } | outer `impl Trait` error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/nested_impl_trait.rs:19:32 + --> $DIR/nested_impl_trait.rs:17:32 | LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | ^^^^^^^^^^^^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/nested_impl_trait.rs:36:42 + --> $DIR/nested_impl_trait.rs:34:42 | LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into { | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs index 850cd1e7336..571bd9fd76e 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs @@ -11,7 +11,6 @@ // compile-flags:-Znll -Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(conservative_impl_trait)] trait Foo<'a> { } diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr index bfa58bfc807..92e4f72da3a 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -1,11 +1,11 @@ warning: not reporting region error due to -Znll - --> $DIR/impl-trait-captures.rs:22:5 + --> $DIR/impl-trait-captures.rs:21:5 | LL | x | ^ error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/impl-trait-captures.rs:22:5 + --> $DIR/impl-trait-captures.rs:21:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { | - consider changing the type of `x` to `&ReEarlyBound(0, 'a) T` diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs index 135805a7339..2e0671f1a51 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs +++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs @@ -11,7 +11,6 @@ // compile-flags:-Znll -Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(conservative_impl_trait)] use std::fmt::Debug; diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr index f29d2233e70..2b90d53774e 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to -Znll - --> $DIR/impl-trait-outlives.rs:18:35 + --> $DIR/impl-trait-outlives.rs:17:35 | LL | fn no_region<'a, T>(x: Box) -> impl Debug + 'a | ^^^^^^^^^^^^^^^ warning: not reporting region error due to -Znll - --> $DIR/impl-trait-outlives.rs:34:42 + --> $DIR/impl-trait-outlives.rs:33:42 | LL | fn wrong_region<'a, 'b, T>(x: Box) -> impl Debug + 'a | ^^^^^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/impl-trait-outlives.rs:23:5 + --> $DIR/impl-trait-outlives.rs:22:5 | LL | x | ^ @@ -19,7 +19,7 @@ LL | x = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... error[E0309]: the parameter type `T` may not live long enough - --> $DIR/impl-trait-outlives.rs:39:5 + --> $DIR/impl-trait-outlives.rs:38:5 | LL | x | ^ diff --git a/src/tools/clippy b/src/tools/clippy index 4edd140e57c..eafd0901081 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 4edd140e57cce900fa930e1439bab469f5bbce46 +Subproject commit eafd09010815da43302ac947afee45b0f5219e6b -- cgit 1.4.1-3-g733a5 From 7ce8191775b44d3773e28d647b5b17ec85508e16 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 16 Mar 2018 19:51:49 -0500 Subject: Stabilize i128_type --- src/liballoc/benches/lib.rs | 2 +- src/liballoc/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/libcore/num/mod.rs | 6 ++-- src/libcore/tests/lib.rs | 2 +- src/libproc_macro/lib.rs | 2 +- src/librustc/lib.rs | 2 +- src/librustc_apfloat/lib.rs | 2 +- src/librustc_apfloat/tests/ieee.rs | 2 +- src/librustc_const_eval/lib.rs | 2 +- src/librustc_const_math/lib.rs | 2 +- src/librustc_data_structures/lib.rs | 2 +- src/librustc_errors/lib.rs | 2 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_lint/lib.rs | 2 +- src/librustc_metadata/lib.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_resolve/lib.rs | 11 -------- src/librustc_trans/lib.rs | 2 +- src/librustc_trans_utils/lib.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/libserialize/lib.rs | 2 +- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 17 ++---------- src/libsyntax/lib.rs | 2 +- src/libsyntax_pos/lib.rs | 2 +- src/test/codegen/unchecked-float-casts.rs | 1 - src/test/mir-opt/lower_128bit_debug_test.rs | 1 - src/test/mir-opt/lower_128bit_test.rs | 1 - src/test/run-pass/float-int-invalid-const-cast.rs | 1 - src/test/run-pass/i128-ffi.rs | 2 -- src/test/run-pass/i128.rs | 2 +- src/test/run-pass/intrinsics-integer.rs | 2 +- src/test/run-pass/issue-38763.rs | 2 -- src/test/run-pass/issue-38987.rs | 1 - .../run-pass/next-power-of-two-overflow-debug.rs | 2 -- .../run-pass/next-power-of-two-overflow-ndebug.rs | 2 -- src/test/run-pass/saturating-float-casts.rs | 2 +- src/test/run-pass/u128-as-f32.rs | 2 +- src/test/run-pass/u128.rs | 2 +- src/test/ui/feature-gate-i128_type.rs | 18 ------------ src/test/ui/feature-gate-i128_type.stderr | 19 ------------- src/test/ui/feature-gate-i128_type2.rs | 8 +++--- src/test/ui/feature-gate-i128_type2.stderr | 32 ---------------------- src/test/ui/lint-ctypes.rs | 2 +- src/test/ui/lint/type-overflow.rs | 2 -- 46 files changed, 37 insertions(+), 147 deletions(-) delete mode 100644 src/test/ui/feature-gate-i128_type.rs delete mode 100644 src/test/ui/feature-gate-i128_type.stderr (limited to 'src/librustc_data_structures') diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 2de0ffb4b26..09685d1bb40 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -10,7 +10,7 @@ #![deny(warnings)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(rand)] #![feature(repr_simd)] #![feature(test)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f914b1a93a9..19d64d8fea9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,7 +97,7 @@ #![feature(from_ref)] #![feature(fundamental)] #![feature(generic_param_attrs)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9aebe2e4ee4..11fecde3951 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,7 +78,7 @@ #![feature(doc_spotlight)] #![feature(fn_must_use)] #![feature(fundamental)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 18e0aa453d8..9ff42a6d4ea 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1635,8 +1635,7 @@ impl i64 { #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "#![feature(i128_type)] -#![feature(i128)] + 170141183460469231731687303715884105727, "#![feature(i128)] # fn main() { ", " # }" } @@ -3493,8 +3492,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128_type)] -#![feature(i128)] + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128)] # fn main() { ", " diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c71669abb1..0b70f692403 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,7 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(iterator_step_by)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index d6e679bad48..716a2cc6cbb 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -34,7 +34,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(lang_items)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1bb903c0627..061044cdf14 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -53,7 +53,7 @@ #![feature(from_ref)] #![feature(fs_read_write)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 565658804b0..2ee7bea8476 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -46,8 +46,8 @@ #![deny(warnings)] #![forbid(unsafe_code)] -#![feature(i128_type)] #![cfg_attr(stage0, feature(slice_patterns))] +#![cfg_attr(stage0, feature(i128_type))] #![feature(try_from)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index ff46ee79c31..627d79724b2 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #[macro_use] extern crate rustc_apfloat; diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 2b0775e8695..2620448927d 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -23,7 +23,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(macro_lifetime_matcher)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(from_ref)] extern crate arena; diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 5555e727a95..a53055c7ce7 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -20,7 +20,7 @@ #![deny(warnings)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ff869072871..01f91e37db8 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,7 +26,7 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(i128)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(specialization)] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 1152c9c574e..37ae64cef57 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -18,7 +18,7 @@ #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(stage0, feature(conservative_impl_trait))] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] extern crate atty; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 6adb950fe4e..5a33f566e90 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -17,7 +17,7 @@ #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(specialization)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4639f7b2d28..d024adad9d0 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -27,7 +27,7 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(macro_vis_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 902dd87c574..4af5ec9ae08 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -16,7 +16,7 @@ #![feature(box_patterns)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(libc)] #![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 750839f8b00..a1f096b2a38 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -27,7 +27,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(decl_macro)] #![feature(dyn_trait)] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2cb2c76c632..01eda71e9b6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3117,17 +3117,6 @@ impl<'a> Resolver<'a> { self.primitive_type_table.primitive_types .contains_key(&path[0].node.name) => { let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; - match prim { - TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !self.session.features_untracked().i128_type { - emit_feature_err(&self.session.parse_sess, - "i128_type", span, GateIssue::Language, - "128-bit type is unstable"); - - } - } - _ => {} - } PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) } PathResult::Module(module) => PathResolution::new(module.def().unwrap()), diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 38adc603628..d89d19db63e 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,7 +24,7 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(i128)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 9e4addd1ed1..99de124c6e1 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -21,7 +21,7 @@ #![feature(box_syntax)] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![cfg_attr(stage0, feature(conservative_impl_trait))] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e466ef39234..8b3d5af3edd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -86,7 +86,7 @@ This API is completely unstable and subject to change. #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate log; diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2e354252c15..ee952523462 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -23,7 +23,7 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(core_intrinsics)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(specialization)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0b06c5d4d65..3cc5d7b81c3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -270,7 +270,7 @@ #![feature(hashmap_internals)] #![feature(heap_api)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1bb369b551d..4e3c77d5e46 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -303,9 +303,6 @@ declare_features! ( // `extern "ptx-*" fn()` (active, abi_ptx, "1.15.0", None, None), - // The `i128` type - (active, i128_type, "1.16.0", Some(35118), None), - // The `repr(i128)` annotation for enums (active, repr128, "1.16.0", Some(35118), None), @@ -564,6 +561,8 @@ declare_features! ( (accepted, universal_impl_trait, "1.26.0", Some(34511), None), // Allows `impl Trait` in function return types. (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), + // The `i128` type + (accepted, i128_type, "1.26.0", Some(35118), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1641,18 +1640,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { e.span, "yield syntax is experimental"); } - ast::ExprKind::Lit(ref lit) => { - if let ast::LitKind::Int(_, ref ty) = lit.node { - match *ty { - ast::LitIntType::Signed(ast::IntTy::I128) | - ast::LitIntType::Unsigned(ast::UintTy::U128) => { - gate_feature_post!(&self, i128_type, e.span, - "128-bit integers are not stable"); - } - _ => {} - } - } - } ast::ExprKind::Catch(_) => { gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 74f1ee373ec..2218b396685 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -24,7 +24,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(match_default_bindings)] #![feature(non_exhaustive)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 5a7b7e9ceca..eb345200f41 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] diff --git a/src/test/codegen/unchecked-float-casts.rs b/src/test/codegen/unchecked-float-casts.rs index c2fc2966170..87ebaaeec32 100644 --- a/src/test/codegen/unchecked-float-casts.rs +++ b/src/test/codegen/unchecked-float-casts.rs @@ -14,7 +14,6 @@ // -Z saturating-float-casts is not enabled. #![crate_type = "lib"] -#![feature(i128_type)] // CHECK-LABEL: @f32_to_u32 #[no_mangle] diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index 1752445a141..d7586b1aa4b 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -15,7 +15,6 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=yes -#![feature(i128_type)] #![feature(const_fn)] static TEST_SIGNED: i128 = const_signed(-222); diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index 4058eaef9b0..341682debeb 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -15,7 +15,6 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -#![feature(i128_type)] #![feature(const_fn)] static TEST_SIGNED: i128 = const_signed(-222); diff --git a/src/test/run-pass/float-int-invalid-const-cast.rs b/src/test/run-pass/float-int-invalid-const-cast.rs index d44f78922c7..f84432abbfa 100644 --- a/src/test/run-pass/float-int-invalid-const-cast.rs +++ b/src/test/run-pass/float-int-invalid-const-cast.rs @@ -10,7 +10,6 @@ // ignore-emscripten no i128 support -#![feature(i128_type)] #![deny(const_err)] use std::{f32, f64}; diff --git a/src/test/run-pass/i128-ffi.rs b/src/test/run-pass/i128-ffi.rs index d989210dd71..edf278cbf64 100644 --- a/src/test/run-pass/i128-ffi.rs +++ b/src/test/run-pass/i128-ffi.rs @@ -15,8 +15,6 @@ // ignore-windows // ignore-32bit -#![feature(i128_type)] - #[link(name = "rust_test_helpers", kind = "static")] extern "C" { fn identity(f: u128) -> u128; diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index c3e43c92590..baf3b339984 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -12,7 +12,7 @@ // compile-flags: -Z borrowck=compare -#![feature(i128_type, test)] +#![feature(test)] extern crate test; use test::black_box as b; diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index cdfad51e648..7a8ff1befc7 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -10,7 +10,7 @@ // ignore-emscripten no i128 support -#![feature(intrinsics, i128_type)] +#![feature(intrinsics)] mod rusti { extern "rust-intrinsic" { diff --git a/src/test/run-pass/issue-38763.rs b/src/test/run-pass/issue-38763.rs index 01cc8265a39..e038062ff9a 100644 --- a/src/test/run-pass/issue-38763.rs +++ b/src/test/run-pass/issue-38763.rs @@ -10,8 +10,6 @@ // ignore-emscripten -#![feature(i128_type)] - #[repr(C)] pub struct Foo(i128); diff --git a/src/test/run-pass/issue-38987.rs b/src/test/run-pass/issue-38987.rs index a513476d4a3..31a3b7233d8 100644 --- a/src/test/run-pass/issue-38987.rs +++ b/src/test/run-pass/issue-38987.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(i128_type)] fn main() { let _ = -0x8000_0000_0000_0000_0000_0000_0000_0000i128; diff --git a/src/test/run-pass/next-power-of-two-overflow-debug.rs b/src/test/run-pass/next-power-of-two-overflow-debug.rs index 599c6dfd31d..2135b3f8764 100644 --- a/src/test/run-pass/next-power-of-two-overflow-debug.rs +++ b/src/test/run-pass/next-power-of-two-overflow-debug.rs @@ -12,8 +12,6 @@ // ignore-wasm32-bare compiled with panic=abort by default // ignore-emscripten dies with an LLVM error -#![feature(i128_type)] - use std::panic; fn main() { diff --git a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs index f2312b70be6..b05c1863d90 100644 --- a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs +++ b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs @@ -11,8 +11,6 @@ // compile-flags: -C debug_assertions=no // ignore-emscripten dies with an LLVM error -#![feature(i128_type)] - fn main() { for i in 129..256 { assert_eq!((i as u8).next_power_of_two(), 0); diff --git a/src/test/run-pass/saturating-float-casts.rs b/src/test/run-pass/saturating-float-casts.rs index c8fa49c62a0..d1a0901bb3d 100644 --- a/src/test/run-pass/saturating-float-casts.rs +++ b/src/test/run-pass/saturating-float-casts.rs @@ -11,7 +11,7 @@ // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. // compile-flags: -Z saturating-float-casts -#![feature(test, i128, i128_type, stmt_expr_attributes)] +#![feature(test, i128, stmt_expr_attributes)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128-as-f32.rs b/src/test/run-pass/u128-as-f32.rs index 117e520155f..3531a961bef 100644 --- a/src/test/run-pass/u128-as-f32.rs +++ b/src/test/run-pass/u128-as-f32.rs @@ -10,7 +10,7 @@ // ignore-emscripten u128 not supported -#![feature(test, i128, i128_type)] +#![feature(test, i128)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index ebd43a86033..d649b3b74d3 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -12,7 +12,7 @@ // compile-flags: -Z borrowck=compare -#![feature(i128_type, test)] +#![feature(test)] extern crate test; use test::black_box as b; diff --git a/src/test/ui/feature-gate-i128_type.rs b/src/test/ui/feature-gate-i128_type.rs deleted file mode 100644 index ddb49a3e5d9..00000000000 --- a/src/test/ui/feature-gate-i128_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -fn test2() { - 0i128; //~ ERROR 128-bit integers are not stable -} - -fn test2_2() { - 0u128; //~ ERROR 128-bit integers are not stable -} - diff --git a/src/test/ui/feature-gate-i128_type.stderr b/src/test/ui/feature-gate-i128_type.stderr deleted file mode 100644 index eb3b29f4f55..00000000000 --- a/src/test/ui/feature-gate-i128_type.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: 128-bit integers are not stable (see issue #35118) - --> $DIR/feature-gate-i128_type.rs:12:5 - | -LL | 0i128; //~ ERROR 128-bit integers are not stable - | ^^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit integers are not stable (see issue #35118) - --> $DIR/feature-gate-i128_type.rs:16:5 - | -LL | 0u128; //~ ERROR 128-bit integers are not stable - | ^^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-i128_type2.rs b/src/test/ui/feature-gate-i128_type2.rs index 8a7d316ed83..cd65b9d9223 100644 --- a/src/test/ui/feature-gate-i128_type2.rs +++ b/src/test/ui/feature-gate-i128_type2.rs @@ -10,20 +10,20 @@ // gate-test-i128_type -fn test1() -> i128 { //~ ERROR 128-bit type is unstable +fn test1() -> i128 { 0 } -fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable +fn test1_2() -> u128 { 0 } fn test3() { - let x: i128 = 0; //~ ERROR 128-bit type is unstable + let x: i128 = 0; } fn test3_2() { - let x: u128 = 0; //~ ERROR 128-bit type is unstable + let x: u128 = 0; } #[repr(u128)] diff --git a/src/test/ui/feature-gate-i128_type2.stderr b/src/test/ui/feature-gate-i128_type2.stderr index 23d4d6c98d9..fe4557899ac 100644 --- a/src/test/ui/feature-gate-i128_type2.stderr +++ b/src/test/ui/feature-gate-i128_type2.stderr @@ -1,35 +1,3 @@ -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:13:15 - | -LL | fn test1() -> i128 { //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:17:17 - | -LL | fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:22:12 - | -LL | let x: i128 = 0; //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:26:12 - | -LL | let x: u128 = 0; //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - error[E0658]: repr with 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:30:1 | diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index 77cb1ef0f51..85957831653 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![deny(improper_ctypes)] -#![feature(libc, i128_type, repr_transparent)] +#![feature(libc, repr_transparent)] extern crate libc; diff --git a/src/test/ui/lint/type-overflow.rs b/src/test/ui/lint/type-overflow.rs index 495989587e5..30e6fb2883b 100644 --- a/src/test/ui/lint/type-overflow.rs +++ b/src/test/ui/lint/type-overflow.rs @@ -10,8 +10,6 @@ // must-compile-successfully -#![feature(i128_type)] - fn main() { let error = 255i8; //~WARNING literal out of range for i8 -- cgit 1.4.1-3-g733a5 From db7d9ea480e16c7135c997f56b44d3c0a657cc9d Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 16 Mar 2018 20:15:56 -0500 Subject: Stabilize i128 feature too --- src/doc/unstable-book/src/language-features/i128-type.md | 2 +- src/libcore/num/i128.rs | 4 ++-- src/libcore/num/mod.rs | 11 ++--------- src/librustc/lib.rs | 3 +-- src/librustc_const_math/lib.rs | 3 +-- src/librustc_data_structures/lib.rs | 3 +-- src/librustc_trans/lib.rs | 3 +-- src/libstd/lib.rs | 7 +++---- src/libsyntax/diagnostic_list.rs | 12 ++++++++---- src/test/ui/error-codes/E0658.stderr | 2 +- 10 files changed, 21 insertions(+), 29 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/doc/unstable-book/src/language-features/i128-type.md b/src/doc/unstable-book/src/language-features/i128-type.md index 6f46469f324..ff5fc0fdc15 100644 --- a/src/doc/unstable-book/src/language-features/i128-type.md +++ b/src/doc/unstable-book/src/language-features/i128-type.md @@ -9,7 +9,7 @@ The tracking issue for this feature is: [#35118] The `i128` feature adds support for `#[repr(u128)]` on `enum`s. ```rust -#![feature(i128)] +#![feature(repri128)] #[repr(u128)] enum Foo { diff --git a/src/libcore/num/i128.rs b/src/libcore/num/i128.rs index 04354e2e33f..989376d1ac2 100644 --- a/src/libcore/num/i128.rs +++ b/src/libcore/num/i128.rs @@ -12,6 +12,6 @@ //! //! *[See also the `i128` primitive type](../../std/primitive.i128.html).* -#![unstable(feature = "i128", issue="35118")] +#![stable(feature = "i128", since = "1.26.0")] -int_module! { i128, #[unstable(feature = "i128", issue="35118")] } +int_module! { i128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 9ff42a6d4ea..66f7160827a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1635,10 +1635,7 @@ impl i64 { #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "#![feature(i128)] -# fn main() { -", " -# }" } + 170141183460469231731687303715884105727, "", "" } } #[cfg(target_pointer_width = "16")] @@ -3492,11 +3489,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128)] - -# fn main() { -", " -# }" } + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "", "" } } #[cfg(target_pointer_width = "16")] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 061044cdf14..e835d6192e5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -52,8 +52,7 @@ #![feature(entry_or_default)] #![feature(from_ref)] #![feature(fs_read_write)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index a53055c7ce7..7177e2818fb 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -19,8 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 01f91e37db8..378a06dd912 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,9 +26,8 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![cfg_attr(stage0, feature(i128_type))] -#![feature(i128)] #![cfg_attr(stage0, feature(conservative_impl_trait))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(specialization)] #![feature(optin_builtin_traits)] #![feature(underscore_lifetimes)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index d89d19db63e..bd33707b1c6 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,8 +24,7 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type))] -#![feature(i128)] +#![cfg_attr(stage0, feature(i128_type, i128))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] #![feature(quote)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3cc5d7b81c3..93996868f16 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -269,8 +269,7 @@ #![feature(generic_param_attrs)] #![feature(hashmap_internals)] #![feature(heap_api)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] @@ -435,7 +434,7 @@ pub use core::i16; pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::i64; -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] pub use core::i128; #[stable(feature = "rust1", since = "1.0.0")] pub use core::usize; @@ -465,7 +464,7 @@ pub use alloc::string; pub use alloc::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::char; -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] pub use core::u128; pub mod f32; diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 1f87c1b94c5..3246dc47701 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -250,7 +250,10 @@ An unstable feature was used. Erroneous code example: ```compile_fail,E658 -let x = ::std::u128::MAX; // error: use of unstable library feature 'i128' +#[repr(u128)] // error: use of unstable library feature 'i128' +enum Foo { + Bar(u64), +} ``` If you're using a stable or a beta version of rustc, you won't be able to use @@ -261,10 +264,11 @@ If you're using a nightly version of rustc, just add the corresponding feature to be able to use it: ``` -#![feature(i128)] +#![feature(repri128)] -fn main() { - let x = ::std::u128::MAX; // ok! +#[repr(u128)] // ok! +enum Foo { + Bar(u64), } ``` "##, diff --git a/src/test/ui/error-codes/E0658.stderr b/src/test/ui/error-codes/E0658.stderr index 5be05600ee5..f4294e6b026 100644 --- a/src/test/ui/error-codes/E0658.stderr +++ b/src/test/ui/error-codes/E0658.stderr @@ -4,7 +4,7 @@ error[E0658]: use of unstable library feature 'i128' (see issue #35118) LL | let _ = ::std::u128::MAX; //~ ERROR E0658 | ^^^^^^^^^^^^^^^^ | - = help: add #![feature(i128)] to the crate attributes to enable + = help: add #![feature(repri128)] to the crate attributes to enable error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 962a53d4741e4e2e514f49d9b13831f3cd4e7b48 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Mon, 26 Mar 2018 20:52:59 +0200 Subject: Add try_write to RwLock --- src/librustc_data_structures/sync.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 184ef136976..0f534f0adec 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -388,6 +388,18 @@ impl RwLock { f(&*self.read()) } + #[cfg(not(parallel_queries))] + #[inline(always)] + pub fn try_write(&self) -> Result, ()> { + self.0.try_borrow_mut().map_err(|_| ()) + } + + #[cfg(parallel_queries)] + #[inline(always)] + pub fn try_write(&self) -> Result, ()> { + self.0.try_write().ok_or(()) + } + #[cfg(not(parallel_queries))] #[inline(always)] pub fn write(&self) -> WriteGuard { -- cgit 1.4.1-3-g733a5 From e6e6bd27d563b9a53687433feb3d4d4672dafd66 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 28 Mar 2018 17:25:39 +0200 Subject: Stabilize underscore lifetimes --- src/librustc/lib.rs | 2 +- src/librustc_data_structures/lib.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_traits/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 13 +++++-------- .../expect-fn-supply-fn-multiple.rs | 1 - .../closure-expected-type/expect-fn-supply-fn.rs | 2 -- src/test/compile-fail/underscore-lifetime-binders.rs | 2 -- .../underscore-lifetime-elison-mismatch.rs | 2 -- src/test/run-pass/impl-trait/lifetimes.rs | 1 - src/test/run-pass/underscore-lifetimes.rs | 2 -- src/test/ui/error-codes/E0637.rs | 1 - src/test/ui/error-codes/E0637.stderr | 6 +++--- src/test/ui/feature-gate-in_band_lifetimes-impl.rs | 1 - .../ui/feature-gate-in_band_lifetimes-impl.stderr | 4 ++-- src/test/ui/feature-gate-underscore-lifetimes.rs | 20 -------------------- src/test/ui/feature-gate-underscore-lifetimes.stderr | 11 ----------- src/test/ui/in-band-lifetimes/impl/assoc-type.rs | 1 - src/test/ui/in-band-lifetimes/impl/assoc-type.stderr | 4 ++-- src/test/ui/in-band-lifetimes/impl/dyn-trait.rs | 1 - src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr | 6 +++--- src/test/ui/in-band-lifetimes/impl/path-elided.rs | 1 - .../ui/in-band-lifetimes/impl/path-elided.stderr | 2 +- .../ui/in-band-lifetimes/impl/path-underscore.rs | 1 - src/test/ui/in-band-lifetimes/impl/ref-underscore.rs | 1 - src/test/ui/in-band-lifetimes/impl/trait-elided.rs | 1 - .../ui/in-band-lifetimes/impl/trait-elided.stderr | 2 +- .../ui/in-band-lifetimes/impl/trait-underscore.rs | 1 - .../dyn-trait-underscore-in-struct.rs | 1 - .../dyn-trait-underscore-in-struct.stderr | 4 ++-- .../ui/underscore-lifetime/dyn-trait-underscore.rs | 1 - .../underscore-lifetime/dyn-trait-underscore.stderr | 8 ++++---- 32 files changed, 27 insertions(+), 82 deletions(-) delete mode 100644 src/test/ui/feature-gate-underscore-lifetimes.rs delete mode 100644 src/test/ui/feature-gate-underscore-lifetimes.stderr (limited to 'src/librustc_data_structures') diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ae8ae9404bc..dcad8132c2b 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -68,7 +68,7 @@ #![feature(slice_patterns)] #![feature(specialization)] #![feature(unboxed_closures)] -#![feature(underscore_lifetimes)] +#![cfg_attr(stage0, feature(underscore_lifetimes))] #![cfg_attr(stage0, feature(universal_impl_trait))] #![feature(trace_macros)] #![feature(trusted_len)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 378a06dd912..622fb423b51 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -30,7 +30,7 @@ #![cfg_attr(stage0, feature(i128_type, i128))] #![feature(specialization)] #![feature(optin_builtin_traits)] -#![feature(underscore_lifetimes)] +#![cfg_attr(stage0, feature(underscore_lifetimes))] #![feature(macro_vis_matcher)] #![feature(allow_internal_unstable)] #![cfg_attr(stage0, feature(universal_impl_trait))] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 262e5f608ca..7af3a397666 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -37,7 +37,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(placement_in_syntax)] #![feature(collection_placement)] #![feature(nonzero)] -#![feature(underscore_lifetimes)] +#![cfg_attr(stage0, feature(underscore_lifetimes))] #![cfg_attr(stage0, feature(never_type))] #![feature(inclusive_range_fields)] diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 0a21cc597e6..90f368edeec 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -15,7 +15,7 @@ #![feature(crate_visibility_modifier)] #![cfg_attr(stage0, feature(match_default_bindings))] -#![feature(underscore_lifetimes)] +#![cfg_attr(stage0, feature(underscore_lifetimes))] #[macro_use] extern crate log; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ce8c613dc8b..526608d07aa 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -385,6 +385,9 @@ declare_features! ( // allow `'_` placeholder lifetimes (active, underscore_lifetimes, "1.22.0", Some(44524), None), + // Default match binding modes (RFC 2005) + (active, match_default_bindings, "1.22.0", Some(42640), None), + // Trait object syntax with `dyn` prefix (active, dyn_trait, "1.22.0", Some(44662), Some(Edition::Edition2018)), @@ -562,6 +565,8 @@ declare_features! ( (accepted, i128_type, "1.26.0", Some(35118), None), // Default match binding modes (RFC 2005) (accepted, match_default_bindings, "1.26.0", Some(42640), None), + // allow `'_` placeholder lifetimes + (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1792,14 +1797,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_generic_param(self, param) } - - fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { - if lt.ident.name == keywords::UnderscoreLifetime.name() { - gate_feature_post!(&self, underscore_lifetimes, lt.span, - "underscore lifetimes are unstable"); - } - visit::walk_lifetime(self, lt) - } } pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], diff --git a/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn-multiple.rs b/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn-multiple.rs index f1b198a0591..124e55ea23a 100644 --- a/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn-multiple.rs +++ b/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn-multiple.rs @@ -10,7 +10,6 @@ // must-compile-successfully -#![feature(underscore_lifetimes)] #![allow(warnings)] type Different<'a, 'b> = &'a mut (&'a (), &'b ()); diff --git a/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn.rs b/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn.rs index 645fd1f80ba..63284c98020 100644 --- a/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn.rs +++ b/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(underscore_lifetimes)] - fn with_closure_expecting_fn_with_free_region(_: F) where F: for<'a> FnOnce(fn(&'a u32), &i32) { diff --git a/src/test/compile-fail/underscore-lifetime-binders.rs b/src/test/compile-fail/underscore-lifetime-binders.rs index 99b6e036f33..eb00ab5f67a 100644 --- a/src/test/compile-fail/underscore-lifetime-binders.rs +++ b/src/test/compile-fail/underscore-lifetime-binders.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(underscore_lifetimes)] - struct Foo<'a>(&'a u8); struct Baz<'a>(&'_ &'a u8); //~ ERROR missing lifetime specifier diff --git a/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs b/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs index a1c4e4a1fd9..b36c8eb324e 100644 --- a/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs +++ b/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(underscore_lifetimes)] - fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } //~ ERROR lifetime mismatch fn main() {} diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index 1b50ceefbe1..d126d795d90 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(underscore_lifetimes)] #![allow(warnings)] use std::fmt::Debug; diff --git a/src/test/run-pass/underscore-lifetimes.rs b/src/test/run-pass/underscore-lifetimes.rs index ed0369353bc..4dd1a565c9f 100644 --- a/src/test/run-pass/underscore-lifetimes.rs +++ b/src/test/run-pass/underscore-lifetimes.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(underscore_lifetimes)] - struct Foo<'a>(&'a u8); fn foo(x: &u8) -> Foo<'_> { diff --git a/src/test/ui/error-codes/E0637.rs b/src/test/ui/error-codes/E0637.rs index 455529b088a..ee6a978d169 100644 --- a/src/test/ui/error-codes/E0637.rs +++ b/src/test/ui/error-codes/E0637.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(underscore_lifetimes)] struct Foo<'a: '_>(&'a u8); //~ ERROR invalid lifetime bound name: `'_` fn foo<'a: '_>(_: &'a u8) {} //~ ERROR invalid lifetime bound name: `'_` diff --git a/src/test/ui/error-codes/E0637.stderr b/src/test/ui/error-codes/E0637.stderr index b8c926efb45..245729376df 100644 --- a/src/test/ui/error-codes/E0637.stderr +++ b/src/test/ui/error-codes/E0637.stderr @@ -1,17 +1,17 @@ error[E0637]: invalid lifetime bound name: `'_` - --> $DIR/E0637.rs:12:16 + --> $DIR/E0637.rs:11:16 | LL | struct Foo<'a: '_>(&'a u8); //~ ERROR invalid lifetime bound name: `'_` | ^^ `'_` is a reserved lifetime name error[E0637]: invalid lifetime bound name: `'_` - --> $DIR/E0637.rs:13:12 + --> $DIR/E0637.rs:12:12 | LL | fn foo<'a: '_>(_: &'a u8) {} //~ ERROR invalid lifetime bound name: `'_` | ^^ `'_` is a reserved lifetime name error[E0637]: invalid lifetime bound name: `'_` - --> $DIR/E0637.rs:16:10 + --> $DIR/E0637.rs:15:10 | LL | impl<'a: '_> Bar<'a> { //~ ERROR invalid lifetime bound name: `'_` | ^^ `'_` is a reserved lifetime name diff --git a/src/test/ui/feature-gate-in_band_lifetimes-impl.rs b/src/test/ui/feature-gate-in_band_lifetimes-impl.rs index a02b3e80009..3eb2ac1b008 100644 --- a/src/test/ui/feature-gate-in_band_lifetimes-impl.rs +++ b/src/test/ui/feature-gate-in_band_lifetimes-impl.rs @@ -9,7 +9,6 @@ // except according to those terms. #![allow(warnings)] -#![feature(underscore_lifetimes)] trait MyTrait<'a> { } diff --git a/src/test/ui/feature-gate-in_band_lifetimes-impl.stderr b/src/test/ui/feature-gate-in_band_lifetimes-impl.stderr index e32a06c3ce4..95bf81f41f8 100644 --- a/src/test/ui/feature-gate-in_band_lifetimes-impl.stderr +++ b/src/test/ui/feature-gate-in_band_lifetimes-impl.stderr @@ -1,11 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/feature-gate-in_band_lifetimes-impl.rs:16:26 + --> $DIR/feature-gate-in_band_lifetimes-impl.rs:15:26 | LL | impl<'a> MyTrait<'a> for &u32 { } | ^ expected lifetime parameter error[E0106]: missing lifetime specifier - --> $DIR/feature-gate-in_band_lifetimes-impl.rs:19:18 + --> $DIR/feature-gate-in_band_lifetimes-impl.rs:18:18 | LL | impl<'a> MyTrait<'_> for &'a f32 { } | ^^ expected lifetime parameter diff --git a/src/test/ui/feature-gate-underscore-lifetimes.rs b/src/test/ui/feature-gate-underscore-lifetimes.rs deleted file mode 100644 index 9da50c5c877..00000000000 --- a/src/test/ui/feature-gate-underscore-lifetimes.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 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. - -struct Foo<'a>(&'a u8); - -fn foo(x: &u8) -> Foo<'_> { //~ ERROR underscore lifetimes are unstable - Foo(x) -} - -fn main() { - let x = 5; - let _ = foo(&x); -} diff --git a/src/test/ui/feature-gate-underscore-lifetimes.stderr b/src/test/ui/feature-gate-underscore-lifetimes.stderr deleted file mode 100644 index c1cddcd763e..00000000000 --- a/src/test/ui/feature-gate-underscore-lifetimes.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: underscore lifetimes are unstable (see issue #44524) - --> $DIR/feature-gate-underscore-lifetimes.rs:13:23 - | -LL | fn foo(x: &u8) -> Foo<'_> { //~ ERROR underscore lifetimes are unstable - | ^^ - | - = help: add #![feature(underscore_lifetimes)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/in-band-lifetimes/impl/assoc-type.rs b/src/test/ui/in-band-lifetimes/impl/assoc-type.rs index 54f38b2e729..ab35331b279 100644 --- a/src/test/ui/in-band-lifetimes/impl/assoc-type.rs +++ b/src/test/ui/in-band-lifetimes/impl/assoc-type.rs @@ -14,7 +14,6 @@ #![allow(warnings)] #![feature(in_band_lifetimes)] -#![feature(underscore_lifetimes)] trait MyTrait { type Output; diff --git a/src/test/ui/in-band-lifetimes/impl/assoc-type.stderr b/src/test/ui/in-band-lifetimes/impl/assoc-type.stderr index 909b86daef0..59b2cfd2226 100644 --- a/src/test/ui/in-band-lifetimes/impl/assoc-type.stderr +++ b/src/test/ui/in-band-lifetimes/impl/assoc-type.stderr @@ -1,11 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/assoc-type.rs:24:19 + --> $DIR/assoc-type.rs:23:19 | LL | type Output = &i32; | ^ expected lifetime parameter error[E0106]: missing lifetime specifier - --> $DIR/assoc-type.rs:29:20 + --> $DIR/assoc-type.rs:28:20 | LL | type Output = &'_ i32; | ^^ expected lifetime parameter diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs b/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs index e839248b0e3..a504bae2e60 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs @@ -15,7 +15,6 @@ #![feature(dyn_trait)] #![feature(in_band_lifetimes)] -#![feature(underscore_lifetimes)] use std::fmt::Debug; diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr b/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr index 0054ca3d1a5..9d6a318c075 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr @@ -1,11 +1,11 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/dyn-trait.rs:34:16 + --> $DIR/dyn-trait.rs:33:16 | LL | static_val(x); //~ ERROR cannot infer | ^ | -note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 33:1... - --> $DIR/dyn-trait.rs:33:1 +note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 32:1... + --> $DIR/dyn-trait.rs:32:1 | LL | fn with_dyn_debug_static<'a>(x: Box) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/in-band-lifetimes/impl/path-elided.rs b/src/test/ui/in-band-lifetimes/impl/path-elided.rs index fa1b4523889..8a758b124ba 100644 --- a/src/test/ui/in-band-lifetimes/impl/path-elided.rs +++ b/src/test/ui/in-band-lifetimes/impl/path-elided.rs @@ -10,7 +10,6 @@ #![allow(warnings)] #![feature(in_band_lifetimes)] -#![feature(underscore_lifetimes)] trait MyTrait { } diff --git a/src/test/ui/in-band-lifetimes/impl/path-elided.stderr b/src/test/ui/in-band-lifetimes/impl/path-elided.stderr index 19e69c61a03..6c1d72411bf 100644 --- a/src/test/ui/in-band-lifetimes/impl/path-elided.stderr +++ b/src/test/ui/in-band-lifetimes/impl/path-elided.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/path-elided.rs:19:18 + --> $DIR/path-elided.rs:18:18 | LL | impl MyTrait for Foo { | ^^^ expected lifetime parameter diff --git a/src/test/ui/in-band-lifetimes/impl/path-underscore.rs b/src/test/ui/in-band-lifetimes/impl/path-underscore.rs index 56f2d93d9e0..756991d97a5 100644 --- a/src/test/ui/in-band-lifetimes/impl/path-underscore.rs +++ b/src/test/ui/in-band-lifetimes/impl/path-underscore.rs @@ -15,7 +15,6 @@ #![allow(warnings)] #![feature(in_band_lifetimes)] -#![feature(underscore_lifetimes)] trait MyTrait { } diff --git a/src/test/ui/in-band-lifetimes/impl/ref-underscore.rs b/src/test/ui/in-band-lifetimes/impl/ref-underscore.rs index 1b1035abeba..99708afff35 100644 --- a/src/test/ui/in-band-lifetimes/impl/ref-underscore.rs +++ b/src/test/ui/in-band-lifetimes/impl/ref-underscore.rs @@ -15,7 +15,6 @@ #![allow(warnings)] #![feature(in_band_lifetimes)] -#![feature(underscore_lifetimes)] trait MyTrait { } diff --git a/src/test/ui/in-band-lifetimes/impl/trait-elided.rs b/src/test/ui/in-band-lifetimes/impl/trait-elided.rs index 7594d66e078..e0709ab6dd0 100644 --- a/src/test/ui/in-band-lifetimes/impl/trait-elided.rs +++ b/src/test/ui/in-band-lifetimes/impl/trait-elided.rs @@ -10,7 +10,6 @@ #![allow(warnings)] #![feature(in_band_lifetimes)] -#![feature(underscore_lifetimes)] trait MyTrait<'a> { } diff --git a/src/test/ui/in-band-lifetimes/impl/trait-elided.stderr b/src/test/ui/in-band-lifetimes/impl/trait-elided.stderr index bb301882868..fe3ded8e04c 100644 --- a/src/test/ui/in-band-lifetimes/impl/trait-elided.stderr +++ b/src/test/ui/in-band-lifetimes/impl/trait-elided.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/trait-elided.rs:17:6 + --> $DIR/trait-elided.rs:16:6 | LL | impl MyTrait for u32 { | ^^^^^^^ expected lifetime parameter diff --git a/src/test/ui/in-band-lifetimes/impl/trait-underscore.rs b/src/test/ui/in-band-lifetimes/impl/trait-underscore.rs index 077e33c1efd..971fd1fe759 100644 --- a/src/test/ui/in-band-lifetimes/impl/trait-underscore.rs +++ b/src/test/ui/in-band-lifetimes/impl/trait-underscore.rs @@ -16,7 +16,6 @@ #![allow(warnings)] #![feature(in_band_lifetimes)] -#![feature(underscore_lifetimes)] trait MyTrait<'a> { } diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs index d10541ad33b..e573ad8fc1f 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs @@ -14,7 +14,6 @@ // cc #48468 #![feature(dyn_trait)] -#![feature(underscore_lifetimes)] use std::fmt::Debug; diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index a88ecb18dd6..6d777841f03 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -1,11 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/dyn-trait-underscore-in-struct.rs:22:24 + --> $DIR/dyn-trait-underscore-in-struct.rs:21:24 | LL | x: Box, //~ ERROR missing lifetime specifier | ^^ expected lifetime parameter error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound - --> $DIR/dyn-trait-underscore-in-struct.rs:22:12 + --> $DIR/dyn-trait-underscore-in-struct.rs:21:12 | LL | x: Box, //~ ERROR missing lifetime specifier | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs index c2476220100..9640d346597 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs @@ -14,7 +14,6 @@ // cc #48468 #![feature(dyn_trait)] -#![feature(underscore_lifetimes)] fn a(items: &[T]) -> Box> { // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index cb3035f42a0..f1e59aed54a 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,11 +1,11 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements - --> $DIR/dyn-trait-underscore.rs:21:20 + --> $DIR/dyn-trait-underscore.rs:20:20 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 19:1... - --> $DIR/dyn-trait-underscore.rs:19:1 +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 18:1... + --> $DIR/dyn-trait-underscore.rs:18:1 | LL | / fn a(items: &[T]) -> Box> { LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` @@ -13,7 +13,7 @@ LL | | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime LL | | } | |_^ note: ...so that reference does not outlive borrowed content - --> $DIR/dyn-trait-underscore.rs:21:14 + --> $DIR/dyn-trait-underscore.rs:20:14 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^ -- cgit 1.4.1-3-g733a5 From c3a63970dee2422e2fcc79d8b99303b4b046f444 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 19 Mar 2018 09:01:17 +0100 Subject: Move alloc::Bound to {core,std}::ops The stable reexport `std::collections::Bound` is now deprecated. Another deprecated reexport could be added in `alloc`, but that crate is unstable. --- src/liballoc/btree/map.rs | 4 +- src/liballoc/btree/set.rs | 2 +- src/liballoc/lib.rs | 51 ---------------------- src/liballoc/range.rs | 2 +- src/liballoc/string.rs | 2 +- src/liballoc/tests/btree/map.rs | 2 +- src/liballoc/vec.rs | 2 +- src/liballoc/vec_deque.rs | 2 +- src/libcore/ops/mod.rs | 2 +- src/libcore/ops/range.rs | 51 ++++++++++++++++++++++ src/librustc_data_structures/array_vec.rs | 2 +- src/libstd/collections/mod.rs | 3 +- .../sync-send-iterators-in-libcollections.rs | 2 +- 13 files changed, 64 insertions(+), 63 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index cada190032a..2ba56063e36 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -13,11 +13,11 @@ use core::fmt::Debug; use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::Index; use core::{fmt, intrinsics, mem, ptr}; use borrow::Borrow; -use Bound::{Excluded, Included, Unbounded}; use range::RangeArgument; use super::node::{self, Handle, NodeRef, marker}; @@ -804,7 +804,7 @@ impl BTreeMap { /// /// ``` /// use std::collections::BTreeMap; - /// use std::collections::Bound::Included; + /// use std::ops::Bound::Included; /// /// let mut map = BTreeMap::new(); /// map.insert(3, "a"); diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index 2e3157147a0..d488dd6cbbd 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -240,7 +240,7 @@ impl BTreeSet { /// /// ``` /// use std::collections::BTreeSet; - /// use std::collections::Bound::Included; + /// use std::ops::Bound::Included; /// /// let mut set = BTreeSet::new(); /// set.insert(3); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 19d64d8fea9..eddbd50ea03 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -204,57 +204,6 @@ mod std { pub use core::ops; // RangeFull } -/// An endpoint of a range of keys. -/// -/// # Examples -/// -/// `Bound`s are range endpoints: -/// -/// ``` -/// #![feature(collections_range)] -/// -/// use std::collections::range::RangeArgument; -/// use std::collections::Bound::*; -/// -/// assert_eq!((..100).start(), Unbounded); -/// assert_eq!((1..12).start(), Included(&1)); -/// assert_eq!((1..12).end(), Excluded(&12)); -/// ``` -/// -/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. -/// Note that in most cases, it's better to use range syntax (`1..5`) instead. -/// -/// ``` -/// use std::collections::BTreeMap; -/// use std::collections::Bound::{Excluded, Included, Unbounded}; -/// -/// let mut map = BTreeMap::new(); -/// map.insert(3, "a"); -/// map.insert(5, "b"); -/// map.insert(8, "c"); -/// -/// for (key, value) in map.range((Excluded(3), Included(8))) { -/// println!("{}: {}", key, value); -/// } -/// -/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next()); -/// ``` -/// -/// [`BTreeMap::range`]: btree_map/struct.BTreeMap.html#method.range -#[stable(feature = "collections_bound", since = "1.17.0")] -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] -pub enum Bound { - /// An inclusive bound. - #[stable(feature = "collections_bound", since = "1.17.0")] - Included(#[stable(feature = "collections_bound", since = "1.17.0")] T), - /// An exclusive bound. - #[stable(feature = "collections_bound", since = "1.17.0")] - Excluded(#[stable(feature = "collections_bound", since = "1.17.0")] T), - /// An infinite endpoint. Indicates that there is no bound in this direction. - #[stable(feature = "collections_bound", since = "1.17.0")] - Unbounded, -} - /// An intermediate trait for specialization of `Extend`. #[doc(hidden)] trait SpecExtend { diff --git a/src/liballoc/range.rs b/src/liballoc/range.rs index b03abc85180..7cadbf3c90a 100644 --- a/src/liballoc/range.rs +++ b/src/liballoc/range.rs @@ -15,7 +15,7 @@ //! Range syntax. use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; -use Bound::{self, Excluded, Included, Unbounded}; +use core::ops::Bound::{self, Excluded, Included, Unbounded}; /// `RangeArgument` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 23c12bef3aa..754c78f7779 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -59,6 +59,7 @@ use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str::pattern::Pattern; @@ -67,7 +68,6 @@ use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; use range::RangeArgument; -use Bound::{Excluded, Included, Unbounded}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use vec::Vec; use boxed::Box; diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 2393101040d..6ebdb86cc4a 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -9,8 +9,8 @@ // except according to those terms. use std::collections::BTreeMap; -use std::collections::Bound::{self, Excluded, Included, Unbounded}; use std::collections::btree_map::Entry::{Occupied, Vacant}; +use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::rc::Rc; use std::iter::FromIterator; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index bcc999d7386..280570ecd65 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -75,6 +75,7 @@ use core::marker::PhantomData; use core::mem; #[cfg(not(test))] use core::num::Float; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{InPlace, Index, IndexMut, Place, Placer}; use core::ops; use core::ptr; @@ -87,7 +88,6 @@ use boxed::Box; use raw_vec::RawVec; use super::range::RangeArgument; use super::allocator::CollectionAllocErr; -use Bound::{Excluded, Included, Unbounded}; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index be6e8d0f22f..9efd730790d 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -21,6 +21,7 @@ use core::cmp::Ordering; use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, Place, Placer, InPlace}; use core::ptr; use core::ptr::NonNull; @@ -33,7 +34,6 @@ use raw_vec::RawVec; use super::allocator::CollectionAllocErr; use super::range::RangeArgument; -use Bound::{Excluded, Included, Unbounded}; use super::vec::Vec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 234970a81fa..b0e75135282 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -192,7 +192,7 @@ pub use self::index::{Index, IndexMut}; pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] -pub use self::range::{RangeInclusive, RangeToInclusive}; +pub use self::range::{RangeInclusive, RangeToInclusive, Bound}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index be51f5239b0..dd44aedd09f 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -442,3 +442,54 @@ impl> RangeToInclusive { // RangeToInclusive cannot impl From> // because underflow would be possible with (..0).into() + +/// An endpoint of a range of keys. +/// +/// # Examples +/// +/// `Bound`s are range endpoints: +/// +/// ``` +/// #![feature(collections_range)] +/// +/// use std::collections::range::RangeArgument; +/// use std::ops::Bound::*; +/// +/// assert_eq!((..100).start(), Unbounded); +/// assert_eq!((1..12).start(), Included(&1)); +/// assert_eq!((1..12).end(), Excluded(&12)); +/// ``` +/// +/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. +/// Note that in most cases, it's better to use range syntax (`1..5`) instead. +/// +/// ``` +/// use std::collections::BTreeMap; +/// use std::ops::Bound::{Excluded, Included, Unbounded}; +/// +/// let mut map = BTreeMap::new(); +/// map.insert(3, "a"); +/// map.insert(5, "b"); +/// map.insert(8, "c"); +/// +/// for (key, value) in map.range((Excluded(3), Included(8))) { +/// println!("{}: {}", key, value); +/// } +/// +/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next()); +/// ``` +/// +/// [`BTreeMap::range`]: ../../std/collections/btree_map/struct.BTreeMap.html#method.range +#[stable(feature = "collections_bound", since = "1.17.0")] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +pub enum Bound { + /// An inclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Included(#[stable(feature = "collections_bound", since = "1.17.0")] T), + /// An exclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Excluded(#[stable(feature = "collections_bound", since = "1.17.0")] T), + /// An infinite endpoint. Indicates that there is no bound in this direction. + #[stable(feature = "collections_bound", since = "1.17.0")] + Unbounded, +} diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 511c407d45a..b40f2f92237 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -19,8 +19,8 @@ use std::slice; use std::fmt; use std::mem; use std::collections::range::RangeArgument; -use std::collections::Bound::{Excluded, Included, Unbounded}; use std::mem::ManuallyDrop; +use std::ops::Bound::{Excluded, Included, Unbounded}; pub unsafe trait Array { type Element; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index be88f4e268a..e6f15a6119e 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -420,7 +420,8 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::Bound; +#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")] +pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 903532e9bc8..e096fb3bbae 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -18,8 +18,8 @@ use std::collections::VecDeque; use std::collections::HashMap; use std::collections::HashSet; -use std::collections::Bound::Included; use std::mem; +use std::ops::Bound::Included; fn is_sync(_: T) where T: Sync {} fn is_send(_: T) where T: Send {} -- cgit 1.4.1-3-g733a5 From 16d3ba1b23195da2d53e058c58c2a41def914dec Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 19 Mar 2018 09:26:29 +0100 Subject: Move RangeArguments to {core::std}::ops and rename to RangeBounds These unstable items are deprecated: * The `std::collections::range::RangeArgument` reexport * The `std::collections::range` module. --- src/liballoc/btree/map.rs | 8 +- src/liballoc/btree/set.rs | 5 +- src/liballoc/lib.rs | 2 +- src/liballoc/range.rs | 152 ------------------------ src/liballoc/string.rs | 7 +- src/liballoc/vec.rs | 7 +- src/liballoc/vec_deque.rs | 5 +- src/libcore/ops/mod.rs | 2 +- src/libcore/ops/range.rs | 155 ++++++++++++++++++++++++- src/librustc_data_structures/accumulate_vec.rs | 5 +- src/librustc_data_structures/array_vec.rs | 4 +- src/librustc_data_structures/indexed_vec.rs | 7 +- src/libstd/collections/mod.rs | 8 +- 13 files changed, 183 insertions(+), 184 deletions(-) delete mode 100644 src/liballoc/range.rs (limited to 'src/librustc_data_structures') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 2ba56063e36..c604df7049e 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -15,10 +15,10 @@ use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::Index; +use core::ops::RangeBounds; use core::{fmt, intrinsics, mem, ptr}; use borrow::Borrow; -use range::RangeArgument; use super::node::{self, Handle, NodeRef, marker}; use super::search; @@ -817,7 +817,7 @@ impl BTreeMap { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range(&self, range: R) -> Range - where T: Ord, K: Borrow, R: RangeArgument + where T: Ord, K: Borrow, R: RangeBounds { let root1 = self.root.as_ref(); let root2 = self.root.as_ref(); @@ -857,7 +857,7 @@ impl BTreeMap { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range_mut(&mut self, range: R) -> RangeMut - where T: Ord, K: Borrow, R: RangeArgument + where T: Ord, K: Borrow, R: RangeBounds { let root1 = self.root.as_mut(); let root2 = unsafe { ptr::read(&root1) }; @@ -1812,7 +1812,7 @@ fn last_leaf_edge } } -fn range_search>( +fn range_search>( root1: NodeRef, root2: NodeRef, range: R diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index d488dd6cbbd..2aad476d315 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -16,12 +16,11 @@ use core::cmp::{min, max}; use core::fmt::Debug; use core::fmt; use core::iter::{Peekable, FromIterator, FusedIterator}; -use core::ops::{BitOr, BitAnd, BitXor, Sub}; +use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; use borrow::Borrow; use btree_map::{BTreeMap, Keys}; use super::Recover; -use range::RangeArgument; // FIXME(conventions): implement bounded iterators @@ -253,7 +252,7 @@ impl BTreeSet { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range(&self, range: R) -> Range - where K: Ord, T: Borrow, R: RangeArgument + where K: Ord, T: Borrow, R: RangeBounds { Range { iter: self.map.range(range) } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index eddbd50ea03..e98b58994bf 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -88,6 +88,7 @@ #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] +#![feature(collections_range)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(custom_attribute)] @@ -178,7 +179,6 @@ mod btree; pub mod borrow; pub mod fmt; pub mod linked_list; -pub mod range; pub mod slice; pub mod str; pub mod string; diff --git a/src/liballoc/range.rs b/src/liballoc/range.rs deleted file mode 100644 index 7cadbf3c90a..00000000000 --- a/src/liballoc/range.rs +++ /dev/null @@ -1,152 +0,0 @@ -// 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. - -#![unstable(feature = "collections_range", - reason = "waiting for dust to settle on inclusive ranges", - issue = "30877")] - -//! Range syntax. - -use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; -use core::ops::Bound::{self, Excluded, Included, Unbounded}; - -/// `RangeArgument` is implemented by Rust's built-in range types, produced -/// by range syntax like `..`, `a..`, `..b` or `c..d`. -pub trait RangeArgument { - /// Start index bound. - /// - /// Returns the start value as a `Bound`. - /// - /// # Examples - /// - /// ``` - /// #![feature(alloc)] - /// #![feature(collections_range)] - /// - /// extern crate alloc; - /// - /// # fn main() { - /// use alloc::range::RangeArgument; - /// use alloc::Bound::*; - /// - /// assert_eq!((..10).start(), Unbounded); - /// assert_eq!((3..10).start(), Included(&3)); - /// # } - /// ``` - fn start(&self) -> Bound<&T>; - - /// End index bound. - /// - /// Returns the end value as a `Bound`. - /// - /// # Examples - /// - /// ``` - /// #![feature(alloc)] - /// #![feature(collections_range)] - /// - /// extern crate alloc; - /// - /// # fn main() { - /// use alloc::range::RangeArgument; - /// use alloc::Bound::*; - /// - /// assert_eq!((3..).end(), Unbounded); - /// assert_eq!((3..10).end(), Excluded(&10)); - /// # } - /// ``` - fn end(&self) -> Bound<&T>; -} - -// FIXME add inclusive ranges to RangeArgument - -impl RangeArgument for RangeFull { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Unbounded - } -} - -impl RangeArgument for RangeFrom { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Unbounded - } -} - -impl RangeArgument for RangeTo { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Excluded(&self.end) - } -} - -impl RangeArgument for Range { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Excluded(&self.end) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -impl RangeArgument for RangeInclusive { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Included(&self.end) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -impl RangeArgument for RangeToInclusive { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Included(&self.end) - } -} - -impl RangeArgument for (Bound, Bound) { - fn start(&self) -> Bound<&T> { - match *self { - (Included(ref start), _) => Included(start), - (Excluded(ref start), _) => Excluded(start), - (Unbounded, _) => Unbounded, - } - } - - fn end(&self) -> Bound<&T> { - match *self { - (_, Included(ref end)) => Included(end), - (_, Excluded(ref end)) => Excluded(end), - (_, Unbounded) => Unbounded, - } - } -} - -impl<'a, T: ?Sized + 'a> RangeArgument for (Bound<&'a T>, Bound<&'a T>) { - fn start(&self) -> Bound<&T> { - self.0 - } - - fn end(&self) -> Bound<&T> { - self.1 - } -} diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 754c78f7779..aa202e23628 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -60,14 +60,13 @@ use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{self, Add, AddAssign, Index, IndexMut}; +use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; use std_unicode::lossy; use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; -use range::RangeArgument; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use vec::Vec; use boxed::Box; @@ -1484,7 +1483,7 @@ impl String { /// ``` #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // @@ -1548,7 +1547,7 @@ impl String { /// ``` #[unstable(feature = "splice", reason = "recently added", issue = "44643")] pub fn splice(&mut self, range: R, replace_with: &str) - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 280570ecd65..df08e46fe25 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -76,7 +76,7 @@ use core::mem; #[cfg(not(test))] use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{InPlace, Index, IndexMut, Place, Placer}; +use core::ops::{InPlace, Index, IndexMut, Place, Placer, RangeBounds}; use core::ops; use core::ptr; use core::ptr::NonNull; @@ -86,7 +86,6 @@ use borrow::ToOwned; use borrow::Cow; use boxed::Box; use raw_vec::RawVec; -use super::range::RangeArgument; use super::allocator::CollectionAllocErr; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. @@ -1176,7 +1175,7 @@ impl Vec { /// ``` #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // @@ -1950,7 +1949,7 @@ impl Vec { #[inline] #[stable(feature = "vec_splice", since = "1.21.0")] pub fn splice(&mut self, range: R, replace_with: I) -> Splice - where R: RangeArgument, I: IntoIterator + where R: RangeBounds, I: IntoIterator { Splice { drain: self.drain(range), diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 9efd730790d..94d042a45aa 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -22,7 +22,7 @@ use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, Place, Placer, InPlace}; +use core::ops::{Index, IndexMut, Place, Placer, InPlace, RangeBounds}; use core::ptr; use core::ptr::NonNull; use core::slice; @@ -33,7 +33,6 @@ use core::cmp; use raw_vec::RawVec; use super::allocator::CollectionAllocErr; -use super::range::RangeArgument; use super::vec::Vec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 @@ -969,7 +968,7 @@ impl VecDeque { #[inline] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index b0e75135282..0b480b618fc 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -192,7 +192,7 @@ pub use self::index::{Index, IndexMut}; pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] -pub use self::range::{RangeInclusive, RangeToInclusive, Bound}; +pub use self::range::{RangeInclusive, RangeToInclusive, RangeBounds, Bound}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index dd44aedd09f..b5aa81e36c4 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -452,8 +452,8 @@ impl> RangeToInclusive { /// ``` /// #![feature(collections_range)] /// -/// use std::collections::range::RangeArgument; /// use std::ops::Bound::*; +/// use std::ops::RangeBounds; /// /// assert_eq!((..100).start(), Unbounded); /// assert_eq!((1..12).start(), Included(&1)); @@ -493,3 +493,156 @@ pub enum Bound { #[stable(feature = "collections_bound", since = "1.17.0")] Unbounded, } + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +/// `RangeBounds` is implemented by Rust's built-in range types, produced +/// by range syntax like `..`, `a..`, `..b` or `c..d`. +pub trait RangeBounds { + /// Start index bound. + /// + /// Returns the start value as a `Bound`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections_range)] + /// + /// # fn main() { + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((..10).start(), Unbounded); + /// assert_eq!((3..10).start(), Included(&3)); + /// # } + /// ``` + fn start(&self) -> Bound<&T>; + + /// End index bound. + /// + /// Returns the end value as a `Bound`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections_range)] + /// + /// # fn main() { + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((3..).end(), Unbounded); + /// assert_eq!((3..10).end(), Excluded(&10)); + /// # } + /// ``` + fn end(&self) -> Bound<&T>; +} + +use self::Bound::{Excluded, Included, Unbounded}; + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeFull { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeFrom { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeTo { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Excluded(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for Range { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Excluded(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeInclusive { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Included(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeToInclusive { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Included(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for (Bound, Bound) { + fn start(&self) -> Bound<&T> { + match *self { + (Included(ref start), _) => Included(start), + (Excluded(ref start), _) => Excluded(start), + (Unbounded, _) => Unbounded, + } + } + + fn end(&self) -> Bound<&T> { + match *self { + (_, Included(ref end)) => Included(end), + (_, Excluded(ref end)) => Excluded(end), + (_, Unbounded) => Unbounded, + } + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { + fn start(&self) -> Bound<&T> { + self.0 + } + + fn end(&self) -> Bound<&T> { + self.1 + } +} diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index 52306de74cb..f50b8cadf15 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -15,11 +15,10 @@ //! //! The N above is determined by Array's implementor, by way of an associated constant. -use std::ops::{Deref, DerefMut}; +use std::ops::{Deref, DerefMut, RangeBounds}; use std::iter::{self, IntoIterator, FromIterator}; use std::slice; use std::vec; -use std::collections::range::RangeArgument; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; @@ -74,7 +73,7 @@ impl AccumulateVec { } pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { match *self { AccumulateVec::Array(ref mut v) => { diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index b40f2f92237..db1cfb5c767 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -18,9 +18,9 @@ use std::hash::{Hash, Hasher}; use std::slice; use std::fmt; use std::mem; -use std::collections::range::RangeArgument; use std::mem::ManuallyDrop; use std::ops::Bound::{Excluded, Included, Unbounded}; +use std::ops::RangeBounds; pub unsafe trait Array { type Element; @@ -106,7 +106,7 @@ impl ArrayVec { } pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index cbb3ff51715..1fb63afc72f 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::range::RangeArgument; use std::fmt::Debug; use std::iter::{self, FromIterator}; use std::slice; use std::marker::PhantomData; -use std::ops::{Index, IndexMut, Range}; +use std::ops::{Index, IndexMut, Range, RangeBounds}; use std::fmt; use std::vec; use std::u32; @@ -448,13 +447,13 @@ impl IndexVec { } #[inline] - pub fn drain<'a, R: RangeArgument>( + pub fn drain<'a, R: RangeBounds>( &'a mut self, range: R) -> impl Iterator + 'a { self.raw.drain(range) } #[inline] - pub fn drain_enumerated<'a, R: RangeArgument>( + pub fn drain_enumerated<'a, R: RangeBounds>( &'a mut self, range: R) -> impl Iterator + 'a { self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index e6f15a6119e..47ea3bc26bf 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -436,8 +436,12 @@ pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::range; +#[unstable(feature = "collections_range", issue = "30877")] +#[rustc_deprecated(reason = "renamed and moved to `std::ops::RangeBounds`", since = "1.26.0")] +/// Range syntax +pub mod range { + pub use ops::RangeBounds as RangeArgument; +} #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] pub use alloc::allocator::CollectionAllocErr; -- cgit 1.4.1-3-g733a5 From 8f9ec1cb06524a483b1bfc81c9912ebb7d46cb52 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 2 Apr 2018 00:14:44 +0300 Subject: avoid IdxSets containing garbage above the universe length This makes sure that all bits in each IdxSet between the universe length and the end of the word are all zero instead of being in an indeterminate state. This fixes a crash with RUST_LOG=rustc_mir, and is probably a good idea anyway. --- src/librustc_data_structures/indexed_set.rs | 74 ++++++++++++++++++++++++++++- src/librustc_mir/dataflow/impls/mod.rs | 4 +- 2 files changed, 75 insertions(+), 3 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 7ab6a269148..c9495587c46 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -121,7 +121,9 @@ impl IdxSetBuf { /// Creates set holding every element whose index falls in range 0..universe_size. pub fn new_filled(universe_size: usize) -> Self { - Self::new(!0, universe_size) + let mut result = Self::new(!0, universe_size); + result.trim_to(universe_size); + result } /// Creates set holding no elements. @@ -168,6 +170,36 @@ impl IdxSet { } } + /// Sets all elements up to `universe_size` + pub fn set_up_to(&mut self, universe_size: usize) { + for b in &mut self.bits { + *b = !0; + } + self.trim_to(universe_size); + } + + /// Clear all elements above `universe_size`. + fn trim_to(&mut self, universe_size: usize) { + let word_bits = mem::size_of::() * 8; + + // `trim_block` is the first block where some bits have + // to be cleared. + let trim_block = universe_size / word_bits; + + // all the blocks above it have to be completely cleared. + if trim_block < self.bits.len() { + for b in &mut self.bits[trim_block+1..] { + *b = 0; + } + + // at that block, the `universe_size % word_bits` lsbs + // should remain. + let remaining_bits = universe_size % word_bits; + let mask = (1< bool { self.bits.clear_bit(elem.index()) @@ -252,3 +284,43 @@ impl<'a, T: Idx> Iterator for Iter<'a, T> { } } } + +#[test] +fn test_trim_to() { + use std::cmp; + + for i in 0..256 { + let mut idx_buf: IdxSetBuf = IdxSetBuf::new_filled(128); + idx_buf.trim_to(i); + + let elems: Vec = idx_buf.iter().collect(); + let expected: Vec = (0..cmp::min(i, 128)).collect(); + assert_eq!(elems, expected); + } +} + +#[test] +fn test_set_up_to() { + for i in 0..128 { + for mut idx_buf in + vec![IdxSetBuf::new_empty(128), IdxSetBuf::new_filled(128)] + .into_iter() + { + idx_buf.set_up_to(i); + + let elems: Vec = idx_buf.iter().collect(); + let expected: Vec = (0..i).collect(); + assert_eq!(elems, expected); + } + } +} + +#[test] +fn test_new_filled() { + for i in 0..128 { + let mut idx_buf = IdxSetBuf::new_filled(i); + let elems: Vec = idx_buf.iter().collect(); + let expected: Vec = (0..i).collect(); + assert_eq!(elems, expected); + } +} diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index c5f5492cd2c..287640439c0 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -389,7 +389,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> // sets on_entry bits for Arg places fn start_block_effect(&self, entry_set: &mut IdxSet) { // set all bits to 1 (uninit) before gathering counterevidence - for e in entry_set.words_mut() { *e = !0; } + entry_set.set_up_to(self.bits_per_block()); drop_flag_effects_for_function_entry( self.tcx, self.mir, self.mdpe, @@ -443,7 +443,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tc // sets on_entry bits for Arg places fn start_block_effect(&self, entry_set: &mut IdxSet) { - for e in entry_set.words_mut() { *e = 0; } + entry_set.clear(); drop_flag_effects_for_function_entry( self.tcx, self.mir, self.mdpe, -- cgit 1.4.1-3-g733a5 From 5c58eec0bd8cee8fb2a191396d5ad5b5c9b0116a Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 4 Apr 2018 19:10:38 -0400 Subject: Replace manual iter exhaust with for_each(drop). --- src/liballoc/btree/map.rs | 3 +-- src/liballoc/linked_list.rs | 2 +- src/liballoc/vec.rs | 9 +++------ src/liballoc/vec_deque.rs | 2 +- src/librustc_data_structures/array_vec.rs | 4 ++-- src/libstd/collections/hash/table.rs | 2 +- 6 files changed, 9 insertions(+), 13 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index ed9c8c18f0d..37274a3c3ec 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1260,8 +1260,7 @@ impl IntoIterator for BTreeMap { #[stable(feature = "btree_drop", since = "1.7.0")] impl Drop for IntoIter { fn drop(&mut self) { - for _ in &mut *self { - } + self.for_each(drop); unsafe { let leaf_node = ptr::read(&self.front).into_node(); if let Some(first_parent) = leaf_node.deallocate_and_ascend() { diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 097d2e414f5..b633787fadf 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -1076,7 +1076,7 @@ impl<'a, T, F> Drop for DrainFilter<'a, T, F> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - for _ in self { } + self.for_each(drop); } } diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 2f57c53a6d8..635ffe08e9c 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2354,7 +2354,7 @@ impl<'a, T> DoubleEndedIterator for Drain<'a, T> { impl<'a, T> Drop for Drain<'a, T> { fn drop(&mut self) { // exhaust self first - while let Some(_) = self.next() {} + self.for_each(drop); if self.tail_len > 0 { unsafe { @@ -2474,9 +2474,7 @@ impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {} #[stable(feature = "vec_splice", since = "1.21.0")] impl<'a, I: Iterator> Drop for Splice<'a, I> { fn drop(&mut self) { - // exhaust drain first - while let Some(_) = self.drain.next() {} - + self.drain.by_ref().for_each(drop); unsafe { if self.drain.tail_len == 0 { @@ -2605,8 +2603,7 @@ impl<'a, T, F> Drop for DrainFilter<'a, T, F> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - for _ in self.by_ref() { } - + self.for_each(drop); unsafe { self.vec.set_len(self.old_len - self.del); } diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 68add3cbd51..ee9d8e796ab 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -2177,7 +2177,7 @@ unsafe impl<'a, T: Send> Send for Drain<'a, T> {} #[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { - for _ in self.by_ref() {} + self.for_each(drop); let source_deque = unsafe { self.deque.as_mut() }; diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 511c407d45a..34e19bba08b 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -207,7 +207,7 @@ pub struct Iter { impl Drop for Iter { fn drop(&mut self) { - for _ in self {} + self.for_each(drop); } } @@ -251,7 +251,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> { impl<'a, A: Array> Drop for Drain<'a, A> { fn drop(&mut self) { // exhaust self first - while let Some(_) = self.next() {} + self.for_each(drop); if self.tail_len > 0 { unsafe { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 73bd5747c10..4ed1e159a0a 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1129,7 +1129,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { fn drop(&mut self) { - for _ in self {} + self.for_each(drop); } } -- cgit 1.4.1-3-g733a5 From 8958815916201421b0a6648c68d7eb31bd3197ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 4 Apr 2018 07:16:25 -0700 Subject: Bump the bootstrap compiler to 1.26.0 beta Holy cow that's a lot of `cfg(stage0)` removed and a lot of new stable language features! --- src/bootstrap/lib.rs | 5 ++- src/bootstrap/tool.rs | 1 - src/liballoc/benches/lib.rs | 1 - src/liballoc/lib.rs | 3 +- src/liballoc/tests/lib.rs | 1 - src/libcore/cmp.rs | 5 ++- src/libcore/intrinsics.rs | 7 ---- src/libcore/lib.rs | 5 --- src/libcore/macros.rs | 65 ------------------------------------- src/libcore/panicking.rs | 3 +- src/libcore/tests/lib.rs | 3 -- src/libpanic_unwind/gcc.rs | 3 +- src/libpanic_unwind/lib.rs | 3 +- src/libpanic_unwind/seh64_gnu.rs | 3 +- src/libpanic_unwind/windows.rs | 9 ++--- src/libproc_macro/lib.rs | 1 - src/librustc/lib.rs | 7 ---- src/librustc_apfloat/lib.rs | 4 --- src/librustc_apfloat/tests/ieee.rs | 2 -- src/librustc_borrowck/lib.rs | 1 - src/librustc_const_math/lib.rs | 2 -- src/librustc_data_structures/lib.rs | 4 --- src/librustc_errors/lib.rs | 2 -- src/librustc_incremental/lib.rs | 3 -- src/librustc_lint/lib.rs | 2 -- src/librustc_metadata/lib.rs | 2 -- src/librustc_mir/lib.rs | 6 ---- src/librustc_traits/lib.rs | 2 -- src/librustc_trans/lib.rs | 4 --- src/librustc_trans_utils/lib.rs | 2 -- src/librustc_typeck/lib.rs | 6 ---- src/librustdoc/lib.rs | 1 - src/libserialize/lib.rs | 1 - src/libstd/lib.rs | 4 --- src/libstd/panicking.rs | 6 ++-- src/libsyntax/lib.rs | 2 -- src/libsyntax_pos/lib.rs | 1 - src/libunwind/libunwind.rs | 9 ++--- src/stage0.txt | 2 +- 39 files changed, 18 insertions(+), 175 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2eeb2691eae..6c46f3e58cf 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -114,8 +114,7 @@ //! also check out the `src/bootstrap/README.md` file for more information. #![deny(warnings)] -#![feature(conservative_impl_trait, fs_read_write, core_intrinsics)] -#![feature(slice_concat_ext)] +#![feature(core_intrinsics)] #[macro_use] extern crate build_helper; @@ -1149,7 +1148,7 @@ impl Build { fn read(&self, path: &Path) -> String { if self.config.dry_run { return String::new(); } - t!(fs::read_string(path)) + t!(fs::read_to_string(path)) } fn create_dir(&self, dir: &Path) { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 93b6153fcb2..5fc92611e65 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -12,7 +12,6 @@ use std::fs; use std::env; use std::path::PathBuf; use std::process::{Command, exit}; -use std::slice::SliceConcatExt; use Mode; use Compiler; diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index a43aadfe9a2..4d92fc67b2a 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(rand)] #![feature(repr_simd)] #![feature(slice_sort_by_cached_key)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 6ce2547ef6e..da26e7c852c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,8 +97,6 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] -#![cfg_attr(stage0, feature(generic_param_attrs))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(lang_items)] #![feature(needs_allocator)] #![feature(nonzero)] @@ -123,6 +121,7 @@ #![feature(exact_chunks)] #![feature(pointer_methods)] #![feature(inclusive_range_fields)] +#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))] #![cfg_attr(test, feature(test))] diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 1a49fb9964a..a173ef10a81 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -14,7 +14,6 @@ #![feature(alloc_system)] #![feature(attr_literals)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(const_fn)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 67445daa436..3ae9b05b865 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -427,7 +427,7 @@ impl Ord for Reverse { /// } /// } /// ``` -#[cfg_attr(not(stage0), lang = "ord")] +#[lang = "ord"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -597,8 +597,7 @@ impl PartialOrd for Ordering { /// assert_eq!(x < y, true); /// assert_eq!(x.lt(&y), true); /// ``` -#[cfg_attr(stage0, lang = "ord")] -#[cfg_attr(not(stage0), lang = "partial_ord")] +#[lang = "partial_ord"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 3b740adc468..83274682250 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1293,7 +1293,6 @@ extern "rust-intrinsic" { pub fn bswap(x: T) -> T; /// Reverses the bits in an integer type `T`. - #[cfg(not(stage0))] pub fn bitreverse(x: T) -> T; /// Performs checked integer addition. @@ -1316,7 +1315,6 @@ extern "rust-intrinsic" { /// Performs an exact division, resulting in undefined behavior where /// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - #[cfg(not(stage0))] pub fn exact_div(x: T, y: T) -> T; /// Performs an unchecked division, resulting in undefined behavior @@ -1401,8 +1399,3 @@ extern "rust-intrinsic" { /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); } - -#[cfg(stage0)] -pub unsafe fn exact_div(a: T, b: T) -> T { - unchecked_div(a, b) -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5a62b8438f9..cf9abb26d3e 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,8 +78,6 @@ #![feature(doc_spotlight)] #![feature(fn_must_use)] #![feature(fundamental)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] #![feature(iterator_repeat_with)] @@ -103,9 +101,6 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] -#![cfg_attr(stage0, allow(unused_attributes))] -#![cfg_attr(stage0, feature(never_type))] - #[prelude_import] #[allow(unused)] use prelude::v1::*; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 8a87bea71e2..90a9cb3379b 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -28,71 +28,6 @@ macro_rules! panic { }); } -/// Ensure that a boolean expression is `true` at runtime. -/// -/// This will invoke the [`panic!`] macro if the provided expression cannot be -/// evaluated to `true` at runtime. -/// -/// # Uses -/// -/// Assertions are always checked in both debug and release builds, and cannot -/// be disabled. See [`debug_assert!`] for assertions that are not enabled in -/// release builds by default. -/// -/// Unsafe code relies on `assert!` to enforce run-time invariants that, if -/// violated could lead to unsafety. -/// -/// Other use-cases of `assert!` include [testing] and enforcing run-time -/// invariants in safe code (whose violation cannot result in unsafety). -/// -/// # Custom Messages -/// -/// This macro has a second form, where a custom panic message can -/// be provided with or without arguments for formatting. See [`std::fmt`] -/// for syntax for this form. -/// -/// [`panic!`]: macro.panic.html -/// [`debug_assert!`]: macro.debug_assert.html -/// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro -/// [`std::fmt`]: ../std/fmt/index.html -/// -/// # Examples -/// -/// ``` -/// // the panic message for these assertions is the stringified value of the -/// // expression given. -/// assert!(true); -/// -/// fn some_computation() -> bool { true } // a very simple function -/// -/// assert!(some_computation()); -/// -/// // assert with a custom message -/// let x = true; -/// assert!(x, "x wasn't true!"); -/// -/// let a = 3; let b = 27; -/// assert!(a + b == 30, "a = {}, b = {}", a, b); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg(stage0)] -macro_rules! assert { - ($cond:expr) => ( - if !$cond { - panic!(concat!("assertion failed: ", stringify!($cond))) - } - ); - ($cond:expr,) => ( - assert!($cond) - ); - ($cond:expr, $($arg:tt)+) => ( - if !$cond { - panic!($($arg)+) - } - ); -} - /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// /// On panic, this macro will print the values of the expressions with their diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 94db0baa3f9..6b3dc75af46 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -64,8 +64,7 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; } let (file, line, col) = *file_line_col; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index de7211e718c..971759dcdd0 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,10 +23,7 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(iterator_step_by)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_flatten)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index ca2fd561cad..eb6dc5b5488 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -286,8 +286,7 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) // See docs in the `unwind` module. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] #[lang = "eh_unwind_resume"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception); } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a5cebc3e4d0..a5c227cb401 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -112,8 +112,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[no_mangle] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { imp::panic(mem::transmute(raw::TraitObject { data: data as *mut (), diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 090cd095380..c3715f96c64 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -108,8 +108,7 @@ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECO } #[lang = "eh_unwind_resume"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { let params = [panic_ctx as c::ULONG_PTR]; c::RaiseException(RUST_PANIC, diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs index 50fba5faee7..5f1dda36a88 100644 --- a/src/libpanic_unwind/windows.rs +++ b/src/libpanic_unwind/windows.rs @@ -79,21 +79,18 @@ pub enum EXCEPTION_DISPOSITION { pub use self::EXCEPTION_DISPOSITION::*; extern "system" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn RaiseException(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, lpArguments: *const ULONG_PTR); - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn RtlUnwindEx(TargetFrame: LPVOID, TargetIp: LPVOID, ExceptionRecord: *const EXCEPTION_RECORD, ReturnValue: LPVOID, OriginalContext: *const CONTEXT, HistoryTable: *const UNWIND_HISTORY_TABLE); - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8); } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 007093981d3..6b2b68b1faa 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -34,7 +34,6 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(lang_items)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index dcad8132c2b..7da664e6d02 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -43,19 +43,14 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] -#![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(dyn_trait)] #![feature(entry_or_default)] #![feature(from_ref)] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type, i128))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] @@ -68,8 +63,6 @@ #![feature(slice_patterns)] #![feature(specialization)] #![feature(unboxed_closures)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] -#![cfg_attr(stage0, feature(universal_impl_trait))] #![feature(trace_macros)] #![feature(trusted_len)] #![feature(catch_expr)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 6f08fcf7025..276f6cd09bf 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -46,10 +46,6 @@ #![deny(warnings)] #![forbid(unsafe_code)] -#![cfg_attr(stage0, feature(slice_patterns))] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(try_from))] - // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] extern crate rustc_cratesio_shim; diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index 627d79724b2..6e06ea858ef 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(stage0, feature(i128_type))] - #[macro_use] extern crate rustc_apfloat; diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index d54654c6086..6fe2ac2b0ca 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -16,7 +16,6 @@ #![allow(non_camel_case_types)] #![feature(from_ref)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(quote)] #[macro_use] extern crate log; diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 7177e2818fb..c4c5886d465 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -19,8 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![cfg_attr(stage0, feature(i128_type, i128))] - extern crate rustc_apfloat; extern crate syntax; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 622fb423b51..1e1628936d5 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,14 +26,10 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(specialization)] #![feature(optin_builtin_traits)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] #![feature(macro_vis_matcher)] #![feature(allow_internal_unstable)] -#![cfg_attr(stage0, feature(universal_impl_trait))] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 37ae64cef57..c283df6ec0f 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -17,8 +17,6 @@ #![allow(unused_attributes)] #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] extern crate atty; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index cad72ff778b..9e72ede309d 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -15,10 +15,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(specialization)] extern crate graphviz; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index d024adad9d0..c915181213d 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -27,11 +27,9 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(macro_vis_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate syntax; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 4af5ec9ae08..e89b5a7fc1b 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -14,9 +14,7 @@ #![deny(warnings)] #![feature(box_patterns)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(libc)] #![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 84baa8c5417..8762e7550cd 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -21,22 +21,16 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] #![feature(catch_expr)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] #![feature(dyn_trait)] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(macro_vis_matcher)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(nonzero)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] -#![cfg_attr(stage0, feature(never_type))] #![feature(inclusive_range_fields)] extern crate arena; diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 90f368edeec..cfa3b6912f2 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -14,8 +14,6 @@ #![deny(warnings)] #![feature(crate_visibility_modifier)] -#![cfg_attr(stage0, feature(match_default_bindings))] -#![cfg_attr(stage0, feature(underscore_lifetimes))] #[macro_use] extern crate log; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index e8a1eb3071a..2ce13a2627f 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,13 +24,9 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type, i128))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(slice_patterns))] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 99de124c6e1..cf47d9b62a9 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -21,10 +21,8 @@ #![feature(box_syntax)] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] extern crate ar; extern crate flate2; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 44ecb32a0bf..6f71db998bd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -72,22 +72,16 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] -#![cfg_attr(stage0, feature(advanced_slice_patterns))] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(crate_visibility_modifier)] #![feature(from_ref)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(exhaustive_patterns)] #![feature(option_filter)] #![feature(quote)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(never_type))] #![feature(dyn_trait)] #[macro_use] extern crate log; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e31390f59e2..42e87f88fd4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,6 @@ #![feature(box_syntax)] #![feature(fs_read_write)] #![feature(set_stdio)] -#![cfg_attr(stage0, feature(slice_patterns))] #![feature(test)] #![feature(unicode)] #![feature(vec_remove_item)] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index ee952523462..f78eed30694 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -23,7 +23,6 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(specialization)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3f1fec4c317..7da2eeefaaa 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -269,7 +269,6 @@ #![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(hashmap_internals)] #![feature(heap_api)] -#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] @@ -321,8 +320,6 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] -#![cfg_attr(stage0, feature(never_type))] -#![cfg_attr(stage0, feature(termination_trait))] #![default_lib_allocator] @@ -355,7 +352,6 @@ use prelude::v1::*; // add a new crate name so we can attach the re-exports to it. #[macro_reexport(assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, unreachable, unimplemented, write, writeln, try)] -#[cfg_attr(stage0, macro_reexport(assert))] extern crate core as __core; #[macro_use] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 454ac64735c..fba3269204e 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -55,8 +55,7 @@ extern { data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] fn __rust_start_panic(data: usize, vtable: usize) -> u32; } @@ -316,8 +315,7 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] #[lang = "panic_fmt"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index dc349c1a3e6..c456dc45d21 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -22,9 +22,7 @@ #![feature(unicode)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(non_exhaustive)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index eb345200f41..b6315900485 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,6 @@ #![feature(const_fn)] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index aa73b11fb38..a640a2b7775 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -83,8 +83,7 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; @@ -221,8 +220,7 @@ if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] { if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { // Not 32-bit iOS extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *mut c_void) @@ -231,8 +229,7 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { } else { // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } diff --git a/src/stage0.txt b/src/stage0.txt index 96ec1e6834d..e8db3358cf0 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-03-18 +date: 2018-04-04 rustc: beta cargo: beta -- cgit 1.4.1-3-g733a5 From c115cc655c8bb3077ff349e4ddd704a2239438a6 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 1 Apr 2018 09:35:53 -0600 Subject: Move deny(warnings) into rustbuild This permits easier iteration without having to worry about warnings being denied. Fixes #49517 --- config.toml.example | 3 +++ src/bootstrap/bin/rustc.rs | 4 ++++ src/bootstrap/builder.rs | 5 +++++ src/bootstrap/config.rs | 8 ++++++++ src/bootstrap/flags.rs | 6 ++++++ src/build_helper/lib.rs | 1 - src/liballoc/benches/lib.rs | 2 -- src/liballoc/lib.rs | 1 - src/liballoc/tests/lib.rs | 2 -- src/liballoc_jemalloc/lib.rs | 1 - src/liballoc_system/lib.rs | 1 - src/libarena/lib.rs | 1 - src/libcore/benches/lib.rs | 2 -- src/libcore/lib.rs | 1 - src/libcore/tests/lib.rs | 2 -- src/libfmt_macros/lib.rs | 1 - src/libgraphviz/lib.rs | 1 - src/libpanic_abort/lib.rs | 1 - src/libpanic_unwind/lib.rs | 1 - src/libproc_macro/lib.rs | 1 - src/librustc/benches/lib.rs | 2 -- src/librustc/lib.rs | 1 - src/librustc_allocator/lib.rs | 2 -- src/librustc_apfloat/lib.rs | 1 - src/librustc_back/lib.rs | 1 - src/librustc_borrowck/lib.rs | 1 - src/librustc_const_math/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/librustc_driver/lib.rs | 1 - src/librustc_errors/lib.rs | 1 - src/librustc_incremental/lib.rs | 1 - src/librustc_lint/lib.rs | 1 - src/librustc_llvm/lib.rs | 1 - src/librustc_metadata/lib.rs | 1 - src/librustc_mir/lib.rs | 2 -- src/librustc_passes/lib.rs | 1 - src/librustc_platform_intrinsics/lib.rs | 1 - src/librustc_plugin/lib.rs | 1 - src/librustc_privacy/lib.rs | 1 - src/librustc_resolve/lib.rs | 1 - src/librustc_save_analysis/lib.rs | 1 - src/librustc_traits/lib.rs | 2 -- src/librustc_trans/lib.rs | 1 - src/librustc_trans_utils/lib.rs | 1 - src/librustc_typeck/lib.rs | 1 - src/librustdoc/lib.rs | 1 - src/libserialize/lib.rs | 1 - src/libstd/lib.rs | 4 ---- src/libstd_unicode/lib.rs | 1 - src/libsyntax/lib.rs | 1 - src/libsyntax_ext/lib.rs | 1 - src/libsyntax_pos/lib.rs | 1 - src/libterm/lib.rs | 1 - src/libtest/lib.rs | 1 - src/libunwind/lib.rs | 1 - src/tools/tidy/src/lib.rs | 2 -- 56 files changed, 26 insertions(+), 63 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/config.toml.example b/config.toml.example index 9dd3002506e..68bc7dfe720 100644 --- a/config.toml.example +++ b/config.toml.example @@ -339,6 +339,9 @@ # rustc to execute. #lld = false +# Whether to deny warnings in crates +#deny-warnings = true + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 6701f58ba8e..3dd9b684059 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -279,6 +279,10 @@ fn main() { cmd.arg("--color=always"); } + if env::var_os("RUSTC_DENY_WARNINGS").is_some() { + cmd.arg("-Dwarnings"); + } + if verbose > 1 { eprintln!("rustc command: {:?}", cmd); eprintln!("sysroot: {:?}", sysroot); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 3f5ec4933d0..7ff64af9196 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -698,6 +698,11 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); + // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. + if self.config.deny_warnings && !(mode == Mode::Libstd && stage == 0) { + cargo.env("RUSTC_DENY_WARNINGS", "1"); + } + // Throughout the build Cargo can execute a number of build scripts // compiling C/C++ code and we need to pass compilers, archivers, flags, etc // obtained previously to those build scripts. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 95baf4f8cca..239316d45c4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -71,6 +71,8 @@ pub struct Config { pub incremental: bool, pub dry_run: bool, + pub deny_warnings: bool, + // llvm codegen options pub llvm_enabled: bool, pub llvm_assertions: bool, @@ -301,6 +303,7 @@ struct Rust { codegen_backends_dir: Option, wasm_syscall: Option, lld: Option, + deny_warnings: Option, } /// TOML representation of how each build target is configured. @@ -340,6 +343,7 @@ impl Config { config.test_miri = false; config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.rust_codegen_backends_dir = "codegen-backends".to_owned(); + config.deny_warnings = true; // set by bootstrap.py config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set"); @@ -366,6 +370,9 @@ impl Config { config.incremental = flags.incremental; config.dry_run = flags.dry_run; config.keep_stage = flags.keep_stage; + if let Some(value) = flags.warnings { + config.deny_warnings = value; + } if config.dry_run { let dir = config.out.join("tmp-dry-run"); @@ -511,6 +518,7 @@ impl Config { config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings)); if let Some(ref backends) = rust.codegen_backends { config.rust_codegen_backends = backends.iter() diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index ef902c68d12..3eb9dca2aa8 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -42,6 +42,9 @@ pub struct Flags { pub exclude: Vec, pub rustc_error_format: Option, pub dry_run: bool, + + // true => deny + pub warnings: Option, } pub enum Subcommand { @@ -118,6 +121,8 @@ To learn more about a subcommand, run `./x.py -h`"); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); + opts.optopt("", "warnings", "if value is deny, will deny warnings, otherwise use default", + "VALUE"); opts.optopt("", "error-format", "rustc error format", "FORMAT"); // fn usage() @@ -374,6 +379,7 @@ Arguments: incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) .into_iter().map(|p| p.into()).collect::>(), + warnings: matches.opt_str("warnings").map(|v| v == "deny"), } } } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 5a12afd03e1..e5c85ddb3a9 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] use std::fs::File; use std::path::{Path, PathBuf}; diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 4d92fc67b2a..4f69aa6670b 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(rand)] #![feature(repr_simd)] #![feature(slice_sort_by_cached_key)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index da26e7c852c..b08bd66b47c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -72,7 +72,6 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] #![needs_allocator] -#![deny(warnings)] #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index a173ef10a81..17f1d0464a5 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(allocator_api)] #![feature(alloc_system)] #![feature(attr_literals)] diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 7a8d01e4ef8..df7e3f61f5f 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,7 +14,6 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![deny(warnings)] #![feature(alloc_system)] #![feature(libc)] #![feature(linkage)] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index d4404e564e0..cdcb732f635 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![allow(unused_attributes)] -#![deny(warnings)] #![unstable(feature = "alloc_system", reason = "this library is unlikely to be stabilized in its current \ form or name", diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 7eaf67e6ea6..b319f333342 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -22,7 +22,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(no_crate_inject, attr(deny(warnings))))] -#![deny(warnings)] #![feature(alloc)] #![feature(core_intrinsics)] diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index c947b003ccb..ced77d77918 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(flt2dec)] #![feature(test)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index cf9abb26d3e..e194b173aa7 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -63,7 +63,6 @@ #![no_core] #![deny(missing_docs)] #![deny(missing_debug_implementations)] -#![deny(warnings)] #![feature(allow_internal_unstable)] #![feature(asm)] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 971759dcdd0..c3162899bbd 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(ascii_ctype)] #![feature(box_syntax)] #![feature(core_float)] diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 0f45f965104..a551b1b770a 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -19,7 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] -#![deny(warnings)] pub use self::Piece::*; pub use self::Position::*; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index d8c366d2413..158d0101515 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -287,7 +287,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![feature(str_escape)] diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 5f768ef4399..43c5bbbc618 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -19,7 +19,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![deny(warnings)] #![panic_runtime] #![allow(unused_features)] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a5c227cb401..9321d6917d1 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -28,7 +28,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![deny(warnings)] #![feature(alloc)] #![feature(core_intrinsics)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 6aa5572721d..dafdacfdd72 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -24,7 +24,6 @@ //! See [the book](../book/first-edition/procedural-macros.html) for more. #![stable(feature = "proc_macro_lib", since = "1.15.0")] -#![deny(warnings)] #![deny(missing_docs)] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", diff --git a/src/librustc/benches/lib.rs b/src/librustc/benches/lib.rs index 278e0f9a26e..5496df1342f 100644 --- a/src/librustc/benches/lib.rs +++ b/src/librustc/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(test)] extern crate test; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 7da664e6d02..b54699901fa 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -39,7 +39,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index e17fce5a2ec..0c7a9a91711 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(rustc_private)] extern crate rustc; diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 276f6cd09bf..0f051ea5981 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -43,7 +43,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![forbid(unsafe_code)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 9baee267709..027a9c45555 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -24,7 +24,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![feature(const_fn)] diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 6fe2ac2b0ca..52a357e1a1d 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![allow(non_camel_case_types)] diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index c4c5886d465..499c330be1d 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1e1628936d5..ba1d73dc268 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -19,7 +19,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(collections_range)] #![feature(nonzero)] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6f88b0aecb6..f6903d26e70 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index a723e455222..8d5f9ac93f0 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(custom_attribute)] #![allow(unused_attributes)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 9e72ede309d..a5e07bcec24 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -13,7 +13,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(fs_read_write)] #![feature(specialization)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c915181213d..16e8600f2d8 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -22,7 +22,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![cfg_attr(test, feature(test))] #![feature(box_patterns)] diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 16bee5b987e..bf8a087ab55 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -16,7 +16,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![feature(concat_idents)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index e89b5a7fc1b..f02a34c65a9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(fs_read_write)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 8762e7550cd..51256c4d96f 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,8 +14,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ -#![deny(warnings)] - #![feature(slice_patterns)] #![feature(from_ref)] #![feature(box_patterns)] diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 1f6cc1f71fc..e65c9de8df1 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 4cc65ee28e8..b57debdd994 100644 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] #![allow(bad_style)] pub struct Intrinsic { diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index c0f830f1fbe..622d8e51a6c 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -63,7 +63,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] #![feature(staged_api)] diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d951a7f1cc1..ef710ff7a7e 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2bf17cd1317..61ff326b2af 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4f46fb3545b..fefedd4e1c8 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(custom_attribute)] #![feature(macro_lifetime_matcher)] #![allow(unused_attributes)] diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index cfa3b6912f2..8136f6857a5 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -11,8 +11,6 @@ //! New recursive solver modeled on Chalk's recursive solver. Most of //! the guts are broken up into modules; see the comments in those modules. -#![deny(warnings)] - #![feature(crate_visibility_modifier)] #[macro_use] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 344f959c141..b9fa5b1353c 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index cf47d9b62a9..b297fd99865 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -15,7 +15,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 6f71db998bd..eb9a26855c6 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -68,7 +68,6 @@ This API is completely unstable and subject to change. #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![allow(non_camel_case_types)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 42e87f88fd4..730f61e0aa6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -12,7 +12,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] -#![deny(warnings)] #![feature(ascii_ctype)] #![feature(rustc_private)] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index f78eed30694..22d27b6697a 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -19,7 +19,6 @@ Core encoding and decoding interfaces. html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![feature(box_syntax)] #![feature(core_intrinsics)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3227aa9acff..672723341eb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -227,10 +227,6 @@ // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] -// Turn warnings into errors, but only after stage0, where it can be useful for -// code to emit warnings during language transitions -#![cfg_attr(not(stage0), deny(warnings))] - // std may use features in a platform-specific way #![allow(unused_features)] diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index c22ea1671fa..cf8c101a2f9 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -27,7 +27,6 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![deny(missing_debug_implementations)] #![no_std] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index c456dc45d21..b2976f71d49 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -18,7 +18,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![deny(warnings)] #![feature(unicode)] #![feature(rustc_diagnostic_macros)] diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 249a64b353f..97e34c554d1 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -13,7 +13,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(proc_macro_internals)] #![feature(decl_macro)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 33428eb271a..9a7d1fd8ee6 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(const_fn)] #![feature(custom_attribute)] diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index ad0e582b1c3..a012f4e776f 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -46,7 +46,6 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] #![deny(missing_docs)] -#![deny(warnings)] #![cfg_attr(windows, feature(libc))] // Handle rustfmt skips diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index b8be1aeff17..9291eaa910b 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -31,7 +31,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![deny(warnings)] #![feature(asm)] #![feature(fnbox)] #![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 5347c781218..2b3c19c067e 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] -#![deny(warnings)] #![feature(cfg_target_vendor)] #![feature(link_cfg)] diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 06eb055f68e..fa227436640 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -13,8 +13,6 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. -#![deny(warnings)] - extern crate serde; extern crate serde_json; #[macro_use] -- cgit 1.4.1-3-g733a5 From e5a602e364d5083a4c475747ad08c81ef29897bf Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Sun, 1 Apr 2018 09:43:19 +0200 Subject: Add OneThread which only allows its inner value to be used in one thread --- src/librustc_data_structures/sync.rs | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 0f534f0adec..ad524916f0c 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -33,6 +33,8 @@ use std::cmp::Ordering; use std::fmt::Debug; use std::fmt::Formatter; use std::fmt; +use std; +use std::ops::{Deref, DerefMut}; use owning_ref::{Erased, OwningRef}; cfg_if! { @@ -161,6 +163,8 @@ cfg_if! { use parking_lot::Mutex as InnerLock; use parking_lot::RwLock as InnerRwLock; + use std::thread; + pub type MetadataRef = OwningRef, [u8]>; /// This makes locks panic if they are already held. @@ -439,3 +443,54 @@ impl Clone for RwLock { RwLock::new(self.borrow().clone()) } } + +/// A type which only allows its inner value to be used in one thread. +/// It will panic if it is used on multiple threads. +#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)] +pub struct OneThread { + #[cfg(parallel_queries)] + thread: thread::ThreadId, + inner: T, +} + +unsafe impl std::marker::Sync for OneThread {} +unsafe impl std::marker::Send for OneThread {} + +impl OneThread { + #[inline(always)] + fn check(&self) { + #[cfg(parallel_queries)] + assert_eq!(thread::current().id(), self.thread); + } + + #[inline(always)] + pub fn new(inner: T) -> Self { + OneThread { + #[cfg(parallel_queries)] + thread: thread::current().id(), + inner, + } + } + + #[inline(always)] + pub fn into_inner(value: Self) -> T { + value.check(); + value.inner + } +} + +impl Deref for OneThread { + type Target = T; + + fn deref(&self) -> &T { + self.check(); + &self.inner + } +} + +impl DerefMut for OneThread { + fn deref_mut(&mut self) -> &mut T { + self.check(); + &mut self.inner + } +} -- cgit 1.4.1-3-g733a5 From 60d0cbe532eba39dba75d84b1eb98abf7cd12a48 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Sun, 1 Apr 2018 10:25:16 +0200 Subject: Add insert_same extension to HashMap --- src/librustc_data_structures/sync.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index ad524916f0c..19039b9b0b0 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -29,6 +29,8 @@ //! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync //! depending on the value of cfg!(parallel_queries). +use std::collections::HashMap; +use std::hash::{Hash, BuildHasher}; use std::cmp::Ordering; use std::fmt::Debug; use std::fmt::Formatter; @@ -227,6 +229,18 @@ pub fn assert_sync() {} pub fn assert_send_val(_t: &T) {} pub fn assert_send_sync_val(_t: &T) {} +pub trait HashMapExt { + /// Same as HashMap::insert, but it may panic if there's already an + /// entry for `key` with a value not equal to `value` + fn insert_same(&mut self, key: K, value: V); +} + +impl HashMapExt for HashMap { + fn insert_same(&mut self, key: K, value: V) { + self.entry(key).and_modify(|old| assert!(*old == value)).or_insert(value); + } +} + impl Debug for LockCell { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("LockCell") -- cgit 1.4.1-3-g733a5 From 26f16e85ffcc3ebcaf12029865dee257760901b5 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Sun, 1 Apr 2018 12:14:19 +0200 Subject: Add a Once type for values which are only written once --- src/librustc_data_structures/sync.rs | 129 +++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 19039b9b0b0..3b7d6efbdae 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -32,6 +32,7 @@ use std::collections::HashMap; use std::hash::{Hash, BuildHasher}; use std::cmp::Ordering; +use std::marker::PhantomData; use std::fmt::Debug; use std::fmt::Formatter; use std::fmt; @@ -241,6 +242,134 @@ impl HashMapExt for HashMap } } +/// A type whose inner value can be written once and then will stay read-only +// This contains a PhantomData since this type conceptually owns a T outside the Mutex once +// initialized. This ensures that Once is Sync only if T is. If we did not have PhantomData +// we could send a &Once> to multiple threads and call `get` on it to get access +// to &Cell on those threads. +pub struct Once(Lock>, PhantomData); + +impl Once { + /// Creates an Once value which is uninitialized + #[inline(always)] + pub fn new() -> Self { + Once(Lock::new(None), PhantomData) + } + + /// Consumes the value and returns Some(T) if it was initialized + #[inline(always)] + pub fn into_inner(self) -> Option { + self.0.into_inner() + } + + /// Tries to initialize the inner value to `value`. + /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it + /// otherwise if the inner value was already set it returns `value` back to the caller + #[inline] + pub fn try_set(&self, value: T) -> Option { + let mut lock = self.0.lock(); + if lock.is_some() { + return Some(value); + } + *lock = Some(value); + None + } + + /// Tries to initialize the inner value to `value`. + /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it + /// otherwise if the inner value was already set it asserts that `value` is equal to the inner + /// value and then returns `value` back to the caller + #[inline] + pub fn try_set_same(&self, value: T) -> Option where T: Eq { + let mut lock = self.0.lock(); + if let Some(ref inner) = *lock { + assert!(*inner == value); + return Some(value); + } + *lock = Some(value); + None + } + + /// Tries to initialize the inner value to `value` and panics if it was already initialized + #[inline] + pub fn set(&self, value: T) { + assert!(self.try_set(value).is_none()); + } + + /// Tries to initialize the inner value by calling the closure while ensuring that no-one else + /// can access the value in the mean time by holding a lock for the duration of the closure. + /// If the value was already initialized the closure is not called and `false` is returned, + /// otherwise if the value from the closure initializes the inner value, `true` is returned + #[inline] + pub fn init_locking T>(&self, f: F) -> bool { + let mut lock = self.0.lock(); + if lock.is_some() { + return false; + } + *lock = Some(f()); + true + } + + /// Tries to initialize the inner value by calling the closure without ensuring that no-one + /// else can access it. This mean when this is called from multiple threads, multiple + /// closures may concurrently be computing a value which the inner value should take. + /// Only one of these closures are used to actually initialize the value. + /// If some other closure already set the value, + /// we return the value our closure computed wrapped in a `Option`. + /// If our closure set the value, `None` is returned. + /// If the value is already initialized, the closure is not called and `None` is returned. + #[inline] + pub fn init_nonlocking T>(&self, f: F) -> Option { + if self.0.lock().is_some() { + None + } else { + self.try_set(f()) + } + } + + /// Tries to initialize the inner value by calling the closure without ensuring that no-one + /// else can access it. This mean when this is called from multiple threads, multiple + /// closures may concurrently be computing a value which the inner value should take. + /// Only one of these closures are used to actually initialize the value. + /// If some other closure already set the value, we assert that it our closure computed + /// a value equal to the value aready set and then + /// we return the value our closure computed wrapped in a `Option`. + /// If our closure set the value, `None` is returned. + /// If the value is already initialized, the closure is not called and `None` is returned. + #[inline] + pub fn init_nonlocking_same T>(&self, f: F) -> Option where T: Eq { + if self.0.lock().is_some() { + None + } else { + self.try_set_same(f()) + } + } + + /// Tries to get a reference to the inner value, returns `None` if it is not yet initialized + #[inline(always)] + pub fn try_get(&self) -> Option<&T> { + let lock = &*self.0.lock(); + if let Some(ref inner) = *lock { + // This is safe since we won't mutate the inner value + unsafe { Some(&*(inner as *const T)) } + } else { + None + } + } + + /// Gets reference to the inner value, panics if it is not yet initialized + #[inline(always)] + pub fn get(&self) -> &T { + self.try_get().expect("value was not set") + } + + /// Gets reference to the inner value, panics if it is not yet initialized + #[inline(always)] + pub fn borrow(&self) -> &T { + self.get() + } +} + impl Debug for LockCell { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("LockCell") -- cgit 1.4.1-3-g733a5 From 259ae181391933040389e7e4206e792ad66b1487 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 24 Apr 2018 13:22:41 +1000 Subject: Implement LazyBTreeMap and use it in a few places. This is a thin wrapper around BTreeMap that avoids allocating upon creation. It speeds up some rustc-perf benchmarks by up to 3.6%. --- src/librustc/infer/higher_ranked/mod.rs | 12 +-- src/librustc/infer/mod.rs | 6 +- src/librustc/ty/fold.rs | 8 +- src/librustc_data_structures/lazy_btree_map.rs | 108 +++++++++++++++++++++++++ src/librustc_data_structures/lib.rs | 1 + 5 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 src/librustc_data_structures/lazy_btree_map.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index d44f2ec9549..a8555a3458f 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -19,7 +19,7 @@ use super::{CombinedSnapshot, use super::combine::CombineFields; use super::region_constraints::{TaintDirections}; -use std::collections::BTreeMap; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use ty::{self, TyCtxt, Binder, TypeFoldable}; use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; @@ -247,7 +247,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &BTreeMap>, + a_map: &LazyBTreeMap>, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { // Regions that pre-dated the LUB computation stay as they are. @@ -343,7 +344,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &BTreeMap>, + a_map: &LazyBTreeMap>, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], r0: ty::Region<'tcx>) @@ -412,7 +414,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - a_map: &BTreeMap>, + a_map: &LazyBTreeMap>, r: ty::Region<'tcx>) -> ty::Region<'tcx> { for (a_br, a_r) in a_map { @@ -435,7 +437,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &BTreeMap>) + map: &LazyBTreeMap>) -> Vec { map.iter() .map(|(_, &r)| match *r { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 40cc43c3ca6..553926dba8f 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -28,9 +28,9 @@ use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::TypeFoldable; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations}; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref, RefMut}; -use std::collections::BTreeMap; use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; @@ -187,7 +187,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap<'tcx> = BTreeMap>; +pub type SkolemizationMap<'tcx> = LazyBTreeMap>; /// See `error_reporting` module for more details #[derive(Clone, Debug)] @@ -1216,7 +1216,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder) - -> (T, BTreeMap>) + -> (T, LazyBTreeMap>) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 8071cd0c639..80bdc4f89df 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -43,8 +43,8 @@ use middle::const_val::ConstVal; use hir::def_id::DefId; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use std::fmt; -use std::collections::BTreeMap; use util::nodemap::FxHashSet; /// The TypeFoldable trait is implemented for every type that can be folded. @@ -334,7 +334,7 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, current_depth: u32, fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), - map: BTreeMap> + map: LazyBTreeMap> } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -349,7 +349,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions(self, value: &Binder, mut f: F) - -> (T, BTreeMap>) + -> (T, LazyBTreeMap>) where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T : TypeFoldable<'tcx>, { @@ -462,7 +462,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { tcx, current_depth: 1, fld_r, - map: BTreeMap::default() + map: LazyBTreeMap::default() } } } diff --git a/src/librustc_data_structures/lazy_btree_map.rs b/src/librustc_data_structures/lazy_btree_map.rs new file mode 100644 index 00000000000..74f91af10fe --- /dev/null +++ b/src/librustc_data_structures/lazy_btree_map.rs @@ -0,0 +1,108 @@ +// Copyright 2018 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. + +use std::collections::btree_map; +use std::collections::BTreeMap; + +/// A thin wrapper around BTreeMap that avoids allocating upon creation. +/// +/// Vec, HashSet and HashMap all have the nice feature that they don't do any +/// heap allocation when creating a new structure of the default size. In +/// contrast, BTreeMap *does* allocate in that situation. The compiler uses +/// B-Tree maps in some places such that many maps are created but few are +/// inserted into, so having a BTreeMap alternative that avoids allocating on +/// creation is a performance win. +/// +/// Only a fraction of BTreeMap's functionality is currently supported. +/// Additional functionality should be added on demand. +#[derive(Debug)] +pub struct LazyBTreeMap(Option>); + +impl LazyBTreeMap { + pub fn new() -> LazyBTreeMap { + LazyBTreeMap(None) + } + + pub fn iter(&self) -> Iter { + Iter(self.0.as_ref().map(|btm| btm.iter())) + } + + pub fn is_empty(&self) -> bool { + self.0.as_ref().map_or(true, |btm| btm.is_empty()) + } +} + +impl LazyBTreeMap { + fn instantiate(&mut self) -> &mut BTreeMap { + if let Some(ref mut btm) = self.0 { + btm + } else { + let btm = BTreeMap::new(); + self.0 = Some(btm); + self.0.as_mut().unwrap() + } + } + + pub fn insert(&mut self, key: K, value: V) -> Option { + self.instantiate().insert(key, value) + } + + pub fn entry(&mut self, key: K) -> btree_map::Entry { + self.instantiate().entry(key) + } + + pub fn values<'a>(&'a self) -> Values<'a, K, V> { + Values(self.0.as_ref().map(|btm| btm.values())) + } +} + +impl Default for LazyBTreeMap { + fn default() -> LazyBTreeMap { + LazyBTreeMap::new() + } +} + +impl<'a, K: 'a, V: 'a> IntoIterator for &'a LazyBTreeMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +pub struct Iter<'a, K: 'a, V: 'a>(Option>); + +impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + fn next(&mut self) -> Option<(&'a K, &'a V)> { + self.0.as_mut().and_then(|iter| iter.next()) + } + + fn size_hint(&self) -> (usize, Option) { + self.0.as_ref().map_or_else(|| (0, Some(0)), |iter| iter.size_hint()) + } +} + +pub struct Values<'a, K: 'a, V: 'a>(Option>); + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + fn next(&mut self) -> Option<&'a V> { + self.0.as_mut().and_then(|values| values.next()) + } + + fn size_hint(&self) -> (usize, Option) { + self.0.as_ref().map_or_else(|| (0, Some(0)), |values| values.size_hint()) + } +} + diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ba1d73dc268..154c086614c 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -56,6 +56,7 @@ pub mod bitvec; pub mod graph; pub mod indexed_set; pub mod indexed_vec; +pub mod lazy_btree_map; pub mod obligation_forest; pub mod sip128; pub mod snapshot_map; -- cgit 1.4.1-3-g733a5 From 04fa0e7bb3e462080be4a6cee45fd94b1c27d287 Mon Sep 17 00:00:00 2001 From: Irina Popa Date: Wed, 25 Apr 2018 19:30:39 +0300 Subject: rustc_target: move in syntax::abi and flip dependency. --- src/Cargo.lock | 11 +- src/librustc/hir/intravisit.rs | 2 +- src/librustc/hir/map/blocks.rs | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/hir/mod.rs | 2 +- src/librustc/hir/print.rs | 2 +- src/librustc/ich/impls_syntax.rs | 2 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/traits/error_reporting.rs | 4 +- src/librustc/traits/select.rs | 2 +- src/librustc/ty/context.rs | 2 +- src/librustc/ty/error.rs | 2 +- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/relate.rs | 2 +- src/librustc/ty/structural_impls.rs | 2 +- src/librustc/ty/sty.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_allocator/Cargo.toml | 1 + src/librustc_allocator/expand.rs | 2 +- src/librustc_allocator/lib.rs | 1 + src/librustc_cratesio_shim/Cargo.toml | 1 + src/librustc_cratesio_shim/src/lib.rs | 1 + src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/lib.rs | 4 + src/librustc_driver/test.rs | 2 +- src/librustc_lint/Cargo.toml | 1 + src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/lib.rs | 1 + src/librustc_lint/types.rs | 2 +- src/librustc_metadata/link_args.rs | 2 +- src/librustc_metadata/native_libs.rs | 2 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/interpret/terminator/mod.rs | 2 +- src/librustc_mir/monomorphize/item.rs | 2 +- src/librustc_mir/shim.rs | 2 +- src/librustc_mir/transform/inline.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/transform/rustc_peek.rs | 2 +- src/librustc_save_analysis/Cargo.toml | 1 + src/librustc_save_analysis/lib.rs | 1 + src/librustc_save_analysis/sig.rs | 6 +- src/librustc_target/Cargo.toml | 2 +- src/librustc_target/abi/call/mod.rs | 8 +- src/librustc_target/lib.rs | 5 +- src/librustc_target/spec/abi.rs | 136 +++++++++++++++++++++++++ src/librustc_target/spec/arm_base.rs | 2 +- src/librustc_target/spec/mod.rs | 3 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/common.rs | 2 +- src/librustc_typeck/Cargo.toml | 1 + src/librustc_typeck/astconv.rs | 3 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 3 +- src/librustc_typeck/lib.rs | 3 +- src/librustc_typeck/outlives/implicit_infer.rs | 3 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/doctree.rs | 2 +- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/render.rs | 3 +- src/librustdoc/lib.rs | 1 + src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/Cargo.toml | 2 +- src/libsyntax/abi.rs | 136 ------------------------- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/lib.rs | 6 +- src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/test.rs | 2 +- src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/Cargo.toml | 3 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- src/libsyntax_ext/lib.rs | 1 + 81 files changed, 242 insertions(+), 213 deletions(-) create mode 100644 src/librustc_target/spec/abi.rs delete mode 100644 src/libsyntax/abi.rs (limited to 'src/librustc_data_structures') diff --git a/src/Cargo.lock b/src/Cargo.lock index 878212d4ee4..e14b9da9713 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1833,6 +1833,7 @@ version = "0.0.0" dependencies = [ "rustc 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -1885,6 +1886,7 @@ name = "rustc_cratesio_shim" version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1896,6 +1898,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1966,6 +1969,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_mir 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2106,6 +2110,7 @@ dependencies = [ "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", + "rustc_target 0.0.0", "rustc_typeck 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -2117,8 +2122,8 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", - "syntax 0.0.0", ] [[package]] @@ -2204,6 +2209,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_platform_intrinsics 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2542,9 +2548,9 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_cratesio_shim 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax_pos 0.0.0", @@ -2558,6 +2564,7 @@ dependencies = [ "proc_macro 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index be9f8b8dac5..62f3f9f4486 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -41,7 +41,7 @@ //! This order consistency is required in a few places in rustc, for //! example generator inference, and possibly also HIR borrowck. -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax_pos::Span; use hir::*; diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 1eaacdb1d7f..362c0bf07f7 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -25,7 +25,7 @@ use hir as ast; use hir::map::{self, Node}; use hir::{Expr, FnDecl}; use hir::intravisit::FnKind; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast::{Attribute, Name, NodeId}; use syntax_pos::Span; diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 9520ed32af9..a9613a60a57 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -21,7 +21,7 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; use middle::cstore::CrateStore; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID}; use syntax::codemap::Spanned; use syntax::ext::base::MacroKind; diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f471ffb072d..0dc89d64bd5 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -34,7 +34,7 @@ use mir::mono::Linkage; use syntax_pos::{Span, DUMMY_SP}; use syntax::codemap::{self, Spanned}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; use syntax::attr::InlineAttr; diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index d3f2458ef87..3943c30127d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -10,7 +10,7 @@ pub use self::AnnNode::*; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::codemap::{CodeMap, Spanned}; use syntax::parse::{token, ParseSess}; diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 4ac678aaa05..d7e16ab3620 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -82,7 +82,7 @@ impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { }); -impl_stable_hash_for!(enum ::syntax::abi::Abi { +impl_stable_hash_for!(enum ::rustc_target::spec::abi::Abi { Cdecl, Stdcall, Fastcall, diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 0a4e5094cde..27f7dbf508d 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -13,7 +13,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use ty::layout::{LayoutError, Pointer, SizeSkeleton}; -use syntax::abi::Abi::RustIntrinsic; +use rustc_target::spec::abi::Abi::RustIntrinsic; use syntax_pos::Span; use hir::intravisit::{self, Visitor, NestedVisitorMap}; use hir; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 48a62c8c14d..0aeb15b49fb 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -26,7 +26,7 @@ use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr; use hir; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a7669b942e3..33abc0c7e15 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1091,7 +1091,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, - ::syntax::abi::Abi::Rust + ::rustc_target::spec::abi::Abi::Rust ) } else { tcx.mk_fn_sig( @@ -1099,7 +1099,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, - ::syntax::abi::Abi::Rust + ::rustc_target::spec::abi::Abi::Rust ) }; format!("{}", ty::Binder::bind(sig)) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index cfc14b7bfe4..f43f5cf3e3f 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -51,7 +51,7 @@ use std::cmp; use std::fmt; use std::mem; use std::rc::Rc; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use hir; use util::nodemap::{FxHashMap, FxHashSet}; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a5df068dee2..b9e8cd454a0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -70,7 +70,7 @@ use std::ops::Deref; use std::iter; use std::sync::mpsc; use std::sync::Arc; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast::{self, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index eb392418647..cf2004a681e 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use ty::{self, BoundRegion, Region, Ty, TyCtxt}; use std::fmt; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::Span; diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 02a03bc542a..ecd415c4bc4 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -12,7 +12,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; use ty::subst::Kind; use traits; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use util::ppaux; use std::fmt; diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 348cf03dd87..03ed6e7ac90 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -22,7 +22,7 @@ use mir::interpret::{GlobalId, Value, PrimVal}; use util::common::ErrorReported; use std::rc::Rc; use std::iter; -use syntax::abi; +use rustc_target::spec::abi; use hir as ast; use rustc_data_structures::accumulate_vec::AccumulateVec; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 199a46678c8..9b20fce6673 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -44,7 +44,7 @@ CloneTypeFoldableAndLiftImpls! { ::hir::MatchSource, ::hir::Mutability, ::hir::Unsafety, - ::syntax::abi::Abi, + ::rustc_target::spec::abi::Abi, ::mir::Local, ::mir::Promoted, ::traits::Reveal, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 92e879a584b..0dfae13cc75 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -22,7 +22,7 @@ use util::captures::Captures; use std::iter; use std::cmp::Ordering; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast::{self, Name}; use syntax::symbol::{keywords, InternedString}; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index efe83252d0f..905776373bd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -28,7 +28,7 @@ use std::fmt; use std::usize; use rustc_data_structures::indexed_vec::Idx; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::CRATE_NODE_ID; use syntax::symbol::{Symbol, InternedString}; use hir; diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml index e3d1d8e32c4..765cb80f357 100644 --- a/src/librustc_allocator/Cargo.toml +++ b/src/librustc_allocator/Cargo.toml @@ -11,5 +11,6 @@ test = false [dependencies] rustc = { path = "../librustc" } rustc_errors = { path = "../librustc_errors" } +rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 9338d000c12..de8814d3d6a 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -10,7 +10,7 @@ use rustc::middle::allocator::AllocatorKind; use rustc_errors; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{Attribute, Crate, LitKind, StrStyle}; use syntax::ast::{Arg, Constness, Generics, Mac, Mutability, Ty, Unsafety}; use syntax::ast::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind}; diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 969086815de..6595564fb30 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -12,6 +12,7 @@ extern crate rustc; extern crate rustc_errors; +extern crate rustc_target; extern crate syntax; extern crate syntax_pos; diff --git a/src/librustc_cratesio_shim/Cargo.toml b/src/librustc_cratesio_shim/Cargo.toml index 143f88e8f4b..342c7d1b678 100644 --- a/src/librustc_cratesio_shim/Cargo.toml +++ b/src/librustc_cratesio_shim/Cargo.toml @@ -21,3 +21,4 @@ crate-type = ["dylib"] [dependencies] bitflags = "1.0" +log = "0.4" diff --git a/src/librustc_cratesio_shim/src/lib.rs b/src/librustc_cratesio_shim/src/lib.rs index 769b4f57206..85a5b331d8c 100644 --- a/src/librustc_cratesio_shim/src/lib.rs +++ b/src/librustc_cratesio_shim/src/lib.rs @@ -12,3 +12,4 @@ #![allow(unused_extern_crates)] extern crate bitflags; +extern crate log; diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e1f0a74fc68..9178d0d00fa 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["dylib"] [dependencies] ena = "0.9.1" log = "0.4" +rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } serialize = { path = "../libserialize" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ba1d73dc268..1320fe75bc5 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -45,6 +45,10 @@ extern crate parking_lot; extern crate cfg_if; extern crate stable_deref_trait; +// See librustc_cratesio_shim/Cargo.toml for a comment explaining this. +#[allow(unused_extern_crates)] +extern crate rustc_cratesio_shim; + pub use rustc_serialize::hex::ToHex; pub mod array_vec; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 83501f45ec0..47c49fbe9ef 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -31,7 +31,7 @@ use rustc::session::config::{OutputFilenames, OutputTypes}; use rustc_data_structures::sync::{self, Lrc}; use syntax; use syntax::ast; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::codemap::{CodeMap, FilePathMapping, FileName}; use errors; use errors::emitter::Emitter; diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 5ff891202db..f097095abe4 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -13,5 +13,6 @@ test = false log = "0.4" rustc = { path = "../librustc" } rustc_mir = { path = "../librustc_mir"} +rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 463ec4796e8..651a2e187f6 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -13,7 +13,7 @@ use rustc::ty; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr; use syntax_pos::Span; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 76991e3e52d..91ce6f3854a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1169,7 +1169,7 @@ impl LintPass for MutableTransmutes { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { - use syntax::abi::Abi::RustIntrinsic; + use rustc_target::spec::abi::Abi::RustIntrinsic; let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ consider instead using an UnsafeCell"; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 889c7d3e34e..65b340d6568 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -37,6 +37,7 @@ extern crate rustc; #[macro_use] extern crate log; extern crate rustc_mir; +extern crate rustc_target; extern crate syntax_pos; use rustc::lint; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 4d2bddd531e..904a3e4c427 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -22,7 +22,7 @@ use std::cmp; use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; use syntax::{ast, attr}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax_pos::Span; use syntax::codemap; diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 6fafde0d09c..b699885b0eb 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -11,7 +11,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; use rustc::ty::TyCtxt; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { let mut collector = Collector { diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 4bb6d8fb87c..70b8c7b11fd 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -14,7 +14,7 @@ use rustc::middle::cstore::{self, NativeLibrary}; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::util::nodemap::FxHashSet; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::codemap::Span; use syntax::feature_gate::{self, GateIssue}; diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 28dc329e4fe..c130b4f550f 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -16,7 +16,7 @@ use hair::*; use rustc::ty; use rustc::mir::*; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr`, storing the result into `destination`, which diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 1dcf1e80041..0d836f5cb97 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -25,7 +25,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use shim; use std::mem; use std::u32; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr::{self, UnwindAttr}; use syntax::symbol::keywords; diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 3360e5b72a7..aa80ee7af18 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -2,7 +2,7 @@ use rustc::mir; use rustc::ty::{self, Ty}; use rustc::ty::layout::LayoutOf; use syntax::codemap::Span; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use rustc::mir::interpret::{EvalResult, PrimVal, Value}; use super::{EvalContext, Place, Machine, ValTy}; diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 181751f1777..9e0c977a3f0 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -339,7 +339,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { } let abi = sig.abi(); - if abi != ::syntax::abi::Abi::Rust { + if abi != ::rustc_target::spec::abi::Abi::Rust { output.push_str("extern \""); output.push_str(abi.name()); output.push_str("\" "); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 6a0f42c6dbb..af60a83a4a2 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -20,7 +20,7 @@ use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax_pos::Span; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 2dd805ccf9b..2b491385d66 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -28,7 +28,7 @@ use transform::{MirPass, MirSource}; use super::simplify::{remove_dead_blocks, CfgSimplifier}; use syntax::{attr}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; const DEFAULT_THRESHOLD: usize = 50; const HINT_THRESHOLD: usize = 100; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 591732fbba9..ff7551ed6f4 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -29,7 +29,7 @@ use rustc::mir::*; use rustc::mir::traversal::ReversePostorder; use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::middle::lang_items; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::ast::LitKind; use syntax::feature_gate::UnstableFeatures; diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 45e7a0d3f4c..8f67b9e7c3d 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::abi::{Abi}; +use rustc_target::spec::abi::{Abi}; use syntax::ast; use syntax_pos::Span; diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 005faa55b58..976614c9542 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["dylib"] log = "0.4" rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_target = { path = "../librustc_target" } rustc_typeck = { path = "../librustc_typeck" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 6a747decbd3..401a280412a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -22,6 +22,7 @@ extern crate rustc; extern crate log; extern crate rustc_data_structures; extern crate rustc_serialize; +extern crate rustc_target; extern crate rustc_typeck; #[macro_use] extern crate syntax; diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index a9df898efb6..829ed320d75 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -237,7 +237,7 @@ impl Sig for ast::Ty { if f.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if f.abi != ::syntax::abi::Abi::Rust { + if f.abi != ::rustc_target::spec::abi::Abi::Rust { text.push_str("extern"); text.push_str(&f.abi.to_string()); text.push(' '); @@ -388,7 +388,7 @@ impl Sig for ast::Item { if unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if abi != ::syntax::abi::Abi::Rust { + if abi != ::rustc_target::spec::abi::Abi::Rust { text.push_str("extern"); text.push_str(&abi.to_string()); text.push(' '); @@ -931,7 +931,7 @@ fn make_method_signature( if m.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if m.abi != ::syntax::abi::Abi::Rust { + if m.abi != ::rustc_target::spec::abi::Abi::Rust { text.push_str("extern"); text.push_str(&m.abi.to_string()); text.push(' '); diff --git a/src/librustc_target/Cargo.toml b/src/librustc_target/Cargo.toml index 4064cb17f01..bb686e914a0 100644 --- a/src/librustc_target/Cargo.toml +++ b/src/librustc_target/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] bitflags = "1.0" log = "0.4" -syntax = { path = "../libsyntax" } +rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } serialize = { path = "../libserialize" } [features] diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 3fad7926e1f..34f28301e54 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -458,22 +458,22 @@ pub struct FnType<'a, Ty> { } impl<'a, Ty> FnType<'a, Ty> { - pub fn adjust_for_cabi(&mut self, cx: C, abi: ::syntax::abi::Abi) -> Result<(), String> + pub fn adjust_for_cabi(&mut self, cx: C, abi: ::spec::abi::Abi) -> Result<(), String> where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf> + HasDataLayout + HasTargetSpec { match &cx.target_spec().arch[..] { "x86" => { - let flavor = if abi == ::syntax::abi::Abi::Fastcall { + let flavor = if abi == ::spec::abi::Abi::Fastcall { x86::Flavor::Fastcall } else { x86::Flavor::General }; x86::compute_abi_info(cx, self, flavor); }, - "x86_64" => if abi == ::syntax::abi::Abi::SysV64 { + "x86_64" => if abi == ::spec::abi::Abi::SysV64 { x86_64::compute_abi_info(cx, self); - } else if abi == ::syntax::abi::Abi::Win64 || cx.target_spec().options.is_like_windows { + } else if abi == ::spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows { x86_win64::compute_abi_info(self); } else { x86_64::compute_abi_info(cx, self); diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index c2418a3b2a7..8f491157439 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -33,11 +33,14 @@ #[macro_use] extern crate bitflags; -extern crate syntax; extern crate serialize; #[macro_use] extern crate log; extern crate serialize as rustc_serialize; // used by deriving +// See librustc_cratesio_shim/Cargo.toml for a comment explaining this. +#[allow(unused_extern_crates)] +extern crate rustc_cratesio_shim; + pub mod abi; pub mod spec; diff --git a/src/librustc_target/spec/abi.rs b/src/librustc_target/spec/abi.rs new file mode 100644 index 00000000000..ed2eb209906 --- /dev/null +++ b/src/librustc_target/spec/abi.rs @@ -0,0 +1,136 @@ +// Copyright 2012-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. + +use std::fmt; + +#[derive(PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Clone, Copy, Debug)] +pub enum Abi { + // NB: This ordering MUST match the AbiDatas array below. + // (This is ensured by the test indices_are_correct().) + + // Single platform ABIs + Cdecl, + Stdcall, + Fastcall, + Vectorcall, + Thiscall, + Aapcs, + Win64, + SysV64, + PtxKernel, + Msp430Interrupt, + X86Interrupt, + + // Multiplatform / generic ABIs + Rust, + C, + System, + RustIntrinsic, + RustCall, + PlatformIntrinsic, + Unadjusted +} + +#[derive(Copy, Clone)] +pub struct AbiData { + abi: Abi, + + /// Name of this ABI as we like it called. + name: &'static str, + + /// A generic ABI is supported on all platforms. + generic: bool, +} + +#[allow(non_upper_case_globals)] +const AbiDatas: &'static [AbiData] = &[ + // Platform-specific ABIs + AbiData {abi: Abi::Cdecl, name: "cdecl", generic: false }, + AbiData {abi: Abi::Stdcall, name: "stdcall", generic: false }, + AbiData {abi: Abi::Fastcall, name: "fastcall", generic: false }, + AbiData {abi: Abi::Vectorcall, name: "vectorcall", generic: false}, + AbiData {abi: Abi::Thiscall, name: "thiscall", generic: false}, + AbiData {abi: Abi::Aapcs, name: "aapcs", generic: false }, + AbiData {abi: Abi::Win64, name: "win64", generic: false }, + AbiData {abi: Abi::SysV64, name: "sysv64", generic: false }, + AbiData {abi: Abi::PtxKernel, name: "ptx-kernel", generic: false }, + AbiData {abi: Abi::Msp430Interrupt, name: "msp430-interrupt", generic: false }, + AbiData {abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false }, + + // Cross-platform ABIs + AbiData {abi: Abi::Rust, name: "Rust", generic: true }, + AbiData {abi: Abi::C, name: "C", generic: true }, + AbiData {abi: Abi::System, name: "system", generic: true }, + AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true }, + AbiData {abi: Abi::RustCall, name: "rust-call", generic: true }, + AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true }, + AbiData {abi: Abi::Unadjusted, name: "unadjusted", generic: true }, +]; + +/// Returns the ABI with the given name (if any). +pub fn lookup(name: &str) -> Option { + AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi) +} + +pub fn all_names() -> Vec<&'static str> { + AbiDatas.iter().map(|d| d.name).collect() +} + +impl Abi { + #[inline] + pub fn index(&self) -> usize { + *self as usize + } + + #[inline] + pub fn data(&self) -> &'static AbiData { + &AbiDatas[self.index()] + } + + pub fn name(&self) -> &'static str { + self.data().name + } + + pub fn generic(&self) -> bool { + self.data().generic + } +} + +impl fmt::Display for Abi { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\"{}\"", self.name()) + } +} + +#[allow(non_snake_case)] +#[test] +fn lookup_Rust() { + let abi = lookup("Rust"); + assert!(abi.is_some() && abi.unwrap().data().name == "Rust"); +} + +#[test] +fn lookup_cdecl() { + let abi = lookup("cdecl"); + assert!(abi.is_some() && abi.unwrap().data().name == "cdecl"); +} + +#[test] +fn lookup_baz() { + let abi = lookup("baz"); + assert!(abi.is_none()); +} + +#[test] +fn indices_are_correct() { + for (i, abi_data) in AbiDatas.iter().enumerate() { + assert_eq!(i, abi_data.abi.index()); + } +} diff --git a/src/librustc_target/spec/arm_base.rs b/src/librustc_target/spec/arm_base.rs index 416e5a0e13a..635b8ae7388 100644 --- a/src/librustc_target/spec/arm_base.rs +++ b/src/librustc_target/spec/arm_base.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::abi::Abi; +use spec::abi::Abi; // All the calling conventions trigger an assertion(Unsupported calling convention) in llvm on arm pub fn abi_blacklist() -> Vec { diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 978ead51b05..1e94f037885 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -50,8 +50,9 @@ use std::default::Default; use std::{fmt, io}; use std::path::{Path, PathBuf}; use std::str::FromStr; -use syntax::abi::{Abi, lookup as lookup_abi}; +use spec::abi::{Abi, lookup as lookup_abi}; +pub mod abi; mod android_base; mod apple_base; mod apple_ios_base; diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 73c72a15b05..483f36afe27 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -24,7 +24,7 @@ use rustc::ty::layout; use libc::c_uint; -pub use syntax::abi::Abi; +pub use rustc_target::spec::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; pub use rustc_target::abi::call::*; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index e83e73c8ae7..25ca2152b27 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -32,7 +32,7 @@ use rustc::hir; use libc::{c_uint, c_char}; use std::iter; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::symbol::InternedString; use syntax_pos::{Span, DUMMY_SP}; diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index c7868cc1e95..70c13e9b7d6 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -18,5 +18,6 @@ rustc = { path = "../librustc" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } +rustc_target = { path = "../librustc_target" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d657db0b125..6cdce127308 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -23,6 +23,7 @@ use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; +use rustc_target::spec::abi; use std::slice; use require_c_abi_if_variadic; use util::common::ErrorReported; @@ -30,7 +31,7 @@ use util::nodemap::FxHashSet; use errors::FatalError; use std::iter; -use syntax::{abi, ast}; +use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax_pos::Span; diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 0c95f5eeb43..4df496763e4 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -17,7 +17,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::{infer, traits}; use rustc::ty::{self, TyCtxt, TypeFoldable, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; -use syntax::abi; +use rustc_target::spec::abi; use syntax::symbol::Symbol; use syntax_pos::Span; diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index ed0613860d0..3b9d561ffc5 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -23,7 +23,7 @@ use rustc::ty::subst::Substs; use rustc::ty::TypeFoldable; use std::cmp; use std::iter; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::codemap::Span; use rustc::hir; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 64b0e7d0a7d..283fbf8fecc 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -17,7 +17,7 @@ use rustc::ty::{self, TyCtxt, Ty}; use rustc::util::nodemap::FxHashMap; use require_same_types; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::symbol::Symbol; use syntax_pos::Span; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4083d4a21ef..787df7c6479 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -118,7 +118,7 @@ use std::fmt::Display; use std::mem::replace; use std::iter; use std::ops::{self, Deref}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr; use syntax::codemap::{original_sp, Spanned}; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fb8c6ba6401..2ebbd64cab9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -38,8 +38,9 @@ use rustc::ty::util::IntTypeExt; use rustc::ty::util::Discr; use rustc::util::captures::Captures; use rustc::util::nodemap::FxHashMap; +use rustc_target::spec::abi; -use syntax::{abi, ast}; +use syntax::ast; use syntax::ast::MetaItemKind; use syntax::attr::{InlineAttr, list_contains_name, mark_used}; use syntax::codemap::Spanned; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d29ee3d9b3a..23fe91ffdeb 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -94,6 +94,7 @@ extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_errors as errors; +extern crate rustc_target; use rustc::hir; use rustc::lint; @@ -111,7 +112,7 @@ use session::{CompileIncomplete, config}; use util::common::time; use syntax::ast; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax_pos::Span; use std::iter; diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index 65c78d3593f..26fba71c812 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -23,7 +23,8 @@ use rustc::ty::{self, AdtKind, CratePredicatesMap, Region, RegionKind, ReprOptio ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; -use syntax::{abi, ast}; +use rustc_target::spec::abi; +use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; /// Infer predicates for the items in the crate. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e37b3a7fcc4..fb05cbfe32c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -20,7 +20,7 @@ pub use self::FunctionRetTy::*; pub use self::Visibility::*; use syntax; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{self, AttrStyle, Ident}; use syntax::attr; use syntax::codemap::{dummy_spanned, Spanned}; diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 413e5623118..f85a70a6d40 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -13,7 +13,7 @@ pub use self::StructType::*; pub use self::TypeBound::*; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast; use syntax::ast::{Name, NodeId}; use syntax::attr; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0a7e19fc643..a9a4c511374 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -19,7 +19,7 @@ use std::fmt; use std::iter::repeat; use rustc::hir::def_id::DefId; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use rustc::hir; use clean::{self, PrimitiveType}; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0ae946c4182..82449e9b5f9 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -54,7 +54,7 @@ use std::sync::Arc; use externalfiles::ExternalHtml; use serialize::json::{ToJson, Json, as_json}; -use syntax::{abi, ast}; +use syntax::ast; use syntax::codemap::FileName; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::middle::privacy::AccessLevels; @@ -62,6 +62,7 @@ use rustc::middle::stability; use rustc::hir; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::flock; +use rustc_target::spec::abi; use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability}; use doctree; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a60db29c2f9..614386a583a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -36,6 +36,7 @@ extern crate rustc_driver; extern crate rustc_resolve; extern crate rustc_lint; extern crate rustc_metadata; +extern crate rustc_target; extern crate rustc_typeck; extern crate serialize; #[macro_use] extern crate syntax; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f45a5b030db..967c50e62db 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -13,7 +13,7 @@ use std::mem; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast; use syntax::attr; use syntax_pos::Span; diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 8c24f36615b..d1a5ab0211b 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -14,6 +14,6 @@ serialize = { path = "../libserialize" } log = "0.4" scoped-tls = "0.1" syntax_pos = { path = "../libsyntax_pos" } -rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } rustc_errors = { path = "../librustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_target = { path = "../librustc_target" } diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs deleted file mode 100644 index ed2eb209906..00000000000 --- a/src/libsyntax/abi.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2012-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. - -use std::fmt; - -#[derive(PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Clone, Copy, Debug)] -pub enum Abi { - // NB: This ordering MUST match the AbiDatas array below. - // (This is ensured by the test indices_are_correct().) - - // Single platform ABIs - Cdecl, - Stdcall, - Fastcall, - Vectorcall, - Thiscall, - Aapcs, - Win64, - SysV64, - PtxKernel, - Msp430Interrupt, - X86Interrupt, - - // Multiplatform / generic ABIs - Rust, - C, - System, - RustIntrinsic, - RustCall, - PlatformIntrinsic, - Unadjusted -} - -#[derive(Copy, Clone)] -pub struct AbiData { - abi: Abi, - - /// Name of this ABI as we like it called. - name: &'static str, - - /// A generic ABI is supported on all platforms. - generic: bool, -} - -#[allow(non_upper_case_globals)] -const AbiDatas: &'static [AbiData] = &[ - // Platform-specific ABIs - AbiData {abi: Abi::Cdecl, name: "cdecl", generic: false }, - AbiData {abi: Abi::Stdcall, name: "stdcall", generic: false }, - AbiData {abi: Abi::Fastcall, name: "fastcall", generic: false }, - AbiData {abi: Abi::Vectorcall, name: "vectorcall", generic: false}, - AbiData {abi: Abi::Thiscall, name: "thiscall", generic: false}, - AbiData {abi: Abi::Aapcs, name: "aapcs", generic: false }, - AbiData {abi: Abi::Win64, name: "win64", generic: false }, - AbiData {abi: Abi::SysV64, name: "sysv64", generic: false }, - AbiData {abi: Abi::PtxKernel, name: "ptx-kernel", generic: false }, - AbiData {abi: Abi::Msp430Interrupt, name: "msp430-interrupt", generic: false }, - AbiData {abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false }, - - // Cross-platform ABIs - AbiData {abi: Abi::Rust, name: "Rust", generic: true }, - AbiData {abi: Abi::C, name: "C", generic: true }, - AbiData {abi: Abi::System, name: "system", generic: true }, - AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true }, - AbiData {abi: Abi::RustCall, name: "rust-call", generic: true }, - AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true }, - AbiData {abi: Abi::Unadjusted, name: "unadjusted", generic: true }, -]; - -/// Returns the ABI with the given name (if any). -pub fn lookup(name: &str) -> Option { - AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi) -} - -pub fn all_names() -> Vec<&'static str> { - AbiDatas.iter().map(|d| d.name).collect() -} - -impl Abi { - #[inline] - pub fn index(&self) -> usize { - *self as usize - } - - #[inline] - pub fn data(&self) -> &'static AbiData { - &AbiDatas[self.index()] - } - - pub fn name(&self) -> &'static str { - self.data().name - } - - pub fn generic(&self) -> bool { - self.data().generic - } -} - -impl fmt::Display for Abi { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "\"{}\"", self.name()) - } -} - -#[allow(non_snake_case)] -#[test] -fn lookup_Rust() { - let abi = lookup("Rust"); - assert!(abi.is_some() && abi.unwrap().data().name == "Rust"); -} - -#[test] -fn lookup_cdecl() { - let abi = lookup("cdecl"); - assert!(abi.is_some() && abi.unwrap().data().name == "cdecl"); -} - -#[test] -fn lookup_baz() { - let abi = lookup("baz"); - assert!(abi.is_none()); -} - -#[test] -fn indices_are_correct() { - for (i, abi_data) in AbiDatas.iter().enumerate() { - assert_eq!(i, abi_data.abi.index()); - } -} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 4e3ee241468..cbfcad12f1e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -19,7 +19,7 @@ pub use util::parser::ExprPrecedence; use syntax_pos::{Span, DUMMY_SP}; use codemap::{respan, Spanned}; -use abi::Abi; +use rustc_target::spec::abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; use ptr::P; diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index a9f48342243..0b64189b2bc 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::Abi; +use rustc_target::spec::abi::Abi; use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind}; use attr; use syntax_pos::{Pos, Span, DUMMY_SP}; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 39ddb13d347..0331e90164f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -25,7 +25,7 @@ use self::AttributeType::*; use self::AttributeGate::*; -use abi::Abi; +use rustc_target::spec::abi::Abi; use ast::{self, NodeId, PatKind, RangeEnd}; use attr; use edition::{ALL_EDITIONS, Edition}; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index ad98e2a6b71..870ce1926ad 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -28,10 +28,6 @@ #![recursion_limit="256"] -// See librustc_cratesio_shim/Cargo.toml for a comment explaining this. -#[allow(unused_extern_crates)] -extern crate rustc_cratesio_shim; - #[macro_use] extern crate bitflags; extern crate core; extern crate serialize; @@ -39,6 +35,7 @@ extern crate serialize; pub extern crate rustc_errors as errors; extern crate syntax_pos; extern crate rustc_data_structures; +extern crate rustc_target; #[macro_use] extern crate scoped_tls; extern crate serialize as rustc_serialize; // used by deriving @@ -138,7 +135,6 @@ pub mod syntax { pub use ast; } -pub mod abi; pub mod ast; pub mod attr; pub mod codemap; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 0397c3297db..ff09c6aa2f0 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -678,7 +678,7 @@ mod tests { use syntax_pos::{self, Span, BytePos, Pos, NO_EXPANSION}; use codemap::{respan, Spanned}; use ast::{self, Ident, PatKind}; - use abi::Abi; + use rustc_target::spec::abi::Abi; use attr::first_attr_value_str_by_name; use parse; use parse::parser::Parser; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9fa3952ca80..324cadc84e8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{self, Abi}; +use rustc_target::spec::abi::{self, Abi}; use ast::{AngleBracketedParameterData, ParenthesizedParameterData, AttrStyle, BareFnTy}; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Unsafety; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index bd06ae8c1a9..88860df10e2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -10,7 +10,7 @@ pub use self::AnnNode::*; -use abi::{self, Abi}; +use rustc_target::spec::abi::{self, Abi}; use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 325927ed832..e2a9f8715e2 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -563,7 +563,7 @@ fn mk_main(cx: &mut TestCtxt) -> P { let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)), ast::Unsafety::Normal, dummy_spanned(ast::Constness::NotConst), - ::abi::Abi::Rust, ast::Generics::default(), main_body); + ::rustc_target::spec::abi::Abi::Rust, ast::Generics::default(), main_body); P(ast::Item { ident: Ident::from_str("main"), attrs: vec![main_attr], diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 8743840e443..40d59d3ff8b 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -23,7 +23,7 @@ //! instance, a walker looking for item names in a module will miss all of //! those that are created by the expansion of a macro. -use abi::Abi; +use rustc_target::spec::abi::Abi; use ast::*; use syntax_pos::Span; use codemap::Spanned; diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index d8eeb5ed255..1676757d9b8 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -14,4 +14,5 @@ proc_macro = { path = "../libproc_macro" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_data_structures = { path = "../librustc_data_structures" } \ No newline at end of file +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_target = { path = "../librustc_target" } \ No newline at end of file diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1ef0d2b0b49..becd70149fd 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -191,7 +191,7 @@ use std::cell::RefCell; use std::collections::HashSet; use std::vec; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{ self, BinOpKind, EnumDef, Expr, GenericParam, Generics, Ident, PatKind, VariantData }; diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 39ad594e5c5..b6721dd28f3 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -27,6 +27,7 @@ extern crate syntax_pos; extern crate proc_macro; extern crate rustc_data_structures; extern crate rustc_errors as errors; +extern crate rustc_target; #[cfg(not(stage0))] mod diagnostics; -- cgit 1.4.1-3-g733a5 From e333725664c45874262ecb11e511c17cfd4672f0 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 9 May 2018 01:41:44 +0200 Subject: use fmt::Result where applicable --- src/librustc/ich/fingerprint.rs | 2 +- src/librustc_data_structures/control_flow_graph/dominators/mod.rs | 4 ++-- src/librustc_data_structures/owning_ref/mod.rs | 6 +++--- src/librustc_errors/lib.rs | 4 ++-- src/librustc_mir/borrow_check/nll/region_infer/mod.rs | 2 +- src/librustc_mir/transform/elaborate_drops.rs | 2 +- src/librustdoc/html/render.rs | 4 ++-- src/libstd/path.rs | 2 +- src/libstd/sys/redox/syscall/error.rs | 4 ++-- src/libstd/sys_common/wtf8.rs | 4 ++-- src/libsyntax_ext/format_foreign.rs | 2 +- src/test/run-pass/atomic-print.rs | 2 +- src/test/run-pass/union/union-trait-impl.rs | 2 +- 13 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index a7adf28c481..f56f4e12e7a 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -67,7 +67,7 @@ impl Fingerprint { } impl ::std::fmt::Display for Fingerprint { - fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(formatter, "{:x}-{:x}", self.0, self.1) } } diff --git a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs index dc487f1162c..54407658e6c 100644 --- a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs @@ -175,7 +175,7 @@ impl DominatorTree { } impl fmt::Debug for DominatorTree { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&DominatorTreeNode { tree: self, node: self.root, @@ -190,7 +190,7 @@ struct DominatorTreeNode<'tree, Node: Idx> { } impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let subtrees: Vec<_> = self.tree .children(self.node) .iter() diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index c466b8f8ad1..aa113fac9fb 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -1002,7 +1002,7 @@ impl Debug for OwningRef where O: Debug, T: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "OwningRef {{ owner: {:?}, reference: {:?} }}", self.owner(), @@ -1014,7 +1014,7 @@ impl Debug for OwningRefMut where O: Debug, T: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "OwningRefMut {{ owner: {:?}, reference: {:?} }}", self.owner(), @@ -1047,7 +1047,7 @@ unsafe impl Sync for OwningRefMut where O: Sync, for<'a> (&'a mut T): Sync {} impl Debug for Erased { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "",) } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index c2b442e9497..fd90e1cbe08 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -232,7 +232,7 @@ impl FatalError { } impl fmt::Display for FatalError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "parser fatal error") } } @@ -249,7 +249,7 @@ impl error::Error for FatalError { pub struct ExplicitBug; impl fmt::Display for ExplicitBug { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "parser internal bug") } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 4d1f3e2b430..57b8824191f 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1185,7 +1185,7 @@ impl<'tcx> RegionDefinition<'tcx> { } impl fmt::Debug for Constraint { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, "({:?}: {:?} @ {:?}) due to {:?}", diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 5397d18cdd7..79252e7654b 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -174,7 +174,7 @@ struct Elaborator<'a, 'b: 'a, 'tcx: 'b> { } impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> { - fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 21de2db1dfe..fe9fc3ddd68 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2579,7 +2579,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter, - implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> Result<(), fmt::Error> { + implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result { write!(w, "
  • ")?; // Entry - dump_set_for!(on_entry_set_for); + dump_set_for!(on_entry_set_for, interpret_set); // MIR statements write!(w, "")?; // Gen - dump_set_for!(gen_set_for); + dump_set_for!(gen_set_for, interpret_hybrid_set); // Kill - dump_set_for!(kill_set_for); + dump_set_for!(kill_set_for, interpret_hybrid_set); write!(w, "")?; @@ -217,19 +217,14 @@ where MWF: MirWithFlowState<'tcx>, -> io::Result<()> { let i = n.index(); - macro_rules! dump_set_for { - ($set:ident) => { - let flow = self.mbcx.flow_state(); - let bits_per_block = flow.sets.bits_per_block(); - let set = flow.sets.$set(i); - write!(w, "", - dot::escape_html(&bits_to_string(set.words(), bits_per_block)))?; - } - } + let flow = self.mbcx.flow_state(); + let bits_per_block = flow.sets.bits_per_block(); write!(w, "")?; + // Entry - dump_set_for!(on_entry_set_for); + let set = flow.sets.on_entry_set_for(i); + write!(w, "", dot::escape_html(&bits_to_string(set.words(), bits_per_block)))?; // Terminator write!(w, "")?; // Gen - dump_set_for!(gen_set_for); + let set = flow.sets.gen_set_for(i); + write!(w, "", dot::escape_html(&format!("{:?}", set)))?; // Kill - dump_set_for!(kill_set_for); + let set = flow.sets.kill_set_for(i); + write!(w, "", dot::escape_html(&format!("{:?}", set)))?; write!(w, "")?; diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 4227f0bcd36..56c4dac19e5 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -10,9 +10,9 @@ use syntax::ast::{self, MetaItem}; -use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; -use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::bitslice::{bitwise, BitwiseOperator, Word}; +use rustc_data_structures::indexed_set::{HybridIdxSetBuf, IdxSet, IdxSetBuf}; +use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::work_queue::WorkQueue; use rustc::ty::{self, TyCtxt}; @@ -188,7 +188,6 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation builder: self, }; propcx.walk_cfg(&mut temp); - } fn build_sets(&mut self) { @@ -243,8 +242,8 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: Bi let sets = self.builder.flow_state.sets.for_block(bb.index()); debug_assert!(in_out.words().len() == sets.on_entry.words().len()); in_out.overwrite(sets.on_entry); - in_out.union(sets.gen_set); - in_out.subtract(sets.kill_set); + in_out.union_hybrid(sets.gen_set); + in_out.subtract_hybrid(sets.kill_set); } self.builder.propagate_bits_into_graph_successors_of( in_out, (bb, bb_data), &mut dirty_queue); @@ -289,15 +288,11 @@ impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation } /// Maps each block to a set of bits -#[derive(Debug)] +#[derive(Clone, Debug)] pub(crate) struct Bits { bits: IdxSetBuf, } -impl Clone for Bits { - fn clone(&self) -> Self { Bits { bits: self.bits.clone() } } -} - impl Bits { fn new(bits: IdxSetBuf) -> Self { Bits { bits: bits } @@ -372,13 +367,15 @@ pub fn state_for_location<'tcx, T: BitDenotation>(loc: Location, result: &DataflowResults, mir: &Mir<'tcx>) -> IdxSetBuf { - let mut entry = result.sets().on_entry_set_for(loc.block.index()).to_owned(); + let mut on_entry = result.sets().on_entry_set_for(loc.block.index()).to_owned(); + let mut kill_set = on_entry.to_hybrid(); + let mut gen_set = kill_set.clone(); { let mut sets = BlockSets { - on_entry: &mut entry.clone(), - kill_set: &mut entry.clone(), - gen_set: &mut entry, + on_entry: &mut on_entry, + kill_set: &mut kill_set, + gen_set: &mut gen_set, }; for stmt in 0..loc.statement_index { @@ -396,7 +393,7 @@ pub fn state_for_location<'tcx, T: BitDenotation>(loc: Location, } } - entry + gen_set.to_dense() } pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation @@ -443,12 +440,22 @@ pub struct DataflowState impl DataflowState { pub(crate) fn interpret_set<'c, P>(&self, o: &'c O, - words: &IdxSet, + set: &IdxSet, render_idx: &P) -> Vec where P: Fn(&O, O::Idx) -> DebugFormatted { - words.iter().map(|i| render_idx(o, i)).collect() + set.iter().map(|i| render_idx(o, i)).collect() + } + + pub(crate) fn interpret_hybrid_set<'c, P>(&self, + o: &'c O, + set: &HybridIdxSetBuf, + render_idx: &P) + -> Vec + where P: Fn(&O, O::Idx) -> DebugFormatted + { + set.iter().map(|i| render_idx(o, i)).collect() } } @@ -461,18 +468,18 @@ pub struct AllSets { /// equal to bits_per_block / (mem::size_of:: * 8), rounded up. words_per_block: usize, + /// For each block, bits valid on entry to the block. + on_entry_sets: Bits, + /// For each block, bits generated by executing the statements in /// the block. (For comparison, the Terminator for each block is /// handled in a flow-specific manner during propagation.) - gen_sets: Bits, + gen_sets: Vec>, /// For each block, bits killed by executing the statements in the /// block. (For comparison, the Terminator for each block is /// handled in a flow-specific manner during propagation.) - kill_sets: Bits, - - /// For each block, bits valid on entry to the block. - on_entry_sets: Bits, + kill_sets: Vec>, } /// Triple of sets associated with a given block. @@ -494,11 +501,13 @@ pub struct BlockSets<'a, E: Idx> { /// Dataflow state immediately before control flow enters the given block. pub(crate) on_entry: &'a mut IdxSet, - /// Bits that are set to 1 by the time we exit the given block. - pub(crate) gen_set: &'a mut IdxSet, + /// Bits that are set to 1 by the time we exit the given block. Hybrid + /// because it usually contains only 0 or 1 elements. + pub(crate) gen_set: &'a mut HybridIdxSetBuf, - /// Bits that are set to 0 by the time we exit the given block. - pub(crate) kill_set: &'a mut IdxSet, + /// Bits that are set to 0 by the time we exit the given block. Hybrid + /// because it usually contains only 0 or 1 elements. + pub(crate) kill_set: &'a mut HybridIdxSetBuf, } impl<'a, E:Idx> BlockSets<'a, E> { @@ -542,8 +551,8 @@ impl<'a, E:Idx> BlockSets<'a, E> { } fn apply_local_effect(&mut self) { - self.on_entry.union(&self.gen_set); - self.on_entry.subtract(&self.kill_set); + self.on_entry.union_hybrid(&self.gen_set); + self.on_entry.subtract_hybrid(&self.kill_set); } } @@ -554,24 +563,21 @@ impl AllSets { let range = E::new(offset)..E::new(offset + self.words_per_block); BlockSets { on_entry: self.on_entry_sets.bits.range_mut(&range), - gen_set: self.gen_sets.bits.range_mut(&range), - kill_set: self.kill_sets.bits.range_mut(&range), + gen_set: &mut self.gen_sets[block_idx], + kill_set: &mut self.kill_sets[block_idx], } } - fn lookup_set_for<'a>(&self, sets: &'a Bits, block_idx: usize) -> &'a IdxSet { + pub fn on_entry_set_for(&self, block_idx: usize) -> &IdxSet { let offset = self.words_per_block * block_idx; let range = E::new(offset)..E::new(offset + self.words_per_block); - sets.bits.range(&range) + self.on_entry_sets.bits.range(&range) } - pub fn gen_set_for(&self, block_idx: usize) -> &IdxSet { - self.lookup_set_for(&self.gen_sets, block_idx) + pub fn gen_set_for(&self, block_idx: usize) -> &HybridIdxSetBuf { + &self.gen_sets[block_idx] } - pub fn kill_set_for(&self, block_idx: usize) -> &IdxSet { - self.lookup_set_for(&self.kill_sets, block_idx) - } - pub fn on_entry_set_for(&self, block_idx: usize) -> &IdxSet { - self.lookup_set_for(&self.on_entry_sets, block_idx) + pub fn kill_set_for(&self, block_idx: usize) -> &HybridIdxSetBuf { + &self.kill_sets[block_idx] } } @@ -731,12 +737,12 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation let num_blocks = mir.basic_blocks().len(); let num_overall = num_blocks * bits_per_block_rounded_up; - let zeroes = Bits::new(IdxSetBuf::new_empty(num_overall)); let on_entry = Bits::new(if D::bottom_value() { IdxSetBuf::new_filled(num_overall) } else { IdxSetBuf::new_empty(num_overall) }); + let empties = vec![HybridIdxSetBuf::new_empty(bits_per_block); num_blocks]; DataflowAnalysis { mir, @@ -745,9 +751,9 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation sets: AllSets { bits_per_block, words_per_block, - gen_sets: zeroes.clone(), - kill_sets: zeroes, on_entry_sets: on_entry, + gen_sets: empties.clone(), + kill_sets: empties, }, operator: denotation, } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index da149f42064..776d7888459 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -138,9 +138,9 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned(); - let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned(); - let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned(); + let mut on_entry = results.0.sets.on_entry_set_for(bb.index()).to_owned(); + let mut gen_set = results.0.sets.gen_set_for(bb.index()).clone(); + let mut kill_set = results.0.sets.kill_set_for(bb.index()).clone(); // Emulate effect of all statements in the block up to (but not // including) the borrow within `peek_arg_place`. Do *not* include @@ -148,9 +148,9 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // of the argument at time immediate preceding Call to // `rustc_peek`). - let mut sets = dataflow::BlockSets { on_entry: &mut entry, - gen_set: &mut gen, - kill_set: &mut kill }; + let mut sets = dataflow::BlockSets { on_entry: &mut on_entry, + gen_set: &mut gen_set, + kill_set: &mut kill_set }; for (j, stmt) in statements.iter().enumerate() { debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); @@ -203,14 +203,14 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}", place, lhs_mpi, stmt); // reset GEN and KILL sets before emulating their effect. - for e in sets.gen_set.words_mut() { *e = 0; } - for e in sets.kill_set.words_mut() { *e = 0; } + sets.gen_set.clear(); + sets.kill_set.clear(); results.0.operator.before_statement_effect( &mut sets, Location { block: bb, statement_index: j }); results.0.operator.statement_effect( &mut sets, Location { block: bb, statement_index: j }); - sets.on_entry.union(sets.gen_set); - sets.on_entry.subtract(sets.kill_set); + sets.on_entry.union_hybrid(sets.gen_set); + sets.on_entry.subtract_hybrid(sets.kill_set); } results.0.operator.before_terminator_effect( -- cgit 1.4.1-3-g733a5 From 14aed81d9ac058824af62c37b892b50fdb769912 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 21 Jul 2018 22:43:31 +0300 Subject: Use the new Entry::or_default method where possible. --- src/bootstrap/sanity.rs | 4 +- src/bootstrap/tool.rs | 2 +- src/librustc/hir/lowering.rs | 6 +- src/librustc/lint/mod.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 26 ++++----- src/librustc/session/config.rs | 4 +- src/librustc/traits/auto_trait.rs | 12 ++-- src/librustc/traits/error_reporting.rs | 6 +- .../traits/specialize/specialization_graph.rs | 24 +++----- src/librustc/ty/context.rs | 5 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/trait_def.rs | 65 +++++++++++----------- src/librustc_borrowck/borrowck/unused.rs | 4 +- src/librustc_borrowck/dataflow.rs | 4 +- src/librustc_codegen_llvm/back/symbol_export.rs | 5 +- src/librustc_codegen_llvm/base.rs | 4 +- src/librustc_data_structures/graph/test.rs | 8 +-- src/librustc_metadata/encoder.rs | 2 +- src/librustc_metadata/locator.rs | 8 ++- src/librustc_mir/borrow_check/borrow_set.rs | 2 +- src/librustc_mir/dataflow/impls/borrows.rs | 2 +- src/librustc_mir/monomorphize/partitioning.rs | 2 +- src/librustc_mir/util/pretty.rs | 2 +- src/librustc_resolve/check_unused.rs | 4 +- src/librustc_resolve/lib.rs | 6 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/op.rs | 2 +- src/librustc_typeck/coherence/inherent_impls.rs | 2 +- src/librustdoc/clean/auto_trait.rs | 28 +++++----- src/librustdoc/clean/simplify.rs | 4 +- src/librustdoc/html/render.rs | 8 +-- src/librustdoc/lib.rs | 4 +- src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/ext/tt/macro_rules.rs | 3 +- src/tools/tidy/src/deps.rs | 4 +- src/tools/tidy/src/errors.rs | 4 +- 36 files changed, 130 insertions(+), 146 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index c7f514da939..c2610de23be 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -176,7 +176,7 @@ pub fn check(build: &mut Build) { if target.contains("-none-") { if build.no_std(*target).is_none() { let target = build.config.target_config.entry(target.clone()) - .or_insert(Default::default()); + .or_default(); target.no_std = true; } @@ -192,7 +192,7 @@ pub fn check(build: &mut Build) { // fall back to the system toolchain in /usr before giving up if build.musl_root(*target).is_none() && build.config.build == *target { let target = build.config.target_config.entry(target.clone()) - .or_insert(Default::default()); + .or_default(); target.musl_root = Some("/usr".into()); } match build.musl_root(*target) { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index eaa31649447..23ef031dcb7 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -183,7 +183,7 @@ impl Step for ToolBuild { let mut artifacts = builder.tool_artifacts.borrow_mut(); let prev_artifacts = artifacts .entry(target) - .or_insert_with(Default::default); + .or_default(); if let Some(prev) = prev_artifacts.get(&*id) { if prev.1 != val.1 { duplicates.push(( diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 9ae5ab7f8be..09f76552279 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2334,7 +2334,7 @@ impl<'a> LoweringContext<'a> { // FIXME: This could probably be done with less rightward drift. Also looks like two control // paths where report_error is called are also the only paths that advance to after // the match statement, so the error reporting could probably just be moved there. - let mut add_bounds = NodeMap(); + let mut add_bounds: NodeMap> = NodeMap(); for pred in &generics.where_clause.predicates { if let WherePredicate::BoundPredicate(ref bound_pred) = *pred { 'next_bound: for bound in &bound_pred.bounds { @@ -2364,7 +2364,7 @@ impl<'a> LoweringContext<'a> { GenericParamKind::Type { .. } => { if node_id == param.id { add_bounds.entry(param.id) - .or_insert(Vec::new()) + .or_default() .push(bound.clone()); continue 'next_bound; } @@ -2730,7 +2730,7 @@ impl<'a> LoweringContext<'a> { if let Some(ref trait_ref) = trait_ref { if let Def::Trait(def_id) = trait_ref.path.def { - this.trait_impls.entry(def_id).or_insert(vec![]).push(id); + this.trait_impls.entry(def_id).or_default().push(id); } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 231a70f873f..c36d674566a 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -512,7 +512,7 @@ impl LintBuffer { msg: msg.to_string(), diagnostic }; - let arr = self.map.entry(id).or_insert(Vec::new()); + let arr = self.map.entry(id).or_default(); if !arr.contains(&early_lint) { arr.push(early_lint); } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index f2d39a905ee..6ae027dac7e 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -391,37 +391,33 @@ fn resolve_lifetimes<'tcx>( let named_region_map = krate(tcx); - let mut defs = FxHashMap(); + let mut rl = ResolveLifetimes { + defs: FxHashMap(), + late_bound: FxHashMap(), + object_lifetime_defaults: FxHashMap(), + }; + for (k, v) in named_region_map.defs { let hir_id = tcx.hir.node_to_hir_id(k); - let map = defs.entry(hir_id.owner_local_def_id()) - .or_insert_with(|| Lrc::new(FxHashMap())); + let map = rl.defs.entry(hir_id.owner_local_def_id()).or_default(); Lrc::get_mut(map).unwrap().insert(hir_id.local_id, v); } - let mut late_bound = FxHashMap(); for k in named_region_map.late_bound { let hir_id = tcx.hir.node_to_hir_id(k); - let map = late_bound - .entry(hir_id.owner_local_def_id()) - .or_insert_with(|| Lrc::new(FxHashSet())); + let map = rl.late_bound.entry(hir_id.owner_local_def_id()).or_default(); Lrc::get_mut(map).unwrap().insert(hir_id.local_id); } - let mut object_lifetime_defaults = FxHashMap(); for (k, v) in named_region_map.object_lifetime_defaults { let hir_id = tcx.hir.node_to_hir_id(k); - let map = object_lifetime_defaults + let map = rl.object_lifetime_defaults .entry(hir_id.owner_local_def_id()) - .or_insert_with(|| Lrc::new(FxHashMap())); + .or_default(); Lrc::get_mut(map) .unwrap() .insert(hir_id.local_id, Lrc::new(v)); } - Lrc::new(ResolveLifetimes { - defs, - late_bound, - object_lifetime_defaults, - }) + Lrc::new(rl) } fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ef1052d562e..3926ebedd37 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -2174,7 +2174,7 @@ pub fn build_session_options_and_crate_config( ); } - let mut externs = BTreeMap::new(); + let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new(); for arg in &matches.opt_strs("extern") { let mut parts = arg.splitn(2, '='); let name = match parts.next() { @@ -2191,7 +2191,7 @@ pub fn build_session_options_and_crate_config( externs .entry(name.to_string()) - .or_insert_with(BTreeSet::new) + .or_default() .insert(location.to_string()); } diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index 1ffe8157a0f..fd8c2d45e64 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -513,26 +513,26 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { { let deps1 = vid_map .entry(RegionTarget::RegionVid(r1)) - .or_insert_with(|| Default::default()); + .or_default(); deps1.larger.insert(RegionTarget::RegionVid(r2)); } let deps2 = vid_map .entry(RegionTarget::RegionVid(r2)) - .or_insert_with(|| Default::default()); + .or_default(); deps2.smaller.insert(RegionTarget::RegionVid(r1)); } &Constraint::RegSubVar(region, vid) => { { let deps1 = vid_map .entry(RegionTarget::Region(region)) - .or_insert_with(|| Default::default()); + .or_default(); deps1.larger.insert(RegionTarget::RegionVid(vid)); } let deps2 = vid_map .entry(RegionTarget::RegionVid(vid)) - .or_insert_with(|| Default::default()); + .or_default(); deps2.smaller.insert(RegionTarget::Region(region)); } &Constraint::VarSubReg(vid, region) => { @@ -542,13 +542,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { { let deps1 = vid_map .entry(RegionTarget::Region(r1)) - .or_insert_with(|| Default::default()); + .or_default(); deps1.larger.insert(RegionTarget::Region(r2)); } let deps2 = vid_map .entry(RegionTarget::Region(r2)) - .or_insert_with(|| Default::default()); + .or_default(); deps2.smaller.insert(RegionTarget::Region(r1)); } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 99b2f3e59fe..113adda3ccb 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -57,7 +57,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { index: Option, // None if this is an old error } - let mut error_map : FxHashMap<_, _> = + let mut error_map : FxHashMap<_, Vec<_>> = self.reported_trait_errors.borrow().iter().map(|(&span, predicates)| { (span, predicates.iter().map(|predicate| ErrorDescriptor { predicate: predicate.clone(), @@ -66,14 +66,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }).collect(); for (index, error) in errors.iter().enumerate() { - error_map.entry(error.obligation.cause.span).or_insert(Vec::new()).push( + error_map.entry(error.obligation.cause.span).or_default().push( ErrorDescriptor { predicate: error.obligation.predicate.clone(), index: Some(index) }); self.reported_trait_errors.borrow_mut() - .entry(error.obligation.cause.span).or_insert(Vec::new()) + .entry(error.obligation.cause.span).or_default() .push(error.obligation.predicate.clone()); } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index f9c0581d3ca..a7652574c1a 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -49,7 +49,7 @@ pub struct Graph { /// Children of a given impl, grouped into blanket/non-blanket varieties as is /// done in `TraitDef`. -#[derive(RustcEncodable, RustcDecodable)] +#[derive(Default, RustcEncodable, RustcDecodable)] struct Children { // Impls of a trait (or specializations of a given impl). To allow for // quicker lookup, the impls are indexed by a simplified version of their @@ -81,13 +81,6 @@ enum Inserted { } impl<'a, 'gcx, 'tcx> Children { - fn new() -> Children { - Children { - nonblanket_impls: FxHashMap(), - blanket_impls: vec![], - } - } - /// Insert an impl into this set of children without comparing to any existing impls fn insert_blindly(&mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, @@ -95,7 +88,7 @@ impl<'a, 'gcx, 'tcx> Children { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { debug!("insert_blindly: impl_def_id={:?} sty={:?}", impl_def_id, sty); - self.nonblanket_impls.entry(sty).or_insert(vec![]).push(impl_def_id) + self.nonblanket_impls.entry(sty).or_default().push(impl_def_id) } else { debug!("insert_blindly: impl_def_id={:?} sty=None", impl_def_id); self.blanket_impls.push(impl_def_id) @@ -230,7 +223,7 @@ impl<'a, 'gcx, 'tcx> Children { } fn filtered(&mut self, sty: SimplifiedType) -> Box + '_> { - let nonblanket = self.nonblanket_impls.entry(sty).or_insert(vec![]).iter(); + let nonblanket = self.nonblanket_impls.entry(sty).or_default().iter(); Box::new(self.blanket_impls.iter().chain(nonblanket).cloned()) } } @@ -268,7 +261,7 @@ impl<'a, 'gcx, 'tcx> Graph { trait_ref, impl_def_id, trait_def_id); self.parent.insert(impl_def_id, trait_def_id); - self.children.entry(trait_def_id).or_insert(Children::new()) + self.children.entry(trait_def_id).or_default() .insert_blindly(tcx, impl_def_id); return Ok(None); } @@ -281,7 +274,7 @@ impl<'a, 'gcx, 'tcx> Graph { loop { use self::Inserted::*; - let insert_result = self.children.entry(parent).or_insert(Children::new()) + let insert_result = self.children.entry(parent).or_default() .insert(tcx, impl_def_id, simplified)?; match insert_result { @@ -318,9 +311,8 @@ impl<'a, 'gcx, 'tcx> Graph { self.parent.insert(impl_def_id, parent); // Add G as N's child. - let mut grand_children = Children::new(); - grand_children.insert_blindly(tcx, grand_child_to_be); - self.children.insert(impl_def_id, grand_children); + self.children.entry(impl_def_id).or_default() + .insert_blindly(tcx, grand_child_to_be); break; } ShouldRecurseOn(new_parent) => { @@ -343,7 +335,7 @@ impl<'a, 'gcx, 'tcx> Graph { was already present."); } - self.children.entry(parent).or_insert(Children::new()).insert_blindly(tcx, child); + self.children.entry(parent).or_default().insert_blindly(tcx, child); } /// The parent of a given impl, which is the def id of the trait when the diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index bb14af29a7a..42948a3f5f1 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1132,11 +1132,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { None }; - let mut trait_map = FxHashMap(); + let mut trait_map: FxHashMap<_, Lrc>> = FxHashMap(); for (k, v) in resolutions.trait_map { let hir_id = hir.node_to_hir_id(k); - let map = trait_map.entry(hir_id.owner) - .or_insert_with(|| Lrc::new(FxHashMap())); + let map = trait_map.entry(hir_id.owner).or_default(); Lrc::get_mut(map).unwrap() .insert(hir_id.local_id, Lrc::new(StableVec::new(v))); diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 19e5406cd0d..0ace44dca77 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -228,7 +228,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { match self.sty { TyAdt(def, substs) => { { - let substs_set = visited.entry(def.did).or_insert(FxHashSet::default()); + let substs_set = visited.entry(def.did).or_default(); if !substs_set.insert(substs) { // We are already calculating the inhabitedness of this type. // The type must contain a reference to itself. Break the diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 32f0d3384c4..6332080a183 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -41,6 +41,7 @@ pub struct TraitDef { pub def_path_hash: DefPathHash, } +#[derive(Default)] pub struct TraitImpls { blanket_impls: Vec, /// Impls indexed by their simplified self-type, for fast lookup. @@ -143,47 +144,43 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_id: DefId) -> Lrc { - let mut remote_impls = Vec::new(); - - // Traits defined in the current crate can't have impls in upstream - // crates, so we don't bother querying the cstore. - if !trait_id.is_local() { - for &cnum in tcx.crates().iter() { - let impls = tcx.implementations_of_trait((cnum, trait_id)); - remote_impls.extend(impls.iter().cloned()); - } - } - - let mut blanket_impls = Vec::new(); - let mut non_blanket_impls = FxHashMap(); + let mut impls = TraitImpls::default(); - let local_impls = tcx.hir - .trait_impls(trait_id) - .into_iter() - .map(|&node_id| tcx.hir.local_def_id(node_id)); + { + let mut add_impl = |impl_def_id| { + let impl_self_ty = tcx.type_of(impl_def_id); + if impl_def_id.is_local() && impl_self_ty.references_error() { + return; + } - for impl_def_id in local_impls.chain(remote_impls.into_iter()) { - let impl_self_ty = tcx.type_of(impl_def_id); - if impl_def_id.is_local() && impl_self_ty.references_error() { - continue + if let Some(simplified_self_ty) = + fast_reject::simplify_type(tcx, impl_self_ty, false) + { + impls.non_blanket_impls + .entry(simplified_self_ty) + .or_default() + .push(impl_def_id); + } else { + impls.blanket_impls.push(impl_def_id); + } + }; + + // Traits defined in the current crate can't have impls in upstream + // crates, so we don't bother querying the cstore. + if !trait_id.is_local() { + for &cnum in tcx.crates().iter() { + for &def_id in tcx.implementations_of_trait((cnum, trait_id)).iter() { + add_impl(def_id); + } + } } - if let Some(simplified_self_ty) = - fast_reject::simplify_type(tcx, impl_self_ty, false) - { - non_blanket_impls - .entry(simplified_self_ty) - .or_insert(vec![]) - .push(impl_def_id); - } else { - blanket_impls.push(impl_def_id); + for &node_id in tcx.hir.trait_impls(trait_id) { + add_impl(tcx.hir.local_def_id(node_id)); } } - Lrc::new(TraitImpls { - blanket_impls: blanket_impls, - non_blanket_impls: non_blanket_impls, - }) + Lrc::new(impls) } impl<'a> HashStable> for TraitImpls { diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs index 475ff0b7443..88545c12415 100644 --- a/src/librustc_borrowck/borrowck/unused.rs +++ b/src/librustc_borrowck/borrowck/unused.rs @@ -44,7 +44,7 @@ struct UnusedMutCx<'a, 'tcx: 'a> { impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { fn check_unused_mut_pat(&self, pats: &[P]) { let tcx = self.bccx.tcx; - let mut mutables = FxHashMap(); + let mut mutables: FxHashMap<_, Vec<_>> = FxHashMap(); for p in pats { p.each_binding(|_, hir_id, span, ident| { // Skip anything that looks like `_foo` @@ -60,7 +60,7 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { _ => return, } - mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span)); + mutables.entry(ident.name).or_default().push((hir_id, span)); } else { tcx.sess.delay_span_bug(span, "missing binding mode"); } diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_borrowck/dataflow.rs index d5f30c1dcd4..75dee2b78fd 100644 --- a/src/librustc_borrowck/dataflow.rs +++ b/src/librustc_borrowck/dataflow.rs @@ -181,7 +181,7 @@ fn build_local_id_to_index(body: Option<&hir::Body>, cfg.graph.each_node(|node_idx, node| { if let cfg::CFGNodeData::AST(id) = node.data { - index.entry(id).or_insert(vec![]).push(node_idx); + index.entry(id).or_default().push(node_idx); } true }); @@ -209,7 +209,7 @@ fn build_local_id_to_index(body: Option<&hir::Body>, } fn visit_pat(&mut self, p: &hir::Pat) { - self.index.entry(p.hir_id.local_id).or_insert(vec![]).push(self.entry); + self.index.entry(p.hir_id.local_id).or_default().push(self.entry); intravisit::walk_pat(self, p) } } diff --git a/src/librustc_codegen_llvm/back/symbol_export.rs b/src/librustc_codegen_llvm/back/symbol_export.rs index c78d061a39b..edb1da0b558 100644 --- a/src/librustc_codegen_llvm/back/symbol_export.rs +++ b/src/librustc_codegen_llvm/back/symbol_export.rs @@ -299,7 +299,7 @@ fn upstream_monomorphizations_provider<'a, 'tcx>( let cnums = tcx.all_crate_nums(LOCAL_CRATE); - let mut instances = DefIdMap(); + let mut instances: DefIdMap> = DefIdMap(); let cnum_stable_ids: IndexVec = { let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, @@ -318,8 +318,7 @@ fn upstream_monomorphizations_provider<'a, 'tcx>( for &cnum in cnums.iter() { for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() { if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { - let substs_map = instances.entry(def_id) - .or_insert_with(|| FxHashMap()); + let substs_map = instances.entry(def_id).or_default(); match substs_map.entry(substs) { Occupied(mut e) => { diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index bd0c62e4766..0330a059826 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -1020,12 +1020,12 @@ fn collect_and_partition_mono_items<'a, 'tcx>( }).collect(); if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { - let mut item_to_cgus = FxHashMap(); + let mut item_to_cgus: FxHashMap<_, Vec<_>> = FxHashMap(); for cgu in &codegen_units { for (&mono_item, &linkage) in cgu.items() { item_to_cgus.entry(mono_item) - .or_insert(Vec::new()) + .or_default() .push((cgu.name().clone(), linkage)); } } diff --git a/src/librustc_data_structures/graph/test.rs b/src/librustc_data_structures/graph/test.rs index 48b654726b8..b72d011c99b 100644 --- a/src/librustc_data_structures/graph/test.rs +++ b/src/librustc_data_structures/graph/test.rs @@ -33,12 +33,12 @@ impl TestGraph { for &(source, target) in edges { graph.num_nodes = max(graph.num_nodes, source + 1); graph.num_nodes = max(graph.num_nodes, target + 1); - graph.successors.entry(source).or_insert(vec![]).push(target); - graph.predecessors.entry(target).or_insert(vec![]).push(source); + graph.successors.entry(source).or_default().push(target); + graph.predecessors.entry(target).or_default().push(source); } for node in 0..graph.num_nodes { - graph.successors.entry(node).or_insert(vec![]); - graph.predecessors.entry(node).or_insert(vec![]); + graph.successors.entry(node).or_default(); + graph.predecessors.entry(node).or_default(); } graph } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 7c445cb715e..02a41e68f68 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1788,7 +1788,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> { if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) { self.impls .entry(trait_ref.def_id) - .or_insert(vec![]) + .or_default() .push(impl_id.index); } } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 52777e5f6b9..f78a19403ac 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -451,7 +451,10 @@ impl<'a> Context<'a> { let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix); let staticlib_prefix = format!("{}{}{}", staticpair.0, self.crate_name, extra_prefix); - let mut candidates = FxHashMap(); + let mut candidates: FxHashMap< + _, + (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>), + > = FxHashMap(); let mut staticlibs = vec![]; // First, find all possible candidate rlibs and dylibs purely based on @@ -493,8 +496,7 @@ impl<'a> Context<'a> { info!("lib candidate: {}", path.display()); let hash_str = hash.to_string(); - let slot = candidates.entry(hash_str) - .or_insert_with(|| (FxHashMap(), FxHashMap(), FxHashMap())); + let slot = candidates.entry(hash_str).or_default(); let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot; fs::canonicalize(path) .map(|p| { diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 2e0cbf4326b..454f89e5d06 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -248,7 +248,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { self.activation_map .entry(location) - .or_insert(Vec::new()) + .or_default() .push(borrow_index); TwoPhaseActivation::ActivatedAt(location) } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index b0c4d37814e..8f3595b1784 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -80,7 +80,7 @@ fn precompute_borrows_out_of_scope<'tcx>( debug!("borrow {:?} gets killed at {:?}", borrow_index, location); borrows_out_of_scope_at_location .entry(location) - .or_insert(vec![]) + .or_default() .push(borrow_index); continue; } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 73d5d1d0948..7d7be69b355 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -696,7 +696,7 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, inlining_map.iter_accesses(|accessor, accessees| { for accessee in accessees { accessor_map.entry(*accessee) - .or_insert(Vec::new()) + .or_default() .push(accessor); } }); diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 4bb74c60974..01ad85cf668 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -528,7 +528,7 @@ pub fn write_mir_intro<'a, 'gcx, 'tcx>( if let Some(parent) = scope_data.parent_scope { scope_tree .entry(parent) - .or_insert(vec![]) + .or_default() .push(SourceScope::new(index)); } else { // Only the argument scope has no parent, because it's the root. diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 77005a83e42..cafacf99c3d 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -65,7 +65,7 @@ impl<'a, 'b, 'd> UnusedImportCheckVisitor<'a, 'b, 'd> { // Check later. return; } - self.unused_imports.entry(item_id).or_insert_with(NodeMap).insert(id, span); + self.unused_imports.entry(item_id).or_default().insert(id, span); } else { // This trait import is definitely used, in a way other than // method resolution. @@ -112,7 +112,7 @@ impl<'a, 'b, 'cl> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'cl> { if items.len() == 0 { self.unused_imports .entry(self.base_id) - .or_insert_with(NodeMap) + .or_default() .insert(id, span); } } else { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bc8ee2a8adb..4b2a96be4dd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1819,7 +1819,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { fn add_to_glob_map(&mut self, id: NodeId, ident: Ident) { if self.make_glob_map { - self.glob_map.entry(id).or_insert_with(FxHashSet).insert(ident.name); + self.glob_map.entry(id).or_default().insert(ident.name); } } @@ -3703,14 +3703,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let seen = self.freevars_seen .entry(function_id) - .or_insert_with(|| NodeMap()); + .or_default(); if let Some(&index) = seen.get(&node_id) { def = Def::Upvar(node_id, index, function_id); continue; } let vec = self.freevars .entry(function_id) - .or_insert_with(|| vec![]); + .or_default(); let depth = vec.len(); def = Def::Upvar(node_id, depth, function_id); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4fac11189a4..189859aad07 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2005,7 +2005,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { closure_def_id: DefId, r: DeferredCallResolution<'gcx, 'tcx>) { let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r); + deferred_call_resolutions.entry(closure_def_id).or_default().push(r); } fn remove_deferred_call_resolutions(&self, diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index cdf2b6ae447..3adcd638a62 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -242,7 +242,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .borrow_mut() .adjustments_mut() .entry(rhs_expr.hir_id) - .or_insert(vec![]) + .or_default() .push(autoref); } } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 02a18fa47df..f37167d1f66 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -304,7 +304,7 @@ impl<'a, 'tcx> InherentCollect<'a, 'tcx> { let impl_def_id = self.tcx.hir.local_def_id(item.id); let mut rc_vec = self.impls_map.inherent_impls .entry(def_id) - .or_insert_with(|| Lrc::new(vec![])); + .or_default(); // At this point, there should not be any clones of the // `Lrc`, so we can still safely push into it in place: diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 5fd0b888707..1331bd5186f 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -267,7 +267,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { // all intermediate RegionVids. At the end, all constraints should // be between Regions (aka region variables). This gives us the information // we need to create the Generics. - let mut finished = FxHashMap(); + let mut finished: FxHashMap<_, Vec<_>> = FxHashMap(); let mut vid_map: FxHashMap = FxHashMap(); @@ -281,25 +281,25 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { { let deps1 = vid_map .entry(RegionTarget::RegionVid(r1)) - .or_insert_with(|| Default::default()); + .or_default(); deps1.larger.insert(RegionTarget::RegionVid(r2)); } let deps2 = vid_map .entry(RegionTarget::RegionVid(r2)) - .or_insert_with(|| Default::default()); + .or_default(); deps2.smaller.insert(RegionTarget::RegionVid(r1)); } &Constraint::RegSubVar(region, vid) => { let deps = vid_map .entry(RegionTarget::RegionVid(vid)) - .or_insert_with(|| Default::default()); + .or_default(); deps.smaller.insert(RegionTarget::Region(region)); } &Constraint::VarSubReg(vid, region) => { let deps = vid_map .entry(RegionTarget::RegionVid(vid)) - .or_insert_with(|| Default::default()); + .or_default(); deps.larger.insert(RegionTarget::Region(region)); } &Constraint::RegSubReg(r1, r2) => { @@ -308,7 +308,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { if self.region_name(r1) != self.region_name(r2) { finished .entry(self.region_name(r2).expect("no region_name found")) - .or_insert_with(|| Vec::new()) + .or_default() .push(r1); } } @@ -343,7 +343,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { if self.region_name(r1) != self.region_name(r2) { finished .entry(self.region_name(r2).expect("no region name found")) - .or_insert_with(|| Vec::new()) + .or_default() .push(r1) // Larger, smaller } } @@ -577,8 +577,8 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { } = full_generics.clean(self.cx); let mut has_sized = FxHashSet(); - let mut ty_to_bounds = FxHashMap(); - let mut lifetime_to_bounds = FxHashMap(); + let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = FxHashMap(); + let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = FxHashMap(); let mut ty_to_traits: FxHashMap> = FxHashMap(); let mut ty_to_fn: FxHashMap, Option)> = FxHashMap(); @@ -647,11 +647,11 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { ty_to_bounds .entry(ty.clone()) - .or_insert_with(|| FxHashSet()); + .or_default(); } else { ty_to_bounds .entry(ty.clone()) - .or_insert_with(|| FxHashSet()) + .or_default() .insert(b.clone()); } } @@ -659,7 +659,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { WherePredicate::RegionPredicate { lifetime, bounds } => { lifetime_to_bounds .entry(lifetime) - .or_insert_with(|| FxHashSet()) + .or_default() .extend(bounds); } WherePredicate::EqPredicate { lhs, rhs } => { @@ -722,7 +722,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { let bounds = ty_to_bounds .entry(*ty.clone()) - .or_insert_with(|| FxHashSet()); + .or_default(); bounds.insert(GenericBound::TraitBound( PolyTrait { @@ -752,7 +752,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { // loop ty_to_traits .entry(*ty.clone()) - .or_insert_with(|| FxHashSet()) + .or_default() .insert(*trait_.clone()); } _ => panic!("Unexpected trait {:?} for {:?}", trait_, did), diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 9ea8bc53635..e938d2d0a16 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -34,7 +34,7 @@ use core::DocContext; pub fn where_clauses(cx: &DocContext, clauses: Vec) -> Vec { // First, partition the where clause into its separate components - let mut params = BTreeMap::new(); + let mut params: BTreeMap<_, Vec<_>> = BTreeMap::new(); let mut lifetimes = Vec::new(); let mut equalities = Vec::new(); let mut tybounds = Vec::new(); @@ -43,7 +43,7 @@ pub fn where_clauses(cx: &DocContext, clauses: Vec) -> Vec { match clause { WP::BoundPredicate { ty, bounds } => { match ty { - clean::Generic(s) => params.entry(s).or_insert(Vec::new()) + clean::Generic(s) => params.entry(s).or_default() .extend(bounds), t => tybounds.push((t, ty_bounds(bounds))), } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 470aa2c10e9..33b3934e3a4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1245,7 +1245,7 @@ impl DocFolder for Cache { // Collect all the implementors of traits. if let clean::ImplItem(ref i) = item.inner { if let Some(did) = i.trait_.def_id() { - self.implementors.entry(did).or_insert(vec![]).push(Impl { + self.implementors.entry(did).or_default().push(Impl { impl_item: item.clone(), }); } @@ -1440,7 +1440,7 @@ impl DocFolder for Cache { unreachable!() }; for did in dids { - self.impls.entry(did).or_insert(vec![]).push(Impl { + self.impls.entry(did).or_default().push(Impl { impl_item: item.clone(), }); } @@ -1971,7 +1971,7 @@ impl Context { fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap> { // BTreeMap instead of HashMap to get a sorted output - let mut map = BTreeMap::new(); + let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new(); for item in &m.items { if item.is_stripped() { continue } @@ -1981,7 +1981,7 @@ impl Context { Some(ref s) => s.to_string(), }; let short = short.to_string(); - map.entry(short).or_insert(vec![]) + map.entry(short).or_default() .push((myname, Some(plain_summary_line(item.doc_value())))); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 7581965cc0c..a8ae6a94d5c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -599,7 +599,7 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { /// returns a map mapping crate names to their paths or else an /// error message. fn parse_externs(matches: &getopts::Matches) -> Result { - let mut externs = BTreeMap::new(); + let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new(); for arg in &matches.opt_strs("extern") { let mut parts = arg.splitn(2, '='); let name = parts.next().ok_or("--extern value must not be empty".to_string())?; @@ -607,7 +607,7 @@ fn parse_externs(matches: &getopts::Matches) -> Result { .ok_or("--extern value must be of the format `foo=bar`" .to_string())?; let name = name.to_string(); - externs.entry(name).or_insert_with(BTreeSet::new).insert(location.to_string()); + externs.entry(name).or_default().insert(location.to_string()); } Ok(Externs::new(externs)) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 90b46268045..ffa2730d686 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -327,7 +327,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Unresolved macros produce dummy outputs as a recovery measure. invocations.reverse(); let mut expanded_fragments = Vec::new(); - let mut derives = HashMap::new(); + let mut derives: HashMap> = HashMap::new(); let mut undetermined_invocations = Vec::new(); let (mut progress, mut force) = (false, !self.monotonic); loop { @@ -388,7 +388,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = add_derived_markers(&mut self.cx, item.span(), &traits, item.clone()); - let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); + let derives = derives.entry(invoc.expansion_data.mark).or_default(); for path in &traits { let mark = Mark::fresh(self.cx.current_expansion.mark); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index f51d079a6c0..770561fe326 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -88,8 +88,7 @@ impl TTMacroExpander for MacroRulesMacroExpander { fn trace_macros_note(cx: &mut ExtCtxt, sp: Span, message: String) { let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); - let values: &mut Vec = cx.expansions.entry(sp).or_insert_with(Vec::new); - values.push(message); + cx.expansions.entry(sp).or_default().push(message); } /// Given `lhses` and `rhses`, this is the new macro we create diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index d63f479f29d..03bcda513fd 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -355,10 +355,10 @@ fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) { // "cargo", // FIXME(#53005) "rustc-ap-syntax", ]; - let mut name_to_id = HashMap::new(); + let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new(); for node in resolve.nodes.iter() { name_to_id.entry(node.id.split_whitespace().next().unwrap()) - .or_insert(Vec::new()) + .or_default() .push(&node.id); } diff --git a/src/tools/tidy/src/errors.rs b/src/tools/tidy/src/errors.rs index 5bf7c894cda..3dccffddf93 100644 --- a/src/tools/tidy/src/errors.rs +++ b/src/tools/tidy/src/errors.rs @@ -20,7 +20,7 @@ use std::path::Path; pub fn check(path: &Path, bad: &mut bool) { let mut contents = String::new(); - let mut map = HashMap::new(); + let mut map: HashMap<_, Vec<_>> = HashMap::new(); super::walk(path, &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), &mut |file| { @@ -61,7 +61,7 @@ pub fn check(path: &Path, bad: &mut bool) { Ok(n) => n, Err(..) => continue, }; - map.entry(code).or_insert(Vec::new()) + map.entry(code).or_default() .push((file.to_owned(), num + 1, line.to_owned())); break } -- cgit 1.4.1-3-g733a5
    ")?; // If there's already another implementor that has the same abbridged name, use the // full path, for example in `std::iter::ExactSizeIterator` @@ -2612,7 +2612,7 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter, fn render_impls(cx: &Context, w: &mut fmt::Formatter, traits: &[&&Impl], - containing_item: &clean::Item) -> Result<(), fmt::Error> { + containing_item: &clean::Item) -> fmt::Result { for i in traits { let did = i.trait_did().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 696711a70d4..5d35a786173 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1460,7 +1460,7 @@ impl> iter::Extend

    for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for PathBuf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } diff --git a/src/libstd/sys/redox/syscall/error.rs b/src/libstd/sys/redox/syscall/error.rs index d8d78d55016..1ef79547431 100644 --- a/src/libstd/sys/redox/syscall/error.rs +++ b/src/libstd/sys/redox/syscall/error.rs @@ -48,13 +48,13 @@ impl Error { } impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.text()) } } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.text()) } } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index fe7e058091e..14a2555adf9 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -56,7 +56,7 @@ pub struct CodePoint { /// Example: `U+1F4A9` impl fmt::Debug for CodePoint { #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "U+{:04X}", self.value) } } @@ -144,7 +144,7 @@ impl ops::DerefMut for Wtf8Buf { /// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800] impl fmt::Debug for Wtf8Buf { #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index e95c6f2e124..2b8603c75a5 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -989,7 +989,7 @@ mod strcursor { } impl<'a> std::fmt::Debug for StrCursor<'a> { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after()) } } diff --git a/src/test/run-pass/atomic-print.rs b/src/test/run-pass/atomic-print.rs index 914b89dfb4d..2d478e954e7 100644 --- a/src/test/run-pass/atomic-print.rs +++ b/src/test/run-pass/atomic-print.rs @@ -15,7 +15,7 @@ use std::{env, fmt, process, sync, thread}; struct SlowFmt(u32); impl fmt::Debug for SlowFmt { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { thread::sleep_ms(3); self.0.fmt(f) } diff --git a/src/test/run-pass/union/union-trait-impl.rs b/src/test/run-pass/union/union-trait-impl.rs index 1cdaff2cab7..c1e408cc02a 100644 --- a/src/test/run-pass/union/union-trait-impl.rs +++ b/src/test/run-pass/union/union-trait-impl.rs @@ -15,7 +15,7 @@ union U { } impl fmt::Display for U { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { write!(f, "Oh hai {}", self.a) } } } -- cgit 1.4.1-3-g733a5 From 964e0691be3262d4864aa5d97e9dd6cecf806484 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 7 May 2018 19:38:41 -0400 Subject: use chunks api for SparseBitMatrix and add a `subset` fn --- src/librustc_data_structures/bitvec.rs | 37 +++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 28e3180063c..7231fe43172 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::BTreeMap; +use indexed_vec::{Idx, IndexVec}; use std::collections::btree_map::Entry; -use std::marker::PhantomData; +use std::collections::BTreeMap; use std::iter::FromIterator; -use indexed_vec::{Idx, IndexVec}; +use std::marker::PhantomData; type Word = u128; const WORD_BITS: usize = 128; @@ -317,14 +317,25 @@ impl SparseBitMatrix { if read != write { let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write); - for read_val in bit_set_read.iter() { - changed = changed | bit_set_write.insert(read_val); + for read_chunk in bit_set_read.chunks() { + changed = changed | bit_set_write.insert_chunk(read_chunk).any(); } } changed } + /// True if `sub` is a subset of `sup` + pub fn subset(&self, sub: R, sup: R) -> bool { + sub == sup || { + let bit_set_sub = &self.vector[sub]; + let bit_set_sup = &self.vector[sup]; + bit_set_sub + .chunks() + .all(|read_chunk| read_chunk.bits_eq(bit_set_sup.contains_chunk(read_chunk))) + } + } + /// Iterates through all the columns set to true in a given row of /// the matrix. pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { @@ -346,6 +357,7 @@ pub struct SparseChunk { } impl SparseChunk { + #[inline] pub fn one(index: I) -> Self { let index = index.index(); let key_usize = index / 128; @@ -358,10 +370,16 @@ impl SparseChunk { } } + #[inline] pub fn any(&self) -> bool { self.bits != 0 } + #[inline] + pub fn bits_eq(&self, other: SparseChunk) -> bool { + self.bits == other.bits + } + pub fn iter(&self) -> impl Iterator { let base = self.key as usize * 128; let mut bits = self.bits; @@ -394,6 +412,10 @@ impl SparseBitSet { self.chunk_bits.len() * 128 } + /// Returns a chunk containing only those bits that are already + /// present. You can test therefore if `self` contains all the + /// bits in chunk already by doing `chunk == + /// self.contains_chunk(chunk)`. pub fn contains_chunk(&self, chunk: SparseChunk) -> SparseChunk { SparseChunk { bits: self.chunk_bits @@ -403,6 +425,11 @@ impl SparseBitSet { } } + /// Modifies `self` to contain all the bits from `chunk` (in + /// addition to any pre-existing bits); returns a new chunk that + /// contains only those bits that were newly added. You can test + /// if anything was inserted by invoking `any()` on the returned + /// value. pub fn insert_chunk(&mut self, chunk: SparseChunk) -> SparseChunk { if chunk.bits == 0 { return chunk; -- cgit 1.4.1-3-g733a5 From 434d59a2c960dee2a17ae2625c8844986d580d7e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 7 May 2018 20:02:19 -0400 Subject: ignore the point where the outlives requirement was added --- src/librustc_data_structures/bitvec.rs | 2 +- .../borrow_check/nll/region_infer/dfs.rs | 265 --------------------- .../borrow_check/nll/region_infer/mod.rs | 134 +++++------ .../borrow_check/nll/region_infer/values.rs | 70 ++---- src/test/ui/nll/get_default.rs | 6 +- src/test/ui/nll/get_default.stderr | 54 ++++- 6 files changed, 122 insertions(+), 409 deletions(-) delete mode 100644 src/librustc_mir/borrow_check/nll/region_infer/dfs.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 7231fe43172..a22dd1fecec 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -326,7 +326,7 @@ impl SparseBitMatrix { } /// True if `sub` is a subset of `sup` - pub fn subset(&self, sub: R, sup: R) -> bool { + pub fn is_subset(&self, sub: R, sup: R) -> bool { sub == sup || { let bit_set_sub = &self.vector[sub]; let bit_set_sup = &self.vector[sup]; diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs b/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs deleted file mode 100644 index f68394d6149..00000000000 --- a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2017 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. - -//! Module defining the `dfs` method on `RegionInferenceContext`, along with -//! its associated helper traits. - -use borrow_check::nll::universal_regions::UniversalRegions; -use borrow_check::nll::region_infer::RegionInferenceContext; -use borrow_check::nll::region_infer::values::{RegionElementIndex, RegionValueElements, - RegionValues}; -use syntax::codemap::Span; -use rustc::mir::{Location, Mir}; -use rustc::ty::RegionVid; -use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::indexed_vec::Idx; - -pub(super) struct DfsStorage { - stack: Vec, - visited: BitVector, -} - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Creates dfs storage for use by dfs; this should be shared - /// across as many calls to dfs as possible to amortize allocation - /// costs. - pub(super) fn new_dfs_storage(&self) -> DfsStorage { - let num_elements = self.elements.num_elements(); - DfsStorage { - stack: vec![], - visited: BitVector::new(num_elements), - } - } - - /// Function used to satisfy or test a `R1: R2 @ P` - /// constraint. The core idea is that it performs a DFS starting - /// from `P`. The precise actions *during* that DFS depend on the - /// `op` supplied, so see (e.g.) `CopyFromSourceToTarget` for more - /// details. - /// - /// Returns: - /// - /// - `Ok(true)` if the walk was completed and something changed - /// along the way; - /// - `Ok(false)` if the walk was completed with no changes; - /// - `Err(early)` if the walk was existed early by `op`. `earlyelem` is the - /// value that `op` returned. - #[inline(never)] // ensure dfs is identifiable in profiles - pub(super) fn dfs( - &self, - mir: &Mir<'tcx>, - dfs: &mut DfsStorage, - mut op: C, - ) -> Result - where - C: DfsOp, - { - let mut changed = false; - - dfs.visited.clear(); - dfs.stack.push(op.start_point()); - while let Some(p) = dfs.stack.pop() { - let point_index = self.elements.index(p); - - if !op.source_region_contains(point_index) { - debug!(" not in from-region"); - continue; - } - - if !dfs.visited.insert(point_index.index()) { - debug!(" already visited"); - continue; - } - - let new = op.add_to_target_region(point_index)?; - changed |= new; - - let block_data = &mir[p.block]; - - let start_stack_len = dfs.stack.len(); - - if p.statement_index < block_data.statements.len() { - dfs.stack.push(Location { - statement_index: p.statement_index + 1, - ..p - }); - } else { - dfs.stack.extend( - block_data - .terminator() - .successors() - .map(|&basic_block| Location { - statement_index: 0, - block: basic_block, - }), - ); - } - - if dfs.stack.len() == start_stack_len { - // If we reach the END point in the graph, then copy - // over any skolemized end points in the `from_region` - // and make sure they are included in the `to_region`. - changed |= op.add_universal_regions_outlived_by_source_to_target()?; - } - } - - Ok(changed) - } -} - -/// Customizes the operation of the `dfs` function. This function is -/// used during inference to satisfy a `R1: R2 @ P` constraint. -pub(super) trait DfsOp { - /// If this op stops the walk early, what type does it propagate? - type Early; - - /// Returns the point from which to start the DFS. - fn start_point(&self) -> Location; - - /// Returns true if the source region contains the given point. - fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool; - - /// Adds the given point to the target region, returning true if - /// something has changed. Returns `Err` if we should abort the - /// walk early. - fn add_to_target_region( - &mut self, - point_index: RegionElementIndex, - ) -> Result; - - /// Adds all universal regions in the source region to the target region, returning - /// true if something has changed. - fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result; -} - -/// Used during inference to enforce a `R1: R2 @ P` constraint. For -/// each point Q we reach along the DFS, we check if Q is in R2 (the -/// "source region"). If not, we stop the walk. Otherwise, we add Q to -/// R1 (the "target region") and continue to Q's successors. If we -/// reach the end of the graph, then we add any universal regions from -/// R2 into R1. -pub(super) struct CopyFromSourceToTarget<'v> { - pub source_region: RegionVid, - pub target_region: RegionVid, - pub inferred_values: &'v mut RegionValues, - pub constraint_point: Location, - pub constraint_span: Span, -} - -impl<'v> DfsOp for CopyFromSourceToTarget<'v> { - /// We never stop the walk early. - type Early = !; - - fn start_point(&self) -> Location { - self.constraint_point - } - - fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool { - self.inferred_values - .contains(self.source_region, point_index) - } - - fn add_to_target_region(&mut self, point_index: RegionElementIndex) -> Result { - Ok(self.inferred_values.add_due_to_outlives( - self.source_region, - self.target_region, - point_index, - self.constraint_point, - self.constraint_span, - )) - } - - fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result { - Ok(self.inferred_values.add_universal_regions_outlived_by( - self.source_region, - self.target_region, - self.constraint_point, - self.constraint_span, - )) - } -} - -/// Used after inference to *test* a `R1: R2 @ P` constraint. For -/// each point Q we reach along the DFS, we check if Q in R2 is also -/// contained in R1. If not, we abort the walk early with an `Err` -/// condition. Similarly, if we reach the end of the graph and find -/// that R1 contains some universal region that R2 does not contain, -/// we abort the walk early. -pub(super) struct TestTargetOutlivesSource<'v, 'tcx: 'v> { - pub source_region: RegionVid, - pub target_region: RegionVid, - pub elements: &'v RegionValueElements, - pub universal_regions: &'v UniversalRegions<'tcx>, - pub inferred_values: &'v RegionValues, - pub constraint_point: Location, -} - -impl<'v, 'tcx> DfsOp for TestTargetOutlivesSource<'v, 'tcx> { - /// The element that was not found within R2. - type Early = RegionElementIndex; - - fn start_point(&self) -> Location { - self.constraint_point - } - - fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool { - self.inferred_values - .contains(self.source_region, point_index) - } - - fn add_to_target_region( - &mut self, - point_index: RegionElementIndex, - ) -> Result { - if !self.inferred_values - .contains(self.target_region, point_index) - { - return Err(point_index); - } - - Ok(false) - } - - fn add_universal_regions_outlived_by_source_to_target( - &mut self, - ) -> Result { - // For all `ur_in_source` in `source_region`. - for ur_in_source in self.inferred_values - .universal_regions_outlived_by(self.source_region) - { - // Check that `target_region` outlives `ur_in_source`. - - // If `ur_in_source` is a member of `target_region`, OK. - // - // (This is implied by the loop below, actually, just an - // irresistible micro-opt. Mm. Premature optimization. So - // tasty.) - if self.inferred_values - .contains(self.target_region, ur_in_source) - { - continue; - } - - // If there is some other element X such that `target_region: X` and - // `X: ur_in_source`, OK. - if self.inferred_values - .universal_regions_outlived_by(self.target_region) - .any(|ur_in_target| self.universal_regions.outlives(ur_in_target, ur_in_source)) - { - continue; - } - - // Otherwise, not known to be true. - return Err(self.elements.index(ur_in_source)); - } - - Ok(false) - } -} diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index b9459bb9023..2fdb7d63cb5 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -11,15 +11,17 @@ use super::universal_regions::UniversalRegions; use borrow_check::nll::region_infer::values::ToElementIndex; use rustc::hir::def_id::DefId; +use rustc::infer::error_reporting::nice_region_error::NiceRegionError; +use rustc::infer::region_constraints::{GenericKind, VarInfos}; use rustc::infer::InferCtxt; use rustc::infer::NLLRegionVariableOrigin; use rustc::infer::RegionObligation; use rustc::infer::RegionVariableOrigin; use rustc::infer::SubregionOrigin; -use rustc::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc::infer::region_constraints::{GenericKind, VarInfos}; -use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, - Local, Location, Mir}; +use rustc::mir::{ + ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location, + Mir, +}; use rustc::traits::ObligationCause; use rustc::ty::{self, RegionVid, Ty, TypeFoldable}; use rustc::util::common::{self, ErrorReported}; @@ -31,8 +33,6 @@ use syntax::ast; use syntax_pos::Span; mod annotation; -mod dfs; -use self::dfs::{CopyFromSourceToTarget, TestTargetOutlivesSource}; mod dump_mir; mod graphviz; mod values; @@ -422,9 +422,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Option> { assert!(self.inferred_values.is_none(), "values already inferred"); - let dfs_storage = &mut self.new_dfs_storage(); - - self.propagate_constraints(mir, dfs_storage); + self.propagate_constraints(mir); // If this is a closure, we can propagate unsatisfied // `outlives_requirements` to our creator, so create a vector @@ -437,13 +435,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { None }; - self.check_type_tests( - infcx, - mir, - dfs_storage, - mir_def_id, - outlives_requirements.as_mut(), - ); + self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut()); self.check_universal_regions(infcx, mir_def_id, outlives_requirements.as_mut()); @@ -464,18 +456,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. - fn propagate_constraints(&mut self, mir: &Mir<'tcx>, dfs_storage: &mut dfs::DfsStorage) { + fn propagate_constraints(&mut self, mir: &Mir<'tcx>) { self.dependency_map = Some(self.build_dependency_map()); - let inferred_values = self.compute_region_values(mir, dfs_storage); + let inferred_values = self.compute_region_values(mir); self.inferred_values = Some(inferred_values); } #[inline(never)] // ensure dfs is identifiable in profiles - fn compute_region_values( - &self, - mir: &Mir<'tcx>, - dfs_storage: &mut dfs::DfsStorage, - ) -> RegionValues { + fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues { debug!("compute_region_values()"); debug!("compute_region_values: constraints={:#?}", { let mut constraints: Vec<_> = self.constraints.iter().collect(); @@ -502,21 +490,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let constraint = &self.constraints[constraint_idx]; debug!("propagate_constraints: constraint={:?}", constraint); - // Grow the value as needed to accommodate the - // outlives constraint. - let Ok(made_changes) = self.dfs( - mir, - dfs_storage, - CopyFromSourceToTarget { - source_region: constraint.sub, - target_region: constraint.sup, - inferred_values: &mut inferred_values, - constraint_point: constraint.point, - constraint_span: constraint.span, - }, - ); - - if made_changes { + if inferred_values.add_region(constraint.sup, constraint.sub) { debug!("propagate_constraints: sub={:?}", constraint.sub); debug!("propagate_constraints: sup={:?}", constraint.sup); @@ -561,7 +535,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, - dfs_storage: &mut dfs::DfsStorage, mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, ) { @@ -570,13 +543,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); - if self.eval_region_test( - mir, - dfs_storage, - type_test.point, - type_test.lower_bound, - &type_test.test, - ) { + if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) { continue; } @@ -833,7 +800,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn eval_region_test( &self, mir: &Mir<'tcx>, - dfs_storage: &mut dfs::DfsStorage, point: Location, lower_bound: RegionVid, test: &RegionTest, @@ -846,27 +812,26 @@ impl<'tcx> RegionInferenceContext<'tcx> { match test { RegionTest::IsOutlivedByAllRegionsIn(regions) => regions .iter() - .all(|&r| self.eval_outlives(mir, dfs_storage, r, lower_bound, point)), + .all(|&r| self.eval_outlives(mir, r, lower_bound, point)), RegionTest::IsOutlivedByAnyRegionIn(regions) => regions .iter() - .any(|&r| self.eval_outlives(mir, dfs_storage, r, lower_bound, point)), + .any(|&r| self.eval_outlives(mir, r, lower_bound, point)), RegionTest::Any(tests) => tests .iter() - .any(|test| self.eval_region_test(mir, dfs_storage, point, lower_bound, test)), + .any(|test| self.eval_region_test(mir, point, lower_bound, test)), RegionTest::All(tests) => tests .iter() - .all(|test| self.eval_region_test(mir, dfs_storage, point, lower_bound, test)), + .all(|test| self.eval_region_test(mir, point, lower_bound, test)), } } // Evaluate whether `sup_region: sub_region @ point`. fn eval_outlives( &self, - mir: &Mir<'tcx>, - dfs_storage: &mut dfs::DfsStorage, + _mir: &Mir<'tcx>, sup_region: RegionVid, sub_region: RegionVid, point: Location, @@ -876,36 +841,43 @@ impl<'tcx> RegionInferenceContext<'tcx> { sup_region, sub_region, point ); - // Roughly speaking, do a DFS of all region elements reachable - // from `point` contained in `sub_region`. If any of those are - // *not* present in `sup_region`, the DFS will abort early and - // yield an `Err` result. - match self.dfs( - mir, - dfs_storage, - TestTargetOutlivesSource { - source_region: sub_region, - target_region: sup_region, - constraint_point: point, - elements: &self.elements, - universal_regions: &self.universal_regions, - inferred_values: self.inferred_values.as_ref().unwrap(), - }, - ) { - Ok(_) => { - debug!("eval_outlives: true"); - true - } + let inferred_values = self.inferred_values.as_ref().expect("values for regions not yet inferred"); - Err(elem) => { - debug!( - "eval_outlives: false because `{:?}` is not present in `{:?}`", - self.elements.to_element(elem), - sup_region - ); - false - } + debug!( + "eval_outlives: sup_region's value = {:?}", + inferred_values.region_value_str(sup_region), + ); + debug!( + "eval_outlives: sub_region's value = {:?}", + inferred_values.region_value_str(sub_region), + ); + + // Both the `sub_region` and `sup_region` consist of the union + // of some number of universal regions (along with the union + // of various points in the CFG; ignore those points for + // now). Therefore, the sup-region outlives the sub-region if, + // for each universal region R1 in the sub-region, there + // exists some region R2 in the sup-region that outlives R1. + let universal_outlives = + inferred_values.universal_regions_outlived_by(sub_region) + .all(|r1| { + inferred_values.universal_regions_outlived_by(sup_region) + .any(|r2| self.universal_regions.outlives(r2, r1)) + }); + + if !universal_outlives { + return false; + } + + // Now we have to compare all the points in the sub region and make + // sure they exist in the sup region. + + if self.universal_regions.is_universal_region(sup_region) { + // Micro-opt: universal regions contain all points. + return true; } + + inferred_values.contains_points(sup_region, sub_region) } /// Once regions have been propagated, this method is used to see diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 126a34831a8..3e2d9d956e7 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -17,7 +17,6 @@ use rustc::mir::{BasicBlock, Location, Mir}; use rustc::ty::RegionVid; use std::fmt::Debug; use std::rc::Rc; -use syntax::codemap::Span; use super::Cause; @@ -74,11 +73,6 @@ impl RegionValueElements { (0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions)) } - /// Iterates over the `RegionElementIndex` for all points in the CFG. - pub(super) fn all_universal_region_indices(&self) -> impl Iterator { - (0..self.num_universal_regions).map(move |i| RegionElementIndex::new(i)) - } - /// Converts a particular `RegionElementIndex` to the `RegionElement` it represents. pub(super) fn to_element(&self, i: RegionElementIndex) -> RegionElement { debug!("to_element(i={:?})", i); @@ -244,6 +238,12 @@ impl RegionValues { self.add_internal(r, i, |_| cause.clone()) } + /// Add all elements in `r_from` to `r_to` (because e.g. `r_to: + /// r_from`). + pub(super) fn add_region(&mut self, r_to: RegionVid, r_from: RegionVid) -> bool { + self.matrix.merge(r_from, r_to) + } + /// Internal method to add an element to a region. /// /// Takes a "lazy" cause -- this function will return the cause, but it will only @@ -278,60 +278,22 @@ impl RegionValues { } } - /// Adds `elem` to `to_region` because of a relation: - /// - /// to_region: from_region @ constraint_location - /// - /// that was added by the cod at `constraint_span`. - pub(super) fn add_due_to_outlives( - &mut self, - from_region: RegionVid, - to_region: RegionVid, - elem: T, - _constraint_location: Location, - _constraint_span: Span, - ) -> bool { - let elem = self.elements.index(elem); - self.add_internal(to_region, elem, |causes| causes[&(from_region, elem)]) - } - - /// Adds all the universal regions outlived by `from_region` to - /// `to_region`. - pub(super) fn add_universal_regions_outlived_by( - &mut self, - from_region: RegionVid, - to_region: RegionVid, - constraint_location: Location, - constraint_span: Span, - ) -> bool { - // We could optimize this by improving `SparseBitMatrix::merge` so - // it does not always merge an entire row. That would - // complicate causal tracking though. - debug!( - "add_universal_regions_outlived_by(from_region={:?}, to_region={:?})", - from_region, to_region - ); - let mut changed = false; - for elem in self.elements.all_universal_region_indices() { - if self.contains(from_region, elem) { - changed |= self.add_due_to_outlives( - from_region, - to_region, - elem, - constraint_location, - constraint_span, - ); - } - } - changed - } - /// True if the region `r` contains the given element. pub(super) fn contains(&self, r: RegionVid, elem: E) -> bool { let i = self.elements.index(elem); self.matrix.contains(r, i) } + /// True if `sup_region` contains all the CFG points that + /// `sub_region` contains. Ignores universal regions. + pub(super) fn contains_points(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { + // This could be done faster by comparing the bitsets. But I + // am lazy. + self.element_indices_contained_in(sub_region) + .skip_while(|&i| self.elements.to_universal_region(i).is_some()) + .all(|e| self.contains(sup_region, e)) + } + /// Iterate over the value of the region `r`, yielding up element /// indices. You may prefer `universal_regions_outlived_by` or /// `elements_contained_in`. diff --git a/src/test/ui/nll/get_default.rs b/src/test/ui/nll/get_default.rs index 728c84695ea..1a417b1e28c 100644 --- a/src/test/ui/nll/get_default.rs +++ b/src/test/ui/nll/get_default.rs @@ -30,8 +30,9 @@ fn ok(map: &mut Map) -> &String { return v; } None => { - map.set(String::new()); // Just AST errors here + map.set(String::new()); // Ideally, this would not error. //~^ ERROR borrowed as immutable (Ast) + //~| ERROR borrowed as immutable (Mir) } } } @@ -47,8 +48,9 @@ fn err(map: &mut Map) -> &String { return v; } None => { - map.set(String::new()); // Just AST errors here + map.set(String::new()); // Ideally, just AST would error here //~^ ERROR borrowed as immutable (Ast) + //~| ERROR borrowed as immutable (Mir) } } } diff --git a/src/test/ui/nll/get_default.stderr b/src/test/ui/nll/get_default.stderr index 064fd38b872..dd69e18652c 100644 --- a/src/test/ui/nll/get_default.stderr +++ b/src/test/ui/nll/get_default.stderr @@ -4,14 +4,14 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as imm LL | match map.get() { | --- immutable borrow occurs here ... -LL | map.set(String::new()); // Just AST errors here +LL | map.set(String::new()); // Ideally, this would not error. | ^^^ mutable borrow occurs here ... LL | } | - immutable borrow ends here error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:44:17 + --> $DIR/get_default.rs:45:17 | LL | match map.get() { | --- immutable borrow occurs here @@ -23,19 +23,61 @@ LL | } | - immutable borrow ends here error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:50:17 + --> $DIR/get_default.rs:51:17 | LL | match map.get() { | --- immutable borrow occurs here ... -LL | map.set(String::new()); // Just AST errors here +LL | map.set(String::new()); // Ideally, just AST would error here | ^^^ mutable borrow occurs here ... LL | } | - immutable borrow ends here error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:44:17 + --> $DIR/get_default.rs:33:17 + | +LL | match map.get() { + | --- immutable borrow occurs here +... +LL | map.set(String::new()); // Ideally, this would not error. + | ^^^ mutable borrow occurs here + | +note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1... + --> $DIR/get_default.rs:26:1 + | +LL | / fn ok(map: &mut Map) -> &String { +LL | | loop { +LL | | match map.get() { +LL | | Some(v) => { +... | +LL | | } +LL | | } + | |_^ + +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) + --> $DIR/get_default.rs:51:17 + | +LL | match map.get() { + | --- immutable borrow occurs here +... +LL | map.set(String::new()); // Ideally, just AST would error here + | ^^^ mutable borrow occurs here + | +note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1... + --> $DIR/get_default.rs:41:1 + | +LL | / fn err(map: &mut Map) -> &String { +LL | | loop { +LL | | match map.get() { +LL | | Some(v) => { +... | +LL | | } +LL | | } + | |_^ + +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) + --> $DIR/get_default.rs:45:17 | LL | match map.get() { | --- immutable borrow occurs here @@ -46,6 +88,6 @@ LL | map.set(String::new()); // Both AST and MIR error here LL | return v; | - borrow later used here -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0502`. -- cgit 1.4.1-3-g733a5 From 28a11825de37532eade7ad250d097855f796a085 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Thu, 26 Apr 2018 00:50:33 +0200 Subject: Add parallel abstractions --- src/librustc/hir/itemlikevisit.rs | 30 ++++++++++++++++++++++ src/librustc/hir/mod.rs | 26 +++++++++++++++++++ src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/sync.rs | 44 ++++++++++++++++++++++++++++++++- 5 files changed, 101 insertions(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 2221ecf07b4..a62000e10c7 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -88,3 +88,33 @@ impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> self.visitor.visit_impl_item(impl_item); } } + +/// A parallel variant of ItemLikeVisitor +pub trait ParItemLikeVisitor<'hir> { + fn visit_item(&self, item: &'hir Item); + fn visit_trait_item(&self, trait_item: &'hir TraitItem); + fn visit_impl_item(&self, impl_item: &'hir ImplItem); +} + +pub trait IntoVisitor<'hir> { + type Visitor: Visitor<'hir>; + fn into_visitor(&self) -> Self::Visitor; +} + +pub struct ParDeepVisitor(pub V); + +impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor + where V: IntoVisitor<'hir> +{ + fn visit_item(&self, item: &'hir Item) { + self.0.into_visitor().visit_item(item); + } + + fn visit_trait_item(&self, trait_item: &'hir TraitItem) { + self.0.into_visitor().visit_trait_item(trait_item); + } + + fn visit_impl_item(&self, impl_item: &'hir ImplItem) { + self.0.into_visitor().visit_impl_item(impl_item); + } +} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 0dc89d64bd5..33076267dbc 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -48,6 +48,7 @@ use ty::AdtKind; use ty::maps::Providers; use rustc_data_structures::indexed_vec; +use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope}; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; use std::collections::BTreeMap; @@ -720,6 +721,31 @@ impl Crate { } } + /// A parallel version of visit_all_item_likes + pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V) + where V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send + { + scope(|s| { + s.spawn(|_| { + par_iter(&self.items).for_each(|(_, item)| { + visitor.visit_item(item); + }); + }); + + s.spawn(|_| { + par_iter(&self.trait_items).for_each(|(_, trait_item)| { + visitor.visit_trait_item(trait_item); + }); + }); + + s.spawn(|_| { + par_iter(&self.impl_items).for_each(|(_, impl_item)| { + visitor.visit_impl_item(impl_item); + }); + }); + }); + } + pub fn body(&self, id: BodyId) -> &Body { &self.bodies[&id] } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 9178d0d00fa..6f1cbcad2f4 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -16,6 +16,7 @@ serialize = { path = "../libserialize" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" parking_lot_core = "0.2.8" +rustc-rayon = "0.1.0" [dependencies.parking_lot] version = "0.5" diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 597d1627ada..b2e7450e76c 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -44,6 +44,7 @@ extern crate parking_lot; #[macro_use] extern crate cfg_if; extern crate stable_deref_trait; +extern crate rustc_rayon as rayon; // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 3b7d6efbdae..36617631330 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true. +//! This module defines types which are thread safe if cfg!(parallel_queries) is true. //! //! `Lrc` is an alias of either Rc or Arc. //! @@ -40,6 +40,29 @@ use std; use std::ops::{Deref, DerefMut}; use owning_ref::{Erased, OwningRef}; +pub fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) + where A: FnOnce() -> RA, + B: FnOnce() -> RB +{ + (oper_a(), oper_b()) +} + +pub struct SerialScope; + +impl SerialScope { + pub fn spawn(&self, f: F) + where F: FnOnce(&SerialScope) + { + f(self) + } +} + +pub fn serial_scope(f: F) -> R + where F: FnOnce(&SerialScope) -> R +{ + f(&SerialScope) +} + cfg_if! { if #[cfg(not(parallel_queries))] { pub auto trait Send {} @@ -55,9 +78,19 @@ cfg_if! { } } + pub use self::serial_join as join; + pub use self::serial_scope as scope; + + pub use std::iter::Iterator as ParallelIterator; + + pub fn par_iter(t: T) -> T::IntoIter { + t.into_iter() + } + pub type MetadataRef = OwningRef, [u8]>; pub use std::rc::Rc as Lrc; + pub use std::rc::Weak as Weak; pub use std::cell::Ref as ReadGuard; pub use std::cell::RefMut as WriteGuard; pub use std::cell::RefMut as LockGuard; @@ -160,6 +193,7 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; pub use std::sync::Arc as Lrc; + pub use std::sync::Weak as Weak; pub use self::Lock as MTLock; @@ -167,6 +201,14 @@ cfg_if! { use parking_lot::RwLock as InnerRwLock; use std::thread; + pub use rayon::{join, scope}; + + pub use rayon::iter::ParallelIterator; + use rayon::iter::IntoParallelIterator; + + pub fn par_iter(t: T) -> T::Iter { + t.into_par_iter() + } pub type MetadataRef = OwningRef, [u8]>; -- cgit 1.4.1-3-g733a5 From f46b888f73d66149f1abe424489722283f60d6e1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 May 2018 22:27:45 +1000 Subject: Remove LazyBTreeMap. It was introduced in #50240 to avoid an allocation when creating a new BTreeMap, which gave some speed-ups. But then #50352 made that the default behaviour for BTreeMap, so LazyBTreeMap is no longer necessary. --- src/librustc/infer/higher_ranked/mod.rs | 12 ++- src/librustc/infer/mod.rs | 6 +- src/librustc/ty/fold.rs | 8 +- src/librustc_data_structures/lazy_btree_map.rs | 108 ------------------------- src/librustc_data_structures/lib.rs | 1 - 5 files changed, 12 insertions(+), 123 deletions(-) delete mode 100644 src/librustc_data_structures/lazy_btree_map.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index b8437e39ddc..acd5c44c1a4 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -19,10 +19,10 @@ use super::{CombinedSnapshot, use super::combine::CombineFields; use super::region_constraints::{TaintDirections}; -use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use ty::{self, TyCtxt, Binder, TypeFoldable}; use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; +use std::collections::BTreeMap; use syntax_pos::Span; use util::nodemap::{FxHashMap, FxHashSet}; @@ -247,8 +247,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &LazyBTreeMap>, + a_map: &BTreeMap>, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { // Regions that pre-dated the LUB computation stay as they are. @@ -344,8 +343,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &LazyBTreeMap>, + a_map: &BTreeMap>, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], r0: ty::Region<'tcx>) @@ -414,7 +412,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - a_map: &LazyBTreeMap>, + a_map: &BTreeMap>, r: ty::Region<'tcx>) -> ty::Region<'tcx> { for (a_br, a_r) in a_map { @@ -437,7 +435,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &LazyBTreeMap>) + map: &BTreeMap>) -> Vec { map.iter() .map(|(_, &r)| match *r { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index c62e7f8d9b6..b72a25dec27 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -28,9 +28,9 @@ use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::TypeFoldable; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations}; -use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref, RefMut}; +use std::collections::BTreeMap; use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; @@ -198,7 +198,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap<'tcx> = LazyBTreeMap>; +pub type SkolemizationMap<'tcx> = BTreeMap>; /// See `error_reporting` module for more details #[derive(Clone, Debug)] @@ -1236,7 +1236,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder) - -> (T, LazyBTreeMap>) + -> (T, BTreeMap>) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 1793b5e1edb..42adc82f48e 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -43,7 +43,7 @@ use middle::const_val::ConstVal; use hir::def_id::DefId; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; -use rustc_data_structures::lazy_btree_map::LazyBTreeMap; +use std::collections::BTreeMap; use std::fmt; use util::nodemap::FxHashSet; @@ -328,7 +328,7 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, current_depth: u32, fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), - map: LazyBTreeMap> + map: BTreeMap> } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -343,7 +343,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions(self, value: &Binder, mut f: F) - -> (T, LazyBTreeMap>) + -> (T, BTreeMap>) where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T : TypeFoldable<'tcx>, { @@ -456,7 +456,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { tcx, current_depth: 1, fld_r, - map: LazyBTreeMap::default() + map: BTreeMap::default() } } } diff --git a/src/librustc_data_structures/lazy_btree_map.rs b/src/librustc_data_structures/lazy_btree_map.rs deleted file mode 100644 index 74f91af10fe..00000000000 --- a/src/librustc_data_structures/lazy_btree_map.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018 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. - -use std::collections::btree_map; -use std::collections::BTreeMap; - -/// A thin wrapper around BTreeMap that avoids allocating upon creation. -/// -/// Vec, HashSet and HashMap all have the nice feature that they don't do any -/// heap allocation when creating a new structure of the default size. In -/// contrast, BTreeMap *does* allocate in that situation. The compiler uses -/// B-Tree maps in some places such that many maps are created but few are -/// inserted into, so having a BTreeMap alternative that avoids allocating on -/// creation is a performance win. -/// -/// Only a fraction of BTreeMap's functionality is currently supported. -/// Additional functionality should be added on demand. -#[derive(Debug)] -pub struct LazyBTreeMap(Option>); - -impl LazyBTreeMap { - pub fn new() -> LazyBTreeMap { - LazyBTreeMap(None) - } - - pub fn iter(&self) -> Iter { - Iter(self.0.as_ref().map(|btm| btm.iter())) - } - - pub fn is_empty(&self) -> bool { - self.0.as_ref().map_or(true, |btm| btm.is_empty()) - } -} - -impl LazyBTreeMap { - fn instantiate(&mut self) -> &mut BTreeMap { - if let Some(ref mut btm) = self.0 { - btm - } else { - let btm = BTreeMap::new(); - self.0 = Some(btm); - self.0.as_mut().unwrap() - } - } - - pub fn insert(&mut self, key: K, value: V) -> Option { - self.instantiate().insert(key, value) - } - - pub fn entry(&mut self, key: K) -> btree_map::Entry { - self.instantiate().entry(key) - } - - pub fn values<'a>(&'a self) -> Values<'a, K, V> { - Values(self.0.as_ref().map(|btm| btm.values())) - } -} - -impl Default for LazyBTreeMap { - fn default() -> LazyBTreeMap { - LazyBTreeMap::new() - } -} - -impl<'a, K: 'a, V: 'a> IntoIterator for &'a LazyBTreeMap { - type Item = (&'a K, &'a V); - type IntoIter = Iter<'a, K, V>; - - fn into_iter(self) -> Iter<'a, K, V> { - self.iter() - } -} - -pub struct Iter<'a, K: 'a, V: 'a>(Option>); - -impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { - type Item = (&'a K, &'a V); - - fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.0.as_mut().and_then(|iter| iter.next()) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.as_ref().map_or_else(|| (0, Some(0)), |iter| iter.size_hint()) - } -} - -pub struct Values<'a, K: 'a, V: 'a>(Option>); - -impl<'a, K, V> Iterator for Values<'a, K, V> { - type Item = &'a V; - - fn next(&mut self) -> Option<&'a V> { - self.0.as_mut().and_then(|values| values.next()) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.as_ref().map_or_else(|| (0, Some(0)), |values| values.size_hint()) - } -} - diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index b2e7450e76c..5bac1bd9a7b 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -61,7 +61,6 @@ pub mod bitvec; pub mod graph; pub mod indexed_set; pub mod indexed_vec; -pub mod lazy_btree_map; pub mod obligation_forest; pub mod sip128; pub mod snapshot_map; -- cgit 1.4.1-3-g733a5 From 89d9ca9b50e01cbc5dc78a26f15cc8c435bbc5a4 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 16 May 2018 18:07:35 +0200 Subject: Stabilize num::NonZeroU* Tracking issue: https://github.com/rust-lang/rust/issues/49137 --- src/liballoc/lib.rs | 1 - src/libcore/num/mod.rs | 16 +++++++--------- src/libcore/tests/lib.rs | 1 - src/librustc/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/libstd/lib.rs | 1 - src/libstd/num.rs | 3 +-- src/test/run-pass/ctfe/tuple-struct-constructors.rs | 1 - src/test/run-pass/enum-null-pointer-opt.rs | 2 -- src/test/ui/print_type_sizes/niche-filling.rs | 1 - 11 files changed, 8 insertions(+), 21 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index bb78c14b905..f7dd9d4f010 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -102,7 +102,6 @@ #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] -#![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] #![feature(pin)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 342f57b50f0..ae8b3087240 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -21,9 +21,9 @@ use ops; use str::FromStr; macro_rules! impl_nonzero_fmt { - ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -35,7 +35,7 @@ macro_rules! impl_nonzero_fmt { } macro_rules! nonzero_integers { - ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { + ( $( $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// @@ -46,7 +46,7 @@ macro_rules! nonzero_integers { /// use std::mem::size_of; /// assert_eq!(size_of::>(), size_of::()); /// ``` - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); @@ -56,14 +56,14 @@ macro_rules! nonzero_integers { /// # Safety /// /// The value must not be zero. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { $Ty(NonZero(n)) } /// Create a non-zero if the given value is not zero. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub fn new(n: $Int) -> Option { if n != 0 { @@ -74,7 +74,7 @@ macro_rules! nonzero_integers { } /// Returns the value as a primitive type. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub fn get(self) -> $Int { self.0 .0 @@ -83,7 +83,6 @@ macro_rules! nonzero_integers { } impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } )+ @@ -91,7 +90,6 @@ macro_rules! nonzero_integers { } nonzero_integers! { - #[unstable(feature = "nonzero", issue = "49137")] NonZeroU8(u8); NonZeroU16(u16); NonZeroU32(u32); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5e98e40e0d5..7fb4b503c01 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -26,7 +26,6 @@ #![feature(iterator_step_by)] #![feature(iterator_flatten)] #![feature(iterator_repeat_with)] -#![feature(nonzero)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 26ac9d6ee9e..ac6ff6831ad 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -56,7 +56,6 @@ #![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(non_exhaustive)] -#![feature(nonzero)] #![feature(proc_macro_internals)] #![feature(quote)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index b2e7450e76c..328ff76c1cd 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -21,7 +21,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(collections_range)] -#![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index fbc0facbc49..ecced1b8168 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -30,7 +30,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] -#![feature(nonzero)] #![feature(inclusive_range_methods)] #![feature(crate_visibility_modifier)] #![feature(never_type)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d41739ab02c..9cdc6a21622 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -277,7 +277,6 @@ #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(exhaustive_patterns)] -#![feature(nonzero)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index aa806b947b0..3f90c1fa3b1 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -21,8 +21,7 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; -#[unstable(feature = "nonzero", issue = "49137")] -#[allow(deprecated)] +#[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; #[cfg(test)] use fmt; diff --git a/src/test/run-pass/ctfe/tuple-struct-constructors.rs b/src/test/run-pass/ctfe/tuple-struct-constructors.rs index ee1ce192fe0..d5f3e88fd52 100644 --- a/src/test/run-pass/ctfe/tuple-struct-constructors.rs +++ b/src/test/run-pass/ctfe/tuple-struct-constructors.rs @@ -10,7 +10,6 @@ // https://github.com/rust-lang/rust/issues/41898 -#![feature(nonzero)] use std::num::NonZeroU64; fn main() { diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index 12f17a1575e..34ed589d418 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(nonzero, core)] - use std::mem::size_of; use std::num::NonZeroUsize; use std::ptr::NonNull; diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index 1aad0b760b1..17e7a21cd02 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -22,7 +22,6 @@ // padding and overall computed sizes can be quite different. #![feature(start)] -#![feature(nonzero)] #![allow(dead_code)] use std::num::NonZeroU32; -- cgit 1.4.1-3-g733a5 From f778bdefdd9663aa78c31ffc7773e31bcae4fb39 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 16 May 2018 20:59:27 +1000 Subject: Avoid repeated HashMap lookups in `opt_normalize_projection_type`. There is a hot path through `opt_normalize_projection_type`: - `try_start` does a cache lookup (#1). - The result is a `NormalizedTy`. - There are no unresolved type vars, so we call `complete`. - `complete` does *another* cache lookup (#2), then calls `SnapshotMap::insert`. - `insert` does *another* cache lookup (#3), inserting the same value that's already in the cache. This patch optimizes this hot path by introducing `complete_normalized`, for use when the value is known in advance to be a `NormalizedTy`. It always avoids lookup #2. Furthermore, if the `NormalizedTy`'s obligations are empty (the common case), we know that lookup #3 would be a no-op, so we avoid it, while inserting a Noop into the `SnapshotMap`'s undo log. --- src/librustc/traits/project.rs | 19 ++++++++++++++++++- src/librustc_data_structures/snapshot_map/mod.rs | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index bfa32f8e7fa..da8f086b9c5 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -596,7 +596,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( // Once we have inferred everything we need to know, we // can ignore the `obligations` from that point on. if !infcx.any_unresolved_type_vars(&ty.value) { - infcx.projection_cache.borrow_mut().complete(cache_key); + infcx.projection_cache.borrow_mut().complete_normalized(cache_key, &ty); ty.obligations = vec![]; } @@ -1682,6 +1682,23 @@ impl<'tcx> ProjectionCache<'tcx> { })); } + /// A specialized version of `complete` for when the key's value is known + /// to be a NormalizedTy. + pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) { + // We want to insert `ty` with no obligations. If the existing value + // already has no obligations (as is common) we can use `insert_noop` + // to do a minimal amount of work -- the HashMap insertion is skipped, + // and minimal changes are made to the undo log. + if ty.obligations.is_empty() { + self.map.insert_noop(); + } else { + self.map.insert(key, ProjectionCacheEntry::NormalizedTy(Normalized { + value: ty.value, + obligations: vec![] + })); + } + } + /// Indicates that trying to normalize `key` resulted in /// ambiguity. No point in trying it again then until we gain more /// type information (in which case, the "fully resolved" key will diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index cede6f14782..6ee8c3579f5 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -67,6 +67,12 @@ impl SnapshotMap } } + pub fn insert_noop(&mut self) { + if !self.undo_log.is_empty() { + self.undo_log.push(UndoLog::Noop); + } + } + pub fn remove(&mut self, key: K) -> bool { match self.map.remove(&key) { Some(old_value) => { -- cgit 1.4.1-3-g733a5 From 7ed0fd76998be8e537fa985c9ec52d3c22844e6e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 18 May 2018 15:25:34 -0400 Subject: use `reset_unifications` instead of creating new unification table --- src/Cargo.lock | 8 ++++---- src/librustc/infer/region_constraints/mod.rs | 7 ++----- src/librustc_data_structures/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/Cargo.lock b/src/Cargo.lock index 70e34c34b99..64f550be514 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -588,7 +588,7 @@ dependencies = [ [[package]] name = "ena" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1750,7 +1750,7 @@ version = "128.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1957,7 +1957,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2999,7 +2999,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4511b63d69dd5d31e8e29aed2c132c413f87acea8035d0584801feaab9dd1f0f" -"checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834" +"checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621" "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "be27f8ea102a7182093a80d98f0b78623b580eda8791cbe8e2345fe6e57567a6" diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index c388fa21371..99d7b4eaf7d 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -318,7 +318,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // should think carefully about whether it needs to be cleared // or updated in some way. let RegionConstraintCollector { - var_infos, + var_infos: _, data, lubs, glbs, @@ -338,10 +338,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // un-unified" state. Note that when we unify `a` and `b`, we // also insert `a <= b` and a `b <= a` edges, so the // `RegionConstraintData` contains the relationship here. - *unification_table = ut::UnificationTable::new(); - for vid in var_infos.indices() { - unification_table.new_key(unify_key::RegionVidKey { min_vid: vid }); - } + unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid }); mem::replace(data, RegionConstraintData::default()) } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 6f1cbcad2f4..bb1fb84a0ce 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -ena = "0.9.1" +ena = "0.9.3" log = "0.4" rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } serialize = { path = "../libserialize" } -- cgit 1.4.1-3-g733a5 From 879eb972adc681cb02b84505760ccebedd7465cd Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 18 May 2018 11:48:11 +0200 Subject: Add SortedMap to rustc_data_structures. --- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/sorted_map.rs | 501 +++++++++++++++++++++++++++++ 2 files changed, 502 insertions(+) create mode 100644 src/librustc_data_structures/sorted_map.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 9a6705fe9ca..cd707152af6 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -73,6 +73,7 @@ pub mod control_flow_graph; pub mod flock; pub mod sync; pub mod owning_ref; +pub mod sorted_map; pub struct OnDrop(pub F); diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs new file mode 100644 index 00000000000..a8a43ebc1ad --- /dev/null +++ b/src/librustc_data_structures/sorted_map.rs @@ -0,0 +1,501 @@ +// Copyright 2018 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. + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::convert::From; +use std::mem; +use std::ops::{RangeBounds, Bound, Index, IndexMut}; + +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct SortedMap { + data: Vec<(K,V)> +} + +impl SortedMap { + + #[inline] + pub fn new() -> SortedMap { + SortedMap { + data: vec![] + } + } + + // It is up to the caller to make sure that the elements are sorted by key + // and that there are no duplicates. + #[inline] + pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap + { + debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + + SortedMap { + data: elements + } + } + + #[inline] + pub fn insert(&mut self, key: K, mut value: V) -> Option { + let index = self.data.binary_search_by(|&(ref x, _)| x.cmp(&key)); + + match index { + Ok(index) => { + let mut slot = unsafe { + self.data.get_unchecked_mut(index) + }; + mem::swap(&mut slot.1, &mut value); + Some(value) + } + Err(index) => { + self.data.insert(index, (key, value)); + None + } + } + } + + #[inline] + pub fn remove(&mut self, key: &K) -> Option { + let index = self.data.binary_search_by(|&(ref x, _)| x.cmp(key)); + + match index { + Ok(index) => { + Some(self.data.remove(index).1) + } + Err(_) => { + None + } + } + } + + #[inline] + pub fn get(&self, key: &K) -> Option<&V> { + let index = self.data.binary_search_by(|&(ref x, _)| x.cmp(key)); + + match index { + Ok(index) => { + unsafe { + Some(&self.data.get_unchecked(index).1) + } + } + Err(_) => { + None + } + } + } + + #[inline] + pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { + let index = self.data.binary_search_by(|&(ref x, _)| x.cmp(key)); + + match index { + Ok(index) => { + unsafe { + Some(&mut self.data.get_unchecked_mut(index).1) + } + } + Err(_) => { + None + } + } + } + + #[inline] + pub fn clear(&mut self) { + self.data.clear(); + } + + /// Iterate over elements, sorted by key + #[inline] + pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { + self.data.iter() + } + + /// Iterate over the keys, sorted + #[inline] + pub fn keys(&self) -> impl Iterator + ExactSizeIterator { + self.data.iter().map(|&(ref k, _)| k) + } + + /// Iterate over values, sorted by key + #[inline] + pub fn values(&self) -> impl Iterator + ExactSizeIterator { + self.data.iter().map(|&(_, ref v)| v) + } + + #[inline] + pub fn len(&self) -> usize { + self.data.len() + } + + #[inline] + pub fn range(&self, range: R) -> &[(K, V)] + where R: RangeBounds + { + let (start, end) = self.range_slice_indices(range); + (&self.data[start .. end]) + } + + #[inline] + pub fn range_mut(&mut self, range: R) -> &mut [(K, V)] + where R: RangeBounds + { + let (start, end) = self.range_slice_indices(range); + (&mut self.data[start .. end]) + } + + #[inline] + pub fn remove_range(&mut self, range: R) + where R: RangeBounds + { + let (start, end) = self.range_slice_indices(range); + self.data.splice(start .. end, ::std::iter::empty()); + } + + /// Mutate all keys with the given function `f`. This mutation must not + /// change the sort-order of keys. + #[inline] + pub fn offset_keys(&mut self, f: F) + where F: Fn(&mut K) + { + self.data.iter_mut().map(|&mut (ref mut k, _)| k).for_each(f); + } + + // It is up to the caller to make sure that the elements are sorted by key + // and that there are no duplicates. + #[inline] + pub fn insert_presorted(&mut self, mut elements: Vec<(K, V)>) { + if elements.is_empty() { + return + } + + debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + + let index = { + let first_element = &elements[0].0; + self.data.binary_search_by(|&(ref x, _)| x.cmp(first_element)) + }; + + let drain = match index { + Ok(index) => { + let mut drain = elements.drain(..); + self.data[index] = drain.next().unwrap(); + drain + } + Err(index) => { + if index == self.data.len() || + elements.last().unwrap().0 < self.data[index].0 { + // We can copy the whole range without having to mix with + // existing elements. + self.data.splice(index .. index, elements.drain(..)); + return + } + + let mut drain = elements.drain(..); + self.data.insert(index, drain.next().unwrap()); + drain + } + }; + + // Insert the rest + for (k, v) in drain { + self.insert(k, v); + } + } + + #[inline] + fn range_slice_indices(&self, range: R) -> (usize, usize) + where R: RangeBounds + { + let start = match range.start() { + Bound::Included(ref k) => { + match self.data.binary_search_by(|&(ref x, _)| x.cmp(k)) { + Ok(index) | Err(index) => index + } + } + Bound::Excluded(ref k) => { + match self.data.binary_search_by(|&(ref x, _)| x.cmp(k)) { + Ok(index) => index + 1, + Err(index) => index, + } + } + Bound::Unbounded => 0, + }; + + let end = match range.end() { + Bound::Included(ref k) => { + match self.data.binary_search_by(|&(ref x, _)| x.cmp(k)) { + Ok(index) => index + 1, + Err(index) => index, + } + } + Bound::Excluded(ref k) => { + match self.data.binary_search_by(|&(ref x, _)| x.cmp(k)) { + Ok(index) | Err(index) => index, + } + } + Bound::Unbounded => self.data.len(), + }; + + (start, end) + } +} + +impl IntoIterator for SortedMap { + type Item = (K, V); + type IntoIter = ::std::vec::IntoIter<(K, V)>; + fn into_iter(self) -> Self::IntoIter { + self.data.into_iter() + } +} + +impl> Index for SortedMap { + type Output = V; + fn index(&self, index: Q) -> &Self::Output { + let k: &K = index.borrow(); + self.get(k).unwrap() + } +} + +impl> IndexMut for SortedMap { + fn index_mut(&mut self, index: Q) -> &mut Self::Output { + let k: &K = index.borrow(); + self.get_mut(k).unwrap() + } +} + +impl> From for SortedMap { + fn from(data: I) -> Self { + let mut data: Vec<(K, V)> = data.collect(); + data.sort_unstable_by(|&(ref k1, _), &(ref k2, _)| k1.cmp(k2)); + data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| { + k1.cmp(k2) == Ordering::Equal + }); + SortedMap { + data + } + } +} + +#[cfg(test)] +mod tests { + use super::SortedMap; + use test::{self, Bencher}; + + #[test] + fn test_insert_and_iter() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0 .. 100 { + assert_eq!(map.iter().cloned().collect::>(), expected); + + let x = 1000 - x * 2; + map.insert(x, x); + expected.insert(0, (x, x)); + } + } + + #[test] + fn test_get_and_index() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0 .. 100 { + let x = 1000 - x; + if x & 1 == 0 { + map.insert(x, x); + } + expected.push(x); + } + + for mut x in expected { + if x & 1 == 0 { + assert_eq!(map.get(&x), Some(&x)); + assert_eq!(map.get_mut(&x), Some(&mut x)); + assert_eq!(map[&x], x); + assert_eq!(&mut map[&x], &mut x); + } else { + assert_eq!(map.get(&x), None); + assert_eq!(map.get_mut(&x), None); + } + } + } + + #[test] + fn test_range() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + map.insert(9, 9); + + let keys = |s: &[(_, _)]| { + s.into_iter().map(|e| e.0).collect::>() + }; + + for start in 0 .. 11 { + for end in 0 .. 11 { + if end < start { + continue + } + + let mut expected = vec![1, 3, 6, 9]; + expected.retain(|&x| x >= start && x < end); + + assert_eq!(keys(map.range(start..end)), expected, "range = {}..{}", start, end); + } + } + } + + + #[test] + fn test_offset_keys() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + + map.offset_keys(|k| *k += 1); + + let mut expected = SortedMap::new(); + expected.insert(2, 1); + expected.insert(4, 3); + expected.insert(7, 6); + + assert_eq!(map, expected); + } + + fn keys(s: SortedMap) -> Vec { + s.into_iter().map(|(k, _)| k).collect::>() + } + + fn elements(s: SortedMap) -> Vec<(u32, u32)> { + s.into_iter().collect::>() + } + + #[test] + fn test_remove_range() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + map.insert(9, 9); + + for start in 0 .. 11 { + for end in 0 .. 11 { + if end < start { + continue + } + + let mut expected = vec![1, 3, 6, 9]; + expected.retain(|&x| x < start || x >= end); + + let mut map = map.clone(); + map.remove_range(start .. end); + + assert_eq!(keys(map), expected, "range = {}..{}", start, end); + } + } + } + + #[test] + fn test_remove() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0..10 { + map.insert(x, x); + expected.push((x, x)); + } + + for x in 0 .. 10 { + let mut map = map.clone(); + let mut expected = expected.clone(); + + assert_eq!(map.remove(&x), Some(x)); + expected.remove(x as usize); + + assert_eq!(map.iter().cloned().collect::>(), expected); + } + } + + #[test] + fn test_insert_presorted_non_overlapping() { + let mut map = SortedMap::new(); + map.insert(2, 0); + map.insert(8, 0); + + map.insert_presorted(vec![(3, 0), (7, 0)]); + + let expected = vec![2, 3, 7, 8]; + assert_eq!(keys(map), expected); + } + + #[test] + fn test_insert_presorted_first_elem_equal() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(8, 8); + + map.insert_presorted(vec![(2, 0), (7, 7)]); + + let expected = vec![(2, 0), (7, 7), (8, 8)]; + assert_eq!(elements(map), expected); + } + + #[test] + fn test_insert_presorted_last_elem_equal() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(8, 8); + + map.insert_presorted(vec![(3, 3), (8, 0)]); + + let expected = vec![(2, 2), (3, 3), (8, 0)]; + assert_eq!(elements(map), expected); + } + + #[test] + fn test_insert_presorted_shuffle() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(7, 7); + + map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]); + + let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)]; + assert_eq!(elements(map), expected); + } + + macro_rules! mk_bench { + ($name:ident, $size:expr) => ( + #[bench] + fn $name(b: &mut Bencher) { + let mut map = SortedMap::new(); + for x in 0 .. $size { + map.insert(x * 3, 0); + } + + b.iter(|| { + test::black_box(map.range(..)); + test::black_box(map.range( $size / 2.. $size )); + test::black_box(map.range( 0 .. $size / 3 )); + test::black_box(map.range( $size / 4 .. $size / 3 )); + }) + } + ) + } + + mk_bench!(bench_range_1, 1); + mk_bench!(bench_range_2, 2); + mk_bench!(bench_range_5, 5); + mk_bench!(bench_range_10, 10); + mk_bench!(bench_range_32, 32); + mk_bench!(bench_range_1000, 1000); +} -- cgit 1.4.1-3-g733a5 From eaa796c8b885c0aecf0c85d8299a3b52cca72370 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 21 May 2018 16:12:02 +0200 Subject: Remove benchmarks from SortedMap. --- src/librustc_data_structures/sorted_map.rs | 33 ++++++++---------------------- 1 file changed, 9 insertions(+), 24 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index a8a43ebc1ad..c3f462f29c8 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -285,7 +285,6 @@ impl> From for SortedMap { #[cfg(test)] mod tests { use super::SortedMap; - use test::{self, Bencher}; #[test] fn test_insert_and_iter() { @@ -473,29 +472,15 @@ mod tests { assert_eq!(elements(map), expected); } - macro_rules! mk_bench { - ($name:ident, $size:expr) => ( - #[bench] - fn $name(b: &mut Bencher) { - let mut map = SortedMap::new(); - for x in 0 .. $size { - map.insert(x * 3, 0); - } + #[test] + fn test_insert_presorted_at_end() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(2, 2); - b.iter(|| { - test::black_box(map.range(..)); - test::black_box(map.range( $size / 2.. $size )); - test::black_box(map.range( 0 .. $size / 3 )); - test::black_box(map.range( $size / 4 .. $size / 3 )); - }) - } - ) - } + map.insert_presorted(vec![(3, 3), (8, 8)]); - mk_bench!(bench_range_1, 1); - mk_bench!(bench_range_2, 2); - mk_bench!(bench_range_5, 5); - mk_bench!(bench_range_10, 10); - mk_bench!(bench_range_32, 32); - mk_bench!(bench_range_1000, 1000); + let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)]; + assert_eq!(elements(map), expected); + } } -- cgit 1.4.1-3-g733a5 From e850d78bcc42d4ef1e2e938f13fde319b37ced9c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 21 May 2018 19:15:00 +0200 Subject: Remove SortedMap::iter_mut() since that allows to break the element sorting order which lookup relies on. --- src/librustc_data_structures/sorted_map.rs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index c3f462f29c8..fd2bf9272a7 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -141,14 +141,6 @@ impl SortedMap { (&self.data[start .. end]) } - #[inline] - pub fn range_mut(&mut self, range: R) -> &mut [(K, V)] - where R: RangeBounds - { - let (start, end) = self.range_slice_indices(range); - (&mut self.data[start .. end]) - } - #[inline] pub fn remove_range(&mut self, range: R) where R: RangeBounds -- cgit 1.4.1-3-g733a5 From 4bedc314597c20cbaf68ac094e42ba569fcc8973 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 21 May 2018 19:16:26 +0200 Subject: Cleanup SortedMap by wrapping element lookup in a method. --- src/librustc_data_structures/sorted_map.rs | 37 +++++++++++++----------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index fd2bf9272a7..cdce1e77c0f 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -42,9 +42,7 @@ impl SortedMap { #[inline] pub fn insert(&mut self, key: K, mut value: V) -> Option { - let index = self.data.binary_search_by(|&(ref x, _)| x.cmp(&key)); - - match index { + match self.lookup_index_for(&key) { Ok(index) => { let mut slot = unsafe { self.data.get_unchecked_mut(index) @@ -61,9 +59,7 @@ impl SortedMap { #[inline] pub fn remove(&mut self, key: &K) -> Option { - let index = self.data.binary_search_by(|&(ref x, _)| x.cmp(key)); - - match index { + match self.lookup_index_for(key) { Ok(index) => { Some(self.data.remove(index).1) } @@ -75,9 +71,7 @@ impl SortedMap { #[inline] pub fn get(&self, key: &K) -> Option<&V> { - let index = self.data.binary_search_by(|&(ref x, _)| x.cmp(key)); - - match index { + match self.lookup_index_for(key) { Ok(index) => { unsafe { Some(&self.data.get_unchecked(index).1) @@ -91,9 +85,7 @@ impl SortedMap { #[inline] pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { - let index = self.data.binary_search_by(|&(ref x, _)| x.cmp(key)); - - match index { + match self.lookup_index_for(key) { Ok(index) => { unsafe { Some(&mut self.data.get_unchecked_mut(index).1) @@ -168,12 +160,9 @@ impl SortedMap { debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); - let index = { - let first_element = &elements[0].0; - self.data.binary_search_by(|&(ref x, _)| x.cmp(first_element)) - }; + let start_index = self.lookup_index_for(&elements[0].0); - let drain = match index { + let drain = match start_index { Ok(index) => { let mut drain = elements.drain(..); self.data[index] = drain.next().unwrap(); @@ -200,18 +189,24 @@ impl SortedMap { } } + /// Looks up the key in `self.data` via `slice::binary_search()`. + #[inline(always)] + fn lookup_index_for(&self, key: &K) -> Result { + self.data.binary_search_by(|&(ref x, _)| x.cmp(key)) + } + #[inline] fn range_slice_indices(&self, range: R) -> (usize, usize) where R: RangeBounds { let start = match range.start() { Bound::Included(ref k) => { - match self.data.binary_search_by(|&(ref x, _)| x.cmp(k)) { + match self.lookup_index_for(k) { Ok(index) | Err(index) => index } } Bound::Excluded(ref k) => { - match self.data.binary_search_by(|&(ref x, _)| x.cmp(k)) { + match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, } @@ -221,13 +216,13 @@ impl SortedMap { let end = match range.end() { Bound::Included(ref k) => { - match self.data.binary_search_by(|&(ref x, _)| x.cmp(k)) { + match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, } } Bound::Excluded(ref k) => { - match self.data.binary_search_by(|&(ref x, _)| x.cmp(k)) { + match self.lookup_index_for(k) { Ok(index) | Err(index) => index, } } -- cgit 1.4.1-3-g733a5 From 95fac99a2036a0120be26262110a1e473a85950d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 21 May 2018 19:17:00 +0200 Subject: Add some doc comments to SortedMap. --- src/librustc_data_structures/sorted_map.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index cdce1e77c0f..e14bd33c82c 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -14,7 +14,15 @@ use std::convert::From; use std::mem; use std::ops::{RangeBounds, Bound, Index, IndexMut}; -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +/// `SortedMap` is a data structure with similar characteristics as BTreeMap but +/// slightly different trade-offs: lookup, inseration, and removal are O(log(N)) +/// and elements can be iterated in order cheaply. +/// +/// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it +/// stores data in a more compact way. It also supports accessing contiguous +/// ranges of elements as a slice, and slices of already sorted elements can be +/// inserted efficiently. +#[derive(Clone, PartialEq, Eq, Hash, Default, Debug, RustcEncodable, RustcDecodable)] pub struct SortedMap { data: Vec<(K,V)> } @@ -28,8 +36,11 @@ impl SortedMap { } } - // It is up to the caller to make sure that the elements are sorted by key - // and that there are no duplicates. + /// Construct a `SortedMap` from a presorted set of elements. This is faster + /// than creating an empty map and then inserting the elements individually. + /// + /// It is up to the caller to make sure that the elements are sorted by key + /// and that there are no duplicates. #[inline] pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap { @@ -150,8 +161,12 @@ impl SortedMap { self.data.iter_mut().map(|&mut (ref mut k, _)| k).for_each(f); } - // It is up to the caller to make sure that the elements are sorted by key - // and that there are no duplicates. + /// Inserts a presorted range of elements into the map. If the range can be + /// inserted as a whole in between to existing elements of the map, this + /// will be faster than inserting the elements individually. + /// + /// It is up to the caller to make sure that the elements are sorted by key + /// and that there are no duplicates. #[inline] pub fn insert_presorted(&mut self, mut elements: Vec<(K, V)>) { if elements.is_empty() { -- cgit 1.4.1-3-g733a5 From 9a8400c3ffddfe642608c79b2f65b01d7416db2b Mon Sep 17 00:00:00 2001 From: toidiu Date: Thu, 17 May 2018 17:42:02 -0400 Subject: implement Ord for OutlivesPredicate and other types --- src/librustc/hir/mod.rs | 6 ++-- src/librustc/middle/const_val.rs | 2 +- src/librustc/mir/interpret/mod.rs | 8 +++--- src/librustc/mir/interpret/value.rs | 8 +++--- src/librustc/ty/mod.rs | 46 ++++++++++++++++++++++++++++-- src/librustc/ty/sty.rs | 32 ++++++++++----------- src/librustc/ty/subst.rs | 23 +++++++++++++++ src/librustc_data_structures/sorted_map.rs | 3 +- src/librustc_target/abi/mod.rs | 2 +- src/librustc_target/spec/abi.rs | 2 +- src/libsyntax/ast.rs | 2 +- 11 files changed, 100 insertions(+), 34 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index caae79961a6..2b0e17bfb5c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -930,7 +930,7 @@ pub enum PatKind { Slice(HirVec>, Option>, HirVec>), } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum Mutability { MutMutable, MutImmutable, @@ -1523,7 +1523,7 @@ pub struct Destination { pub target_id: Result, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum GeneratorMovability { Static, Movable, @@ -1775,7 +1775,7 @@ pub enum IsAuto { No } -#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq,PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Unsafety { Unsafe, Normal, diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 3a76f75d018..d7f11670511 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -22,7 +22,7 @@ use rustc_data_structures::sync::Lrc; pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; -#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)] pub enum ConstVal<'tcx> { Unevaluated(DefId, &'tcx Substs<'tcx>), Value(ConstValue<'tcx>), diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 9827ee51ba2..48954b1f0aa 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -109,7 +109,7 @@ pub trait PointerArithmetic: layout::HasDataLayout { impl PointerArithmetic for T {} -#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)] pub struct MemoryPointer { pub alloc_id: AllocId, pub offset: Size, @@ -335,7 +335,7 @@ impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> { } } -#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Allocation { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer @@ -384,7 +384,7 @@ impl Allocation { impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {} -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Relocations(SortedMap); impl Relocations { @@ -455,7 +455,7 @@ pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result type Block = u64; const BLOCK_SIZE: u64 = 64; -#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct UndefMask { blocks: Vec, len: Size, diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 5ac2f7f356e..7ad6826b2f6 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -7,7 +7,7 @@ use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation}; /// Represents a constant value in Rust. ByVal and ByValPair are optimizations which /// matches Value's optimizations for easy conversions between these two types -#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)] pub enum ConstValue<'tcx> { /// Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef ByVal(PrimVal), @@ -76,7 +76,7 @@ impl<'tcx> ConstValue<'tcx> { /// For optimization of a few very common cases, there is also a representation for a pair of /// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary /// operations and fat pointers. This idea was taken from rustc's codegen. -#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)] pub enum Value { ByRef(Pointer, Align), ByVal(PrimVal), @@ -99,7 +99,7 @@ impl<'tcx> ty::TypeFoldable<'tcx> for Value { /// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just /// the representation of pointers. Also all the sites that convert between primvals and pointers /// are explicit now (and rare!) -#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)] pub struct Pointer { pub primval: PrimVal, } @@ -194,7 +194,7 @@ impl ::std::convert::From for Pointer { /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes /// of a simple value, a pointer into another `Allocation`, or be undefined. -#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)] pub enum PrimVal { /// The raw bytes of a simple value. Bytes(u128), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b975f9e5195..4507da1c698 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -39,7 +39,7 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use serialize::{self, Encodable, Encoder}; use std::cell::RefCell; -use std::cmp; +use std::cmp::{self, Ordering}; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; @@ -491,6 +491,18 @@ pub struct TyS<'tcx> { region_depth: u32, } +impl<'tcx> Ord for TyS<'tcx> { + fn cmp(&self, other: &TyS<'tcx>) -> Ordering { + self.sty.cmp(&other.sty) + } +} + +impl<'tcx> PartialOrd for TyS<'tcx> { + fn partial_cmp(&self, other: &TyS<'tcx>) -> Option { + Some(self.sty.cmp(&other.sty)) + } +} + impl<'tcx> PartialEq for TyS<'tcx> { #[inline] fn eq(&self, other: &TyS<'tcx>) -> bool { @@ -578,6 +590,22 @@ impl <'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for Ty<'tcx> { #[derive(Debug, RustcEncodable)] pub struct Slice([T]); +impl Ord for Slice where T: Ord { + fn cmp(&self, other: &Slice) -> Ordering { + if self == other { Ordering::Equal } else { + <[T] as Ord>::cmp(&self.0, &other.0) + } + } +} + +impl PartialOrd for Slice where T: PartialOrd { + fn partial_cmp(&self, other: &Slice) -> Option { + if self == other { Some(Ordering::Equal) } else { + <[T] as PartialOrd>::partial_cmp(&self.0, &other.0) + } + } +} + impl PartialEq for Slice { #[inline] fn eq(&self, other: &Slice) -> bool { @@ -1104,7 +1132,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct OutlivesPredicate(pub A, pub B); // `A : B` pub type PolyOutlivesPredicate = ty::Binder>; pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate, @@ -1606,6 +1634,20 @@ pub struct AdtDef { pub repr: ReprOptions, } +impl PartialOrd for AdtDef { + fn partial_cmp(&self, other: &AdtDef) -> Option { + Some(self.cmp(&other)) + } +} + +/// There should be only one AdtDef for each `did`, therefore +/// it is fine to implement `Ord` only based on `did`. +impl Ord for AdtDef { + fn cmp(&self, other: &AdtDef) -> Ordering { + self.did.cmp(&other.did) + } +} + impl PartialEq for AdtDef { // AdtDef are always interned and this is part of TyS equality #[inline] diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d9797bf4985..faf93ab30b7 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -34,7 +34,7 @@ use hir; use self::InferTy::*; use self::TypeVariants::*; -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct TypeAndMut<'tcx> { pub ty: Ty<'tcx>, pub mutbl: hir::Mutability, @@ -80,7 +80,7 @@ impl BoundRegion { /// NB: If you change this, you'll probably want to change the corresponding /// AST structure in libsyntax/ast.rs as well. -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum TypeVariants<'tcx> { /// The primitive boolean type. Written as `bool`. TyBool, @@ -268,7 +268,7 @@ pub enum TypeVariants<'tcx> { /// /// It'd be nice to split this struct into ClosureSubsts and /// GeneratorSubsts, I believe. -nmatsakis -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function, /// concatenated with the types of the upvars. @@ -351,7 +351,7 @@ impl<'tcx> ClosureSubsts<'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct GeneratorSubsts<'tcx> { pub substs: &'tcx Substs<'tcx>, } @@ -484,7 +484,7 @@ impl<'tcx> UpvarSubsts<'tcx> { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum ExistentialPredicate<'tcx> { /// e.g. Iterator Trait(ExistentialTraitRef<'tcx>), @@ -660,7 +660,7 @@ impl<'tcx> PolyTraitRef<'tcx> { /// /// The substitutions don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct ExistentialTraitRef<'tcx> { pub def_id: DefId, pub substs: &'tcx Substs<'tcx>, @@ -728,7 +728,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { /// erase, or otherwise "discharge" these bound regions, we change the /// type from `Binder` to just `T` (see /// e.g. `liberate_late_bound_regions`). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Binder(T); impl Binder { @@ -834,7 +834,7 @@ impl Binder { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `>::N`. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ProjectionTy<'tcx> { /// The parameters of the associated item. pub substs: &'tcx Substs<'tcx>, @@ -902,7 +902,7 @@ impl<'tcx> PolyGenSig<'tcx> { /// - `inputs` is the list of arguments and their modes. /// - `output` is the return type. /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns) -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct FnSig<'tcx> { pub inputs_and_output: &'tcx Slice>, pub variadic: bool, @@ -946,7 +946,7 @@ impl<'tcx> PolyFnSig<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct ParamTy { pub idx: u32, pub name: InternedString, @@ -1148,17 +1148,17 @@ pub struct EarlyBoundRegion { pub name: InternedString, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct TyVid { pub index: u32, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct IntVid { pub index: u32, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct FloatVid { pub index: u32, } @@ -1169,7 +1169,7 @@ newtype_index!(RegionVid DEBUG_FORMAT = custom, }); -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum InferTy { TyVar(TyVid), IntVar(IntVid), @@ -1189,7 +1189,7 @@ pub enum InferTy { newtype_index!(CanonicalVar); /// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExistentialProjection<'tcx> { pub item_def_id: DefId, pub substs: &'tcx Substs<'tcx>, @@ -1758,7 +1758,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } /// Typed constant value. -#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)] pub struct Const<'tcx> { pub ty: Ty<'tcx>, diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index f44e1533f52..2e3c6df9754 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -20,6 +20,7 @@ use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::array_vec::ArrayVec; use core::intrinsics; +use std::cmp::Ordering; use std::fmt; use std::marker::PhantomData; use std::mem; @@ -70,6 +71,28 @@ impl<'tcx> UnpackedKind<'tcx> { } } +impl<'tcx> Ord for Kind<'tcx> { + fn cmp(&self, other: &Kind) -> Ordering { + match (self.unpack(), other.unpack()) { + (UnpackedKind::Type(_), UnpackedKind::Lifetime(_)) => Ordering::Greater, + + (UnpackedKind::Type(ty1), UnpackedKind::Type(ty2)) => { + ty1.sty.cmp(&ty2.sty) + } + + (UnpackedKind::Lifetime(reg1), UnpackedKind::Lifetime(reg2)) => reg1.cmp(reg2), + + (UnpackedKind::Lifetime(_), UnpackedKind::Type(_)) => Ordering::Less, + } + } +} + +impl<'tcx> PartialOrd for Kind<'tcx> { + fn partial_cmp(&self, other: &Kind) -> Option { + Some(self.cmp(&other)) + } +} + impl<'tcx> From> for Kind<'tcx> { fn from(r: ty::Region<'tcx>) -> Kind<'tcx> { UnpackedKind::Lifetime(r).pack() diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index e14bd33c82c..9f1a795b350 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -22,7 +22,8 @@ use std::ops::{RangeBounds, Bound, Index, IndexMut}; /// stores data in a more compact way. It also supports accessing contiguous /// ranges of elements as a slice, and slices of already sorted elements can be /// inserted efficiently. -#[derive(Clone, PartialEq, Eq, Hash, Default, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, RustcEncodable, + RustcDecodable)] pub struct SortedMap { data: Vec<(K,V)> } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 7f593aff21d..4b11de09773 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -332,7 +332,7 @@ impl AddAssign for Size { /// Each field is a power of two, giving the alignment a maximum value /// of 2(28 - 1), which is limited by LLVM to a /// maximum capacity of 229 or 536870912. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Align { abi_pow2: u8, pref_pow2: u8, diff --git a/src/librustc_target/spec/abi.rs b/src/librustc_target/spec/abi.rs index ed2eb209906..927d224389f 100644 --- a/src/librustc_target/spec/abi.rs +++ b/src/librustc_target/spec/abi.rs @@ -10,7 +10,7 @@ use std::fmt; -#[derive(PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Clone, Copy, Debug)] pub enum Abi { // NB: This ordering MUST match the AbiDatas array below. // (This is ensured by the test indices_are_correct().) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 72d5323a872..e1e220f49c9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -667,7 +667,7 @@ pub enum PatKind { Mac(Mac), } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum Mutability { Mutable, Immutable, -- cgit 1.4.1-3-g733a5 From 1440f300d848610b0cb798a735e2c75a94998aa9 Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Thu, 24 May 2018 04:39:35 -0700 Subject: stabilize RangeBounds collections_range #30877 rename RangeBounds::start() -> start_bound() rename RangeBounds::end() -> end_bound() --- src/liballoc/btree/map.rs | 6 +- src/liballoc/string.rs | 8 +- src/liballoc/vec.rs | 4 +- src/liballoc/vec_deque.rs | 4 +- src/libcore/ops/range.rs | 138 +++++++++++------------------ src/librustc_data_structures/array_vec.rs | 4 +- src/librustc_data_structures/sorted_map.rs | 4 +- 7 files changed, 68 insertions(+), 100 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index bb2c68a27ba..28c42144b2a 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1834,7 +1834,7 @@ fn range_search>( Handle, marker::Edge>) where Q: Ord, K: Borrow { - match (range.start(), range.end()) { + match (range.start_bound(), range.end_bound()) { (Excluded(s), Excluded(e)) if s==e => panic!("range start and end are equal and excluded in BTreeMap"), (Included(s), Included(e)) | @@ -1852,7 +1852,7 @@ fn range_search>( let mut diverged = false; loop { - let min_edge = match (min_found, range.start()) { + let min_edge = match (min_found, range.start_bound()) { (false, Included(key)) => match search::search_linear(&min_node, key) { (i, true) => { min_found = true; i }, (i, false) => i, @@ -1866,7 +1866,7 @@ fn range_search>( (true, Excluded(_)) => 0, }; - let max_edge = match (max_found, range.end()) { + let max_edge = match (max_found, range.end_bound()) { (false, Included(key)) => match search::search_linear(&max_node, key) { (i, true) => { max_found = true; i+1 }, (i, false) => i, diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 449e3152d8f..a988b6a26d9 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1493,12 +1493,12 @@ impl String { // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, @@ -1551,12 +1551,12 @@ impl String { // Replace_range does not have the memory safety issues of a vector Splice. // of the vector version. The data is just plain bytes. - match range.start() { + match range.start_bound() { Included(&n) => assert!(self.is_char_boundary(n)), Excluded(&n) => assert!(self.is_char_boundary(n + 1)), Unbounded => {}, }; - match range.end() { + match range.end_bound() { Included(&n) => assert!(self.is_char_boundary(n + 1)), Excluded(&n) => assert!(self.is_char_boundary(n)), Unbounded => {}, diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index c48c64a8bef..b5739e1a825 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1166,12 +1166,12 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index ff82b3a469c..e917a65c9c5 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -980,12 +980,12 @@ impl VecDeque { // and the head/tail values will be restored correctly. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 7c6e2447bdb..01e279589da 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -588,14 +588,12 @@ impl> RangeToInclusive { /// `Bound`s are range endpoints: /// /// ``` -/// #![feature(collections_range)] -/// /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// -/// assert_eq!((..100).start(), Unbounded); -/// assert_eq!((1..12).start(), Included(&1)); -/// assert_eq!((1..12).end(), Excluded(&12)); +/// assert_eq!((..100).start_bound(), Unbounded); +/// assert_eq!((1..12).start_bound(), Included(&1)); +/// assert_eq!((1..12).end_bound(), Excluded(&12)); /// ``` /// /// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. @@ -632,9 +630,7 @@ pub enum Bound { Unbounded, } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] /// `RangeBounds` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. pub trait RangeBounds { @@ -645,17 +641,16 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(collections_range)] - /// /// # fn main() { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// - /// assert_eq!((..10).start(), Unbounded); - /// assert_eq!((3..10).start(), Included(&3)); + /// assert_eq!((..10).start_bound(), Unbounded); + /// assert_eq!((3..10).start_bound(), Included(&3)); /// # } /// ``` - fn start(&self) -> Bound<&T>; + #[stable(feature = "collections_range", since = "1.28.0")] + fn start_bound(&self) -> Bound<&T>; /// End index bound. /// @@ -664,17 +659,16 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(collections_range)] - /// /// # fn main() { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// - /// assert_eq!((3..).end(), Unbounded); - /// assert_eq!((3..10).end(), Excluded(&10)); + /// assert_eq!((3..).end_bound(), Unbounded); + /// assert_eq!((3..10).end_bound(), Excluded(&10)); /// # } /// ``` - fn end(&self) -> Bound<&T>; + #[stable(feature = "collections_range", since = "1.28.0")] + fn end_bound(&self) -> Bound<&T>; /// Returns `true` if `item` is contained in the range. @@ -699,13 +693,13 @@ pub trait RangeBounds { T: PartialOrd, U: ?Sized + PartialOrd, { - (match self.start() { + (match self.start_bound() { Included(ref start) => *start <= item, Excluded(ref start) => *start < item, Unbounded => true, }) && - (match self.end() { + (match self.end_bound() { Included(ref end) => item <= *end, Excluded(ref end) => item < *end, Unbounded => true, @@ -715,83 +709,69 @@ pub trait RangeBounds { use self::Bound::{Excluded, Included, Unbounded}; -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeFull { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeFrom { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeTo { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for Range { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeInclusive { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeToInclusive { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for (Bound, Bound) { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { match *self { (Included(ref start), _) => Included(start), (Excluded(ref start), _) => Excluded(start), @@ -799,7 +779,7 @@ impl RangeBounds for (Bound, Bound) { } } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { match *self { (_, Included(ref end)) => Included(end), (_, Excluded(ref end)) => Excluded(end), @@ -808,75 +788,63 @@ impl RangeBounds for (Bound, Bound) { } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { self.0 } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { self.1 } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeFrom<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeTo<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for Range<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeInclusive<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeToInclusive<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(self.end) } } diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 7b33ee40d8c..56bb9613242 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -119,12 +119,12 @@ impl ArrayVec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index e14bd33c82c..f7e7d6405fc 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -214,7 +214,7 @@ impl SortedMap { fn range_slice_indices(&self, range: R) -> (usize, usize) where R: RangeBounds { - let start = match range.start() { + let start = match range.start_bound() { Bound::Included(ref k) => { match self.lookup_index_for(k) { Ok(index) | Err(index) => index @@ -229,7 +229,7 @@ impl SortedMap { Bound::Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Bound::Included(ref k) => { match self.lookup_index_for(k) { Ok(index) => index + 1, -- cgit 1.4.1-3-g733a5 From 9c548bf26d9f35a92e98bb6a1465135e4cda76d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 May 2018 08:48:02 -0400 Subject: get `rustc_hash` from external crate --- src/Cargo.lock | 28 +++++++++++ src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/fx.rs | 89 ++------------------------------- src/librustc_data_structures/lib.rs | 1 + 4 files changed, 34 insertions(+), 85 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/Cargo.lock b/src/Cargo.lock index 0392466956e..40ec413c90a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -261,6 +261,23 @@ name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chalk-engine" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "chalk-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "chrono" version = "0.4.1" @@ -1739,6 +1756,7 @@ dependencies = [ "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", @@ -1840,6 +1858,11 @@ name = "rustc-demangle" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-hash" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc-main" version = "0.0.0" @@ -1982,6 +2005,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", @@ -2216,6 +2240,7 @@ name = "rustc_traits" version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -2998,6 +3023,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3" "checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a146c19172c7eea48ea55a7123ac95da786639bc665097f1e14034ee5f1d8699" +"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" "checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873" "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" "checksum clippy_lints 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)" = "d2432663f6bdb90255dcf9df5ca504f99b575bb471281591138f62f9d31f863b" @@ -3142,6 +3169,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-syntax 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf9ca2901388714e9ccc7de7281ef06cec55d9f245252ba1d635bc86c730d9a" "checksum rustc-ap-syntax_pos 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5217444369a36e98e11f4ac976f03878704893832e2e0b57d49f2f31438139f" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" +"checksum rustc-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06ddba37baa245040f932b15403071a46681d7e0e4158e230741943c4718b84" "checksum rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1aa5cd8c3a706edb19b6ec6aa7b056bdc635b6e99c5cf7014f9af9d92f15e99" "checksum rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69983f8613a9c3ba1a3bbf5e8bdf2fd5c42317b1d8dd8623ca8030173bf8a6b" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index bb1fb84a0ce..c2b1130b75a 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -17,6 +17,7 @@ cfg-if = "0.1.2" stable_deref_trait = "1.0.0" parking_lot_core = "0.2.8" rustc-rayon = "0.1.0" +rustc-hash = "1.0.0" [dependencies.parking_lot] version = "0.5" diff --git a/src/librustc_data_structures/fx.rs b/src/librustc_data_structures/fx.rs index 5bf25437763..3bf3170d1df 100644 --- a/src/librustc_data_structures/fx.rs +++ b/src/librustc_data_structures/fx.rs @@ -10,11 +10,11 @@ use std::collections::{HashMap, HashSet}; use std::default::Default; -use std::hash::{Hasher, Hash, BuildHasherDefault}; -use std::ops::BitXor; +use std::hash::Hash; -pub type FxHashMap = HashMap>; -pub type FxHashSet = HashSet>; +pub use rustc_hash::FxHashMap; +pub use rustc_hash::FxHashSet; +pub use rustc_hash::FxHasher; #[allow(non_snake_case)] pub fn FxHashMap() -> FxHashMap { @@ -26,84 +26,3 @@ pub fn FxHashSet() -> FxHashSet { HashSet::default() } -/// A speedy hash algorithm for use within rustc. The hashmap in liballoc -/// by default uses SipHash which isn't quite as speedy as we want. In the -/// compiler we're not really worried about DOS attempts, so we use a fast -/// non-cryptographic hash. -/// -/// This is the same as the algorithm used by Firefox -- which is a homespun -/// one not based on any widely-known algorithm -- though modified to produce -/// 64-bit hash values instead of 32-bit hash values. It consistently -/// out-performs an FNV-based hash within rustc itself -- the collision rate is -/// similar or slightly worse than FNV, but the speed of the hash function -/// itself is much higher because it works on up to 8 bytes at a time. -pub struct FxHasher { - hash: usize -} - -#[cfg(target_pointer_width = "32")] -const K: usize = 0x9e3779b9; -#[cfg(target_pointer_width = "64")] -const K: usize = 0x517cc1b727220a95; - -impl Default for FxHasher { - #[inline] - fn default() -> FxHasher { - FxHasher { hash: 0 } - } -} - -impl FxHasher { - #[inline] - fn add_to_hash(&mut self, i: usize) { - self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(K); - } -} - -impl Hasher for FxHasher { - #[inline] - fn write(&mut self, bytes: &[u8]) { - for byte in bytes { - let i = *byte; - self.add_to_hash(i as usize); - } - } - - #[inline] - fn write_u8(&mut self, i: u8) { - self.add_to_hash(i as usize); - } - - #[inline] - fn write_u16(&mut self, i: u16) { - self.add_to_hash(i as usize); - } - - #[inline] - fn write_u32(&mut self, i: u32) { - self.add_to_hash(i as usize); - } - - #[cfg(target_pointer_width = "32")] - #[inline] - fn write_u64(&mut self, i: u64) { - self.add_to_hash(i as usize); - self.add_to_hash((i >> 32) as usize); - } - - #[cfg(target_pointer_width = "64")] - #[inline] - fn write_u64(&mut self, i: u64) { - self.add_to_hash(i as usize); - } - - #[inline] - fn write_usize(&mut self, i: usize) { - self.add_to_hash(i); - } - - #[inline] - fn finish(&self) -> u64 { - self.hash as u64 - } -} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index cd707152af6..e2a80acbd12 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -44,6 +44,7 @@ extern crate parking_lot; extern crate cfg_if; extern crate stable_deref_trait; extern crate rustc_rayon as rayon; +extern crate rustc_hash; // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] -- cgit 1.4.1-3-g733a5 From 7ebd4d637dd9f2e13f3903f87e19932f42d2e0a8 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Thu, 24 May 2018 05:37:40 +0200 Subject: Update rustc-hash to hash up to 8 bytes at once with FxHasher --- src/Cargo.lock | 13 ++++++++----- src/librustc_data_structures/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/Cargo.lock b/src/Cargo.lock index 1371145e487..7dce201505a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -267,7 +267,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1816,7 +1816,7 @@ dependencies = [ "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-rustc_cratesio_shim 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-serialize 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1884,8 +1884,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-hash" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "rustc-main" @@ -2029,7 +2032,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", @@ -3196,7 +3199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-syntax 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "402c1f402e6d47defcd884d3f715aaa8c6f2cbdd5f13cb06fea70486d512426b" "checksum rustc-ap-syntax_pos 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb707a229093791dc3fc35aca61d9bf0e3708f23da4536683527857bc624b061" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" -"checksum rustc-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06ddba37baa245040f932b15403071a46681d7e0e4158e230741943c4718b84" +"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1aa5cd8c3a706edb19b6ec6aa7b056bdc635b6e99c5cf7014f9af9d92f15e99" "checksum rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69983f8613a9c3ba1a3bbf5e8bdf2fd5c42317b1d8dd8623ca8030173bf8a6b" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index c2b1130b75a..15956829ff9 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = "0.1.2" stable_deref_trait = "1.0.0" parking_lot_core = "0.2.8" rustc-rayon = "0.1.0" -rustc-hash = "1.0.0" +rustc-hash = "1.0.1" [dependencies.parking_lot] version = "0.5" -- cgit 1.4.1-3-g733a5 From f46d0213e4825633f182d9b9026b96a7358a1e93 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 May 2018 11:36:31 +1000 Subject: Remove `ObligationForest::cache_list`. It's never used in a meaningful way. --- src/librustc_data_structures/obligation_forest/mod.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 42a17d33fa6..612f44f09cf 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -75,9 +75,6 @@ pub struct ObligationForest { done_cache: FxHashSet, /// An cache of the nodes in `nodes`, indexed by predicate. waiting_cache: FxHashMap, - /// A list of the obligations added in snapshots, to allow - /// for their removal. - cache_list: Vec, scratch: Option>, } @@ -158,7 +155,6 @@ impl ObligationForest { nodes: vec![], done_cache: FxHashSet(), waiting_cache: FxHashMap(), - cache_list: vec![], scratch: Some(vec![]), } } @@ -207,7 +203,6 @@ impl ObligationForest { debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}", obligation, parent, self.nodes.len()); v.insert(NodeIndex::new(self.nodes.len())); - self.cache_list.push(obligation.as_predicate().clone()); self.nodes.push(Node::new(parent, obligation)); Ok(()) } -- cgit 1.4.1-3-g733a5 From a5ffcf6dd830367ccd9b0924c1a1f052330173a2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 May 2018 16:58:48 +1000 Subject: Inline `NodeIndex` methods. Because they are small and hot. --- src/librustc_data_structures/obligation_forest/node_index.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs index 37512e4bcd5..d89bd22ec96 100644 --- a/src/librustc_data_structures/obligation_forest/node_index.rs +++ b/src/librustc_data_structures/obligation_forest/node_index.rs @@ -17,11 +17,13 @@ pub struct NodeIndex { } impl NodeIndex { + #[inline] pub fn new(value: usize) -> NodeIndex { assert!(value < (u32::MAX as usize)); NodeIndex { index: NonZeroU32::new((value as u32) + 1).unwrap() } } + #[inline] pub fn get(self) -> usize { (self.index.get() - 1) as usize } -- cgit 1.4.1-3-g733a5 From f9f90ede826e24a9b314ca7bf0bc04856e11aadb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 28 May 2018 17:43:53 +0200 Subject: Add TinyList data structure. --- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/tiny_list.rs | 251 ++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 src/librustc_data_structures/tiny_list.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index e2a80acbd12..23a920739b9 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -74,6 +74,7 @@ pub mod control_flow_graph; pub mod flock; pub mod sync; pub mod owning_ref; +pub mod tiny_list; pub mod sorted_map; pub struct OnDrop(pub F); diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs new file mode 100644 index 00000000000..3c54805502c --- /dev/null +++ b/src/librustc_data_structures/tiny_list.rs @@ -0,0 +1,251 @@ +// Copyright 2018 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. + + +//! A singly-linked list. +//! +//! Using this data structure only makes sense under very specific +//! circumstances: +//! +//! - If you have a list that rarely stores more than one element, then this +//! data-structure can store the element without allocating and only uses as +//! much space as a `Option<(T, usize)>`. If T can double as the `Option` +//! discriminant, it will even only be as large as `T, usize`. +//! +//! If you expect to store more than 1 element in the common case, steer clear +//! and use a `Vec`, `Box<[T]>`, or a `SmallVec`. + +use std::mem; + +#[derive(Clone, Hash, Debug, PartialEq)] +pub struct TinyList { + head: Option> +} + +impl TinyList { + + #[inline] + pub fn new() -> TinyList { + TinyList { + head: None + } + } + + #[inline] + pub fn new_single(data: T) -> TinyList { + TinyList { + head: Some(Element { + data, + next: None, + }) + } + } + + #[inline] + pub fn insert(&mut self, data: T) { + let current_head = mem::replace(&mut self.head, None); + + if let Some(current_head) = current_head { + let current_head = Box::new(current_head); + self.head = Some(Element { + data, + next: Some(current_head) + }); + } else { + self.head = Some(Element { + data, + next: None, + }) + } + } + + #[inline] + pub fn remove(&mut self, data: &T) -> bool { + let remove_head = if let Some(ref mut head) = self.head { + if head.data == *data { + Some(mem::replace(&mut head.next, None)) + } else { + None + } + } else { + return false + }; + + if let Some(remove_head) = remove_head { + if let Some(next) = remove_head { + self.head = Some(*next); + } else { + self.head = None; + } + return true + } + + self.head.as_mut().unwrap().remove_next(data) + } + + #[inline] + pub fn contains(&self, data: &T) -> bool { + if let Some(ref head) = self.head { + head.contains(data) + } else { + false + } + } + + #[inline] + pub fn len(&self) -> usize { + if let Some(ref head) = self.head { + head.len() + } else { + 0 + } + } +} + +#[derive(Clone, Hash, Debug, PartialEq)] +struct Element { + data: T, + next: Option>>, +} + +impl Element { + + fn remove_next(&mut self, data: &T) -> bool { + let new_next = if let Some(ref mut next) = self.next { + if next.data != *data { + return next.remove_next(data) + } else { + mem::replace(&mut next.next, None) + } + } else { + return false + }; + + self.next = new_next; + return true + } + + fn len(&self) -> usize { + if let Some(ref next) = self.next { + 1 + next.len() + } else { + 1 + } + } + + fn contains(&self, data: &T) -> bool { + if self.data == *data { + return true + } + + if let Some(ref next) = self.next { + next.contains(data) + } else { + false + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_contains_and_insert() { + fn do_insert(i : u32) -> bool { + i % 2 == 0 + } + + let mut list = TinyList::new(); + + for i in 0 .. 10 { + for j in 0 .. i { + if do_insert(j) { + assert!(list.contains(&j)); + } else { + assert!(!list.contains(&j)); + } + } + + assert!(!list.contains(i)); + + if do_insert(i) { + list.insert(i); + assert!(list.contains(&i)); + } + } + } + + #[test] + fn test_remove_first() { + let mut list = TinyList::new(); + list.insert(1); + list.insert(2); + list.insert(3); + list.insert(4); + assert_eq!(list.len(), 4); + + assert!(list.remove(&4)); + assert!(!list.contains(&4)); + + assert_eq!(list.len(), 3); + assert!(list.contains(&1)); + assert!(list.contains(&2)); + assert!(list.contains(&3)); + } + + #[test] + fn test_remove_last() { + let mut list = TinyList::new(); + list.insert(1); + list.insert(2); + list.insert(3); + list.insert(4); + assert_eq!(list.len(), 4); + + assert!(list.remove(&1)); + assert!(!list.contains(&1)); + + assert_eq!(list.len(), 3); + assert!(list.contains(&2)); + assert!(list.contains(&3)); + assert!(list.contains(&4)); + } + + #[test] + fn test_remove_middle() { + let mut list = TinyList::new(); + list.insert(1); + list.insert(2); + list.insert(3); + list.insert(4); + assert_eq!(list.len(), 4); + + assert!(list.remove(&2)); + assert!(!list.contains(&2)); + + assert_eq!(list.len(), 3); + assert!(list.contains(&1)); + assert!(list.contains(&3)); + assert!(list.contains(&4)); + } + + #[test] + fn test_remove_single() { + let mut list = TinyList::new(); + list.insert(1); + assert_eq!(list.len(), 1); + + assert!(list.remove(&1)); + assert!(!list.contains(&1)); + + assert_eq!(list.len(), 0); + } +} -- cgit 1.4.1-3-g733a5 From 24dfcbef9c28158385f0cf526fd650f2d8a05064 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 25 May 2018 17:19:31 +0200 Subject: Make const decoding from the incremental cache thread-safe. --- src/librustc/lib.rs | 1 + src/librustc/mir/interpret/mod.rs | 169 ++++++++++++++++++++++++++++++ src/librustc/ty/maps/on_disk_cache.rs | 51 ++------- src/librustc_data_structures/tiny_list.rs | 2 +- 4 files changed, 181 insertions(+), 42 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index da6340b5f61..10e8905054d 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -68,6 +68,7 @@ #![feature(trace_macros)] #![feature(trusted_len)] #![feature(catch_expr)] +#![feature(integer_atomics)] #![feature(test)] #![feature(in_band_lifetimes)] #![feature(macro_at_most_once_rep)] diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index b41652469ae..11dd6d1389a 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -26,7 +26,12 @@ use syntax::ast::Mutability; use rustc_serialize::{Encoder, Decoder, Decodable, Encodable}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{Lock as Mutex, HashMapExt}; +use rustc_data_structures::tiny_list::TinyList; use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; +use ty::codec::TyDecoder; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::num::NonZeroU32; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum Lock { @@ -245,6 +250,166 @@ pub fn specialized_decode_alloc_id< } } +// Used to avoid infinite recursion when decoding cyclic allocations. +type DecodingSessionId = NonZeroU32; + +#[derive(Clone)] +enum State { + Empty, + InProgressNonAlloc(TinyList), + InProgress(TinyList, AllocId), + Done(AllocId), +} + +pub struct AllocDecodingState { + // For each AllocId we keep track of which decoding state it's currently in. + decoding_state: Vec>, + // The offsets of each allocation in the data stream. + data_offsets: Vec, +} + +impl AllocDecodingState { + + pub fn new_decoding_session(&self) -> AllocDecodingSession { + static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0); + let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst); + + // Make sure this is never zero + let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap(); + + AllocDecodingSession { + state: self, + session_id, + } + } + + pub fn new(data_offsets: Vec) -> AllocDecodingState { + let decoding_state: Vec<_> = ::std::iter::repeat(Mutex::new(State::Empty)) + .take(data_offsets.len()) + .collect(); + + AllocDecodingState { + decoding_state: decoding_state, + data_offsets, + } + } +} + +#[derive(Copy, Clone)] +pub struct AllocDecodingSession<'s> { + state: &'s AllocDecodingState, + session_id: DecodingSessionId, +} + +impl<'s> AllocDecodingSession<'s> { + + // Decodes an AllocId in a thread-safe way. + pub fn decode_alloc_id<'a, 'tcx, D>(&self, + decoder: &mut D) + -> Result + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, + { + // Read the index of the allocation + let idx = decoder.read_u32()? as usize; + let pos = self.state.data_offsets[idx] as usize; + + // Decode the AllocKind now so that we know if we have to reserve an + // AllocId. + let (alloc_kind, pos) = decoder.with_position(pos, |decoder| { + let alloc_kind = AllocKind::decode(decoder)?; + Ok((alloc_kind, decoder.position())) + })?; + + // Check the decoding state, see if it's already decoded or if we should + // decode it here. + let alloc_id = { + let mut entry = self.state.decoding_state[idx].lock(); + + match *entry { + State::Done(alloc_id) => { + return Ok(alloc_id); + } + ref mut entry @ State::Empty => { + // We are allowed to decode + match alloc_kind { + AllocKind::Alloc => { + // If this is an allocation, we need to reserve an + // AllocId so we can decode cyclic graphs. + let alloc_id = decoder.tcx().alloc_map.lock().reserve(); + *entry = State::InProgress( + TinyList::new_single(self.session_id), + alloc_id); + Some(alloc_id) + }, + AllocKind::Fn | AllocKind::Static => { + // Fns and statics cannot be cyclic and their AllocId + // is determined later by interning + *entry = State::InProgressNonAlloc( + TinyList::new_single(self.session_id)); + None + } + } + } + State::InProgressNonAlloc(ref mut sessions) => { + if sessions.contains(&self.session_id) { + bug!("This should be unreachable") + } else { + // Start decoding concurrently + sessions.insert(self.session_id); + None + } + } + State::InProgress(ref mut sessions, alloc_id) => { + if sessions.contains(&self.session_id) { + // Don't recurse. + return Ok(alloc_id) + } else { + // Start decoding concurrently + sessions.insert(self.session_id); + Some(alloc_id) + } + } + } + }; + + // Now decode the actual data + let alloc_id = decoder.with_position(pos, |decoder| { + match alloc_kind { + AllocKind::Alloc => { + let allocation = <&'tcx Allocation as Decodable>::decode(decoder)?; + // We already have a reserved AllocId. + let alloc_id = alloc_id.unwrap(); + trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); + decoder.tcx().alloc_map.lock().set_id_same_memory(alloc_id, allocation); + Ok(alloc_id) + }, + AllocKind::Fn => { + assert!(alloc_id.is_none()); + trace!("creating fn alloc id"); + let instance = ty::Instance::decode(decoder)?; + trace!("decoded fn alloc instance: {:?}", instance); + let alloc_id = decoder.tcx().alloc_map.lock().create_fn_alloc(instance); + Ok(alloc_id) + }, + AllocKind::Static => { + assert!(alloc_id.is_none()); + trace!("creating extern static alloc id at"); + let did = DefId::decode(decoder)?; + let alloc_id = decoder.tcx().alloc_map.lock().intern_static(did); + Ok(alloc_id) + } + } + })?; + + self.state.decoding_state[idx].with_lock(|entry| { + *entry = State::Done(alloc_id); + }); + + Ok(alloc_id) + } +} + impl fmt::Display for AllocId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) @@ -340,6 +505,10 @@ impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> { bug!("tried to set allocation id {}, but it was already existing as {:#?}", id, old); } } + + pub fn set_id_same_memory(&mut self, id: AllocId, mem: M) { + self.id_to_type.insert_same(id, AllocType::Memory(mem)); + } } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 9ca90a06c4e..cd317ff6cdb 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -16,6 +16,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, use hir::map::definitions::DefPathHash; use ich::{CachingCodemapView, Fingerprint}; use mir::{self, interpret}; +use mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -23,7 +24,6 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, SpecializedDecoder, SpecializedEncoder, UseSpecializedDecodable, UseSpecializedEncodable}; use session::{CrateDisambiguator, Session}; -use std::cell::RefCell; use std::mem; use syntax::ast::NodeId; use syntax::codemap::{CodeMap, StableFilemapId}; @@ -77,11 +77,7 @@ pub struct OnDiskCache<'sess> { // `serialized_data`. prev_diagnostics_index: FxHashMap, - // Alloc indices to memory location map - prev_interpret_alloc_index: Vec, - - /// Deserialization: A cache to ensure we don't read allocations twice - interpret_alloc_cache: RefCell>, + alloc_decoding_state: AllocDecodingState, } // This type is used only for (de-)serialization. @@ -92,7 +88,7 @@ struct Footer { query_result_index: EncodedQueryResultIndex, diagnostics_index: EncodedQueryResultIndex, // the location of all allocations - interpret_alloc_index: Vec, + interpret_alloc_index: Vec, } type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; @@ -149,8 +145,7 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: footer.query_result_index.into_iter().collect(), prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), synthetic_expansion_infos: Lock::new(FxHashMap()), - prev_interpret_alloc_index: footer.interpret_alloc_index, - interpret_alloc_cache: RefCell::new(FxHashMap::default()), + alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), } } @@ -166,8 +161,7 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: FxHashMap(), prev_diagnostics_index: FxHashMap(), synthetic_expansion_infos: Lock::new(FxHashMap()), - prev_interpret_alloc_index: Vec::new(), - interpret_alloc_cache: RefCell::new(FxHashMap::default()), + alloc_decoding_state: AllocDecodingState::new(Vec::new()), } } @@ -291,7 +285,7 @@ impl<'sess> OnDiskCache<'sess> { } for idx in n..new_n { let id = encoder.interpret_allocs_inverse[idx]; - let pos = AbsoluteBytePos::new(encoder.position()); + let pos = encoder.position() as u32; interpret_alloc_index.push(pos); interpret::specialized_encode_alloc_id( &mut encoder, @@ -424,8 +418,7 @@ impl<'sess> OnDiskCache<'sess> { file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, synthetic_expansion_infos: &self.synthetic_expansion_infos, - prev_interpret_alloc_index: &self.prev_interpret_alloc_index, - interpret_alloc_cache: &self.interpret_alloc_cache, + alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), }; match decode_tagged(&mut decoder, dep_node_index) { @@ -487,9 +480,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { synthetic_expansion_infos: &'x Lock>, file_index_to_file: &'x Lock>>, file_index_to_stable_id: &'x FxHashMap, - interpret_alloc_cache: &'x RefCell>, - /// maps from index in the cache file to location in the cache file - prev_interpret_alloc_index: &'x [AbsoluteBytePos], + alloc_decoding_session: AllocDecodingSession<'x>, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { @@ -612,30 +603,8 @@ implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { - let tcx = self.tcx; - let idx = usize::decode(self)?; - trace!("loading index {}", idx); - - if let Some(cached) = self.interpret_alloc_cache.borrow().get(&idx).cloned() { - trace!("loading alloc id {:?} from alloc_cache", cached); - return Ok(cached); - } - let pos = self.prev_interpret_alloc_index[idx].to_usize(); - trace!("loading position {}", pos); - self.with_position(pos, |this| { - interpret::specialized_decode_alloc_id( - this, - tcx, - |this, alloc_id| { - trace!("caching idx {} for alloc id {} at position {}", idx, alloc_id, pos); - assert!(this - .interpret_alloc_cache - .borrow_mut() - .insert(idx, alloc_id) - .is_none()); - }, - ) - }) + let alloc_decoding_session = self.alloc_decoding_session; + alloc_decoding_session.decode_alloc_id(self) } } impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index 3c54805502c..5b1b2aadec5 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -174,7 +174,7 @@ mod test { } } - assert!(!list.contains(i)); + assert!(!list.contains(&i)); if do_insert(i) { list.insert(i); -- cgit 1.4.1-3-g733a5 From d6c63ec949c09e30f89f4bc63b42f7822c197b2b Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Fri, 20 Apr 2018 23:50:10 +0200 Subject: Fix OneThread --- src/librustc_data_structures/sync.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 36617631330..9cceee65bf9 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -36,7 +36,6 @@ use std::marker::PhantomData; use std::fmt::Debug; use std::fmt::Formatter; use std::fmt; -use std; use std::ops::{Deref, DerefMut}; use owning_ref::{Erased, OwningRef}; @@ -200,6 +199,7 @@ cfg_if! { use parking_lot::Mutex as InnerLock; use parking_lot::RwLock as InnerRwLock; + use std; use std::thread; pub use rayon::{join, scope}; @@ -638,7 +638,9 @@ pub struct OneThread { inner: T, } +#[cfg(parallel_queries)] unsafe impl std::marker::Sync for OneThread {} +#[cfg(parallel_queries)] unsafe impl std::marker::Send for OneThread {} impl OneThread { -- cgit 1.4.1-3-g733a5 From 969296b79b22363c67b1e6786bd115ced881210f Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Fri, 11 May 2018 16:28:28 +0200 Subject: Add a WorkerLocal abstraction --- src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/sync.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 15956829ff9..17ee771e529 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -17,6 +17,7 @@ cfg-if = "0.1.2" stable_deref_trait = "1.0.0" parking_lot_core = "0.2.8" rustc-rayon = "0.1.0" +rustc-rayon-core = "0.1.0" rustc-hash = "1.0.1" [dependencies.parking_lot] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 23a920739b9..7046a2a2a49 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -44,6 +44,7 @@ extern crate parking_lot; extern crate cfg_if; extern crate stable_deref_trait; extern crate rustc_rayon as rayon; +extern crate rustc_rayon_core as rayon_core; extern crate rustc_hash; // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 9cceee65bf9..6f7d9e1b54b 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -99,6 +99,33 @@ cfg_if! { use std::cell::Cell; + #[derive(Debug)] + pub struct WorkerLocal(OneThread); + + impl WorkerLocal { + /// Creates a new worker local where the `initial` closure computes the + /// value this worker local should take for each thread in the thread pool. + #[inline] + pub fn new T>(mut f: F) -> WorkerLocal { + WorkerLocal(OneThread::new(f(0))) + } + + /// Returns the worker-local value for each thread + #[inline] + pub fn into_inner(self) -> Vec { + vec![OneThread::into_inner(self.0)] + } + } + + impl Deref for WorkerLocal { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &*self.0 + } + } + #[derive(Debug)] pub struct MTLock(T); @@ -203,6 +230,8 @@ cfg_if! { use std::thread; pub use rayon::{join, scope}; + pub use rayon_core::WorkerLocal; + pub use rayon::iter::ParallelIterator; use rayon::iter::IntoParallelIterator; -- cgit 1.4.1-3-g733a5 From d85b5eadeaca624b886838787150adbdfdb1dcbe Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Mon, 14 May 2018 03:00:52 +0200 Subject: Update Rayon version --- src/librustc/Cargo.toml | 4 ++-- src/librustc_data_structures/Cargo.toml | 4 ++-- src/librustc_driver/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 4dc818c650e..0ff4dc2eace 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -19,8 +19,8 @@ scoped-tls = { version = "0.1.1", features = ["nightly"] } log = { version = "0.4", features = ["release_max_level_info", "std"] } polonius-engine = "0.5.0" proc_macro = { path = "../libproc_macro" } -rustc-rayon = "0.1.0" -rustc-rayon-core = "0.1.0" +rustc-rayon = "0.1.1" +rustc-rayon-core = "0.1.1" rustc_apfloat = { path = "../librustc_apfloat" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 17ee771e529..fc5fe91c977 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -16,8 +16,8 @@ serialize = { path = "../libserialize" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" parking_lot_core = "0.2.8" -rustc-rayon = "0.1.0" -rustc-rayon-core = "0.1.0" +rustc-rayon = "0.1.1" +rustc-rayon-core = "0.1.1" rustc-hash = "1.0.1" [dependencies.parking_lot] diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 24bf07d793f..5b75912c18f 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -13,7 +13,7 @@ arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } log = "0.4" env_logger = { version = "0.5", default-features = false } -rustc-rayon = "0.1.0" +rustc-rayon = "0.1.1" scoped-tls = { version = "0.1.1", features = ["nightly"] } rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } -- cgit 1.4.1-3-g733a5 From 77259af56ab337d476cafeeb657c9b8953f8b75b Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Sun, 27 May 2018 07:46:19 +0200 Subject: Use try_lock in collect_active_jobs --- src/librustc/ty/maps/plumbing.rs | 4 +++- src/librustc_data_structures/sync.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 2ab8d18e3e7..13d2a13e5dd 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -659,7 +659,9 @@ macro_rules! define_maps { pub fn collect_active_jobs(&self) -> Vec>> { let mut jobs = Vec::new(); - $(for v in self.$name.lock().active.values() { + // We use try_lock here since we are only called from the + // deadlock handler, and this shouldn't be locked + $(for v in self.$name.try_lock().unwrap().active.values() { match *v { QueryResult::Started(ref job) => jobs.push(job.clone()), _ => (), diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 6f7d9e1b54b..33f6eda2a87 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -519,6 +519,18 @@ impl Lock { self.0.get_mut() } + #[cfg(parallel_queries)] + #[inline(always)] + pub fn try_lock(&self) -> Option> { + self.0.try_lock() + } + + #[cfg(not(parallel_queries))] + #[inline(always)] + pub fn try_lock(&self) -> Option> { + self.0.try_borrow_mut().ok() + } + #[cfg(parallel_queries)] #[inline(always)] pub fn lock(&self) -> LockGuard { -- cgit 1.4.1-3-g733a5 From 090b8341bcd1eb7de3d0cbaa71eb2d77924fc4bc Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Sun, 27 May 2018 07:47:44 +0200 Subject: Add and use OnDrop::disable --- src/librustc/ty/maps/job.rs | 2 +- src/librustc_data_structures/lib.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/ty/maps/job.rs b/src/librustc/ty/maps/job.rs index 3fe22dba6e1..6b7170f2c47 100644 --- a/src/librustc/ty/maps/job.rs +++ b/src/librustc/ty/maps/job.rs @@ -456,5 +456,5 @@ fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) { waiter.notify(tcx, registry); } - mem::forget(on_panic); + on_panic.disable(); } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 7046a2a2a49..5844edf000a 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -80,6 +80,14 @@ pub mod sorted_map; pub struct OnDrop(pub F); +impl OnDrop { + /// Forgets the function which prevents it from running. + /// Ensure that the function owns no memory, otherwise it will be leaked. + pub fn disable(self) { + std::mem::forget(self); + } +} + impl Drop for OnDrop { fn drop(&mut self) { (self.0)(); -- cgit 1.4.1-3-g733a5 From c83d152ebae3667e5545245acbe1b14bf0b74236 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 7 Jun 2018 15:06:22 +1000 Subject: Introduce `ProcessResult`. A tri-valued enum is nicer than Result>, and it's slightly faster. --- src/librustc/traits/fulfill.rs | 78 ++++++++-------- .../obligation_forest/mod.rs | 24 +++-- .../obligation_forest/test.rs | 100 ++++++++++----------- 3 files changed, 107 insertions(+), 95 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 68ad1e665ad..78ebd2d1390 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -12,8 +12,8 @@ use infer::{RegionObligation, InferCtxt}; use mir::interpret::GlobalId; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate}; use ty::error::ExpectedFound; -use rustc_data_structures::obligation_forest::{ObligationForest, Error}; -use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; +use rustc_data_structures::obligation_forest::{Error, ForestObligation, ObligationForest}; +use rustc_data_structures::obligation_forest::{ObligationProcessor, ProcessResult}; use std::marker::PhantomData; use hir::def_id::DefId; use middle::const_val::{ConstEvalErr, ErrKind}; @@ -263,16 +263,16 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, type Error = FulfillmentErrorCode<'tcx>; /// Processes a predicate obligation and returns either: - /// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true - /// - `Ok(None)` if we don't have enough info to be sure - /// - `Err` if the predicate does not hold + /// - `Changed(v)` if the predicate is true, presuming that `v` are also true + /// - `Unchanged` if we don't have enough info to be sure + /// - `Error(e)` if the predicate does not hold /// /// This is always inlined, despite its size, because it has a single /// callsite and it is called *very* frequently. #[inline(always)] fn process_obligation(&mut self, pending_obligation: &mut Self::Obligation) - -> Result>, Self::Error> + -> ProcessResult { // if we were stalled on some unresolved variables, first check // whether any of them have been resolved; if not, don't bother @@ -286,7 +286,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, self.selcx.infcx() .resolve_type_vars_if_possible(&pending_obligation.obligation), pending_obligation.stalled_on); - return Ok(None); + return ProcessResult::Unchanged; } pending_obligation.stalled_on = vec![]; } @@ -308,7 +308,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, if self.selcx.infcx().predicate_must_hold(&obligation) { debug!("selecting trait `{:?}` at depth {} evaluated to holds", data, obligation.recursion_depth); - return Ok(Some(vec![])) + return ProcessResult::Changed(vec![]) } } @@ -316,7 +316,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, Ok(Some(vtable)) => { debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)", data, obligation.recursion_depth); - Ok(Some(mk_pending(vtable.nested_obligations()))) + ProcessResult::Changed(mk_pending(vtable.nested_obligations())) } Ok(None) => { debug!("selecting trait `{:?}` at depth {} yielded Ok(None)", @@ -342,21 +342,21 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, self.selcx.infcx().resolve_type_vars_if_possible(obligation), pending_obligation.stalled_on); - Ok(None) + ProcessResult::Unchanged } Err(selection_err) => { info!("selecting trait `{:?}` at depth {} yielded Err", data, obligation.recursion_depth); - Err(CodeSelectionError(selection_err)) + ProcessResult::Error(CodeSelectionError(selection_err)) } } } ty::Predicate::RegionOutlives(ref binder) => { match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { - Ok(()) => Ok(Some(Vec::new())), - Err(_) => Err(CodeSelectionError(Unimplemented)), + Ok(()) => ProcessResult::Changed(vec![]), + Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), } } @@ -373,7 +373,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, // If so, this obligation is an error (for now). Eventually we should be // able to support additional cases here, like `for<'a> &'a str: 'a`. None => { - Err(CodeSelectionError(Unimplemented)) + ProcessResult::Error(CodeSelectionError(Unimplemented)) } // Otherwise, we have something of the form // `for<'a> T: 'a where 'a not in T`, which we can treat as @@ -389,7 +389,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, cause: obligation.cause.clone(), }); } - Ok(Some(vec![])) + ProcessResult::Changed(vec![]) } } } @@ -404,7 +404,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, cause: obligation.cause.clone() }); } - Ok(Some(vec![])) + ProcessResult::Changed(vec![]) } } } @@ -416,18 +416,18 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, let tcx = self.selcx.tcx(); pending_obligation.stalled_on = trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx)); - Ok(None) + ProcessResult::Unchanged } - Ok(Some(os)) => Ok(Some(mk_pending(os))), - Err(e) => Err(CodeProjectionError(e)) + Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)), + Err(e) => ProcessResult::Error(CodeProjectionError(e)) } } ty::Predicate::ObjectSafe(trait_def_id) => { if !self.selcx.tcx().is_object_safe(trait_def_id) { - Err(CodeSelectionError(Unimplemented)) + ProcessResult::Error(CodeSelectionError(Unimplemented)) } else { - Ok(Some(Vec::new())) + ProcessResult::Changed(vec![]) } } @@ -435,13 +435,13 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, match self.selcx.infcx().closure_kind(closure_def_id, closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { - Ok(Some(vec![])) + ProcessResult::Changed(vec![]) } else { - Err(CodeSelectionError(Unimplemented)) + ProcessResult::Error(CodeSelectionError(Unimplemented)) } } None => { - Ok(None) + ProcessResult::Unchanged } } } @@ -453,9 +453,9 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, ty, obligation.cause.span) { None => { pending_obligation.stalled_on = vec![ty]; - Ok(None) + ProcessResult::Unchanged } - Some(os) => Ok(Some(mk_pending(os))) + Some(os) => ProcessResult::Changed(mk_pending(os)) } } @@ -467,16 +467,17 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, // None means that both are unresolved. pending_obligation.stalled_on = vec![subtype.skip_binder().a, subtype.skip_binder().b]; - Ok(None) + ProcessResult::Unchanged } Some(Ok(ok)) => { - Ok(Some(mk_pending(ok.obligations))) + ProcessResult::Changed(mk_pending(ok.obligations)) } Some(Err(err)) => { let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected, subtype.skip_binder().a, subtype.skip_binder().b); - Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) + ProcessResult::Error( + FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) } } } @@ -484,7 +485,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, ty::Predicate::ConstEvaluatable(def_id, substs) => { match self.selcx.tcx().lift_to_global(&obligation.param_env) { None => { - Ok(None) + ProcessResult::Unchanged } Some(param_env) => { match self.selcx.tcx().lift_to_global(&substs) { @@ -502,19 +503,22 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, }; match self.selcx.tcx().at(obligation.cause.span) .const_eval(param_env.and(cid)) { - Ok(_) => Ok(Some(vec![])), - Err(err) => Err(CodeSelectionError(ConstEvalFailure(err))) + Ok(_) => ProcessResult::Changed(vec![]), + Err(err) => ProcessResult::Error( + CodeSelectionError(ConstEvalFailure(err))) } } else { - Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr { - span: obligation.cause.span, - kind: ErrKind::CouldNotResolve.into(), - }))) + ProcessResult::Error( + CodeSelectionError(ConstEvalFailure(ConstEvalErr { + span: obligation.cause.span, + kind: ErrKind::CouldNotResolve.into(), + })) + ) } }, None => { pending_obligation.stalled_on = substs.types().collect(); - Ok(None) + ProcessResult::Unchanged } } } diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 612f44f09cf..1378f46b64c 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -41,7 +41,7 @@ pub trait ObligationProcessor { fn process_obligation(&mut self, obligation: &mut Self::Obligation) - -> Result>, Self::Error>; + -> ProcessResult; /// As we do the cycle check, we invoke this callback when we /// encounter an actual cycle. `cycle` is an iterator that starts @@ -57,6 +57,14 @@ pub trait ObligationProcessor { where I: Clone + Iterator; } +/// The result type used by `process_obligation`. +#[derive(Debug)] +pub enum ProcessResult { + Unchanged, + Changed(Vec), + Error(E), +} + pub struct ObligationForest { /// The list of obligations. In between calls to /// `process_obligations`, this list only contains nodes in the @@ -136,8 +144,8 @@ pub struct Outcome { /// If true, then we saw no successful obligations, which means /// there is no point in further iteration. This is based on the - /// assumption that when trait matching returns `Err` or - /// `Ok(None)`, those results do not affect environmental + /// assumption that when trait matching returns `Error` or + /// `Unchanged`, those results do not affect environmental /// inference state. (Note that if we invoke `process_obligations` /// with no pending obligations, stalled will be true.) pub stalled: bool, @@ -270,11 +278,11 @@ impl ObligationForest { result); match result { - Ok(None) => { - // no change in state + ProcessResult::Unchanged => { + // No change in state. } - Ok(Some(children)) => { - // if we saw a Some(_) result, we are not (yet) stalled + ProcessResult::Changed(children) => { + // We are not (yet) stalled. stalled = false; self.nodes[index].state.set(NodeState::Success); @@ -290,7 +298,7 @@ impl ObligationForest { } } } - Err(err) => { + ProcessResult::Error(err) => { stalled = false; let backtrace = self.error_at(index); errors.push(Error { diff --git a/src/librustc_data_structures/obligation_forest/test.rs b/src/librustc_data_structures/obligation_forest/test.rs index a95b2b84b34..527a1ef0ec4 100644 --- a/src/librustc_data_structures/obligation_forest/test.rs +++ b/src/librustc_data_structures/obligation_forest/test.rs @@ -10,7 +10,7 @@ #![cfg(test)] -use super::{ObligationForest, ObligationProcessor, Outcome, Error}; +use super::{Error, ObligationForest, ObligationProcessor, Outcome, ProcessResult}; use std::fmt; use std::marker::PhantomData; @@ -31,7 +31,7 @@ struct ClosureObligationProcessor { #[allow(non_snake_case)] fn C(of: OF, bf: BF) -> ClosureObligationProcessor - where OF: FnMut(&mut O) -> Result>, &'static str>, + where OF: FnMut(&mut O) -> ProcessResult, BF: FnMut(&[O]) { ClosureObligationProcessor { @@ -44,7 +44,7 @@ fn C(of: OF, bf: BF) -> ClosureObligationProcessor ObligationProcessor for ClosureObligationProcessor where O: super::ForestObligation + fmt::Debug, E: fmt::Debug, - OF: FnMut(&mut O) -> Result>, E>, + OF: FnMut(&mut O) -> ProcessResult, BF: FnMut(&[O]) { type Obligation = O; @@ -52,7 +52,7 @@ impl ObligationProcessor for ClosureObligationProcessor Result>, Self::Error> + -> ProcessResult { (self.process_obligation)(obligation) } @@ -78,9 +78,9 @@ fn push_pop() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), - "B" => Err("B is for broken"), - "C" => Ok(Some(vec![])), + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), + "B" => ProcessResult::Error("B is for broken"), + "C" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_| {})); @@ -101,10 +101,10 @@ fn push_pop() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.1" => Ok(None), - "A.2" => Ok(None), - "A.3" => Ok(Some(vec!["A.3.i"])), - "D" => Ok(Some(vec!["D.1", "D.2"])), + "A.1" => ProcessResult::Unchanged, + "A.2" => ProcessResult::Unchanged, + "A.3" => ProcessResult::Changed(vec!["A.3.i"]), + "D" => ProcessResult::Changed(vec!["D.1", "D.2"]), _ => unreachable!(), } }, |_| {})); @@ -119,11 +119,11 @@ fn push_pop() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.1" => Ok(Some(vec![])), - "A.2" => Err("A is for apple"), - "A.3.i" => Ok(Some(vec![])), - "D.1" => Ok(Some(vec!["D.1.i"])), - "D.2" => Ok(Some(vec!["D.2.i"])), + "A.1" => ProcessResult::Changed(vec![]), + "A.2" => ProcessResult::Error("A is for apple"), + "A.3.i" => ProcessResult::Changed(vec![]), + "D.1" => ProcessResult::Changed(vec!["D.1.i"]), + "D.2" => ProcessResult::Changed(vec!["D.2.i"]), _ => unreachable!(), } }, |_| {})); @@ -138,8 +138,8 @@ fn push_pop() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D.1.i" => Err("D is for dumb"), - "D.2.i" => Ok(Some(vec![])), + "D.1.i" => ProcessResult::Error("D is for dumb"), + "D.2.i" => ProcessResult::Changed(vec![]), _ => panic!("unexpected obligation {:?}", obligation), } }, |_| {})); @@ -167,7 +167,7 @@ fn success_in_grandchildren() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), _ => unreachable!(), } }, |_| {})); @@ -177,9 +177,9 @@ fn success_in_grandchildren() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.1" => Ok(Some(vec![])), - "A.2" => Ok(Some(vec!["A.2.i", "A.2.ii"])), - "A.3" => Ok(Some(vec![])), + "A.1" => ProcessResult::Changed(vec![]), + "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]), + "A.3" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_| {})); @@ -189,8 +189,8 @@ fn success_in_grandchildren() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.2.i" => Ok(Some(vec!["A.2.i.a"])), - "A.2.ii" => Ok(Some(vec![])), + "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]), + "A.2.ii" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_| {})); @@ -200,7 +200,7 @@ fn success_in_grandchildren() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.2.i.a" => Ok(Some(vec![])), + "A.2.i.a" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_| {})); @@ -223,7 +223,7 @@ fn to_errors_no_throw() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), _ => unreachable!(), } }, |_|{})); @@ -244,7 +244,7 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2"])), + "A" => ProcessResult::Changed(vec!["A.1", "A.2"]), _ => unreachable!(), } }, |_|{})); @@ -254,8 +254,8 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.1" => Ok(Some(vec!["D"])), - "A.2" => Ok(Some(vec!["D"])), + "A.1" => ProcessResult::Changed(vec!["D"]), + "A.2" => ProcessResult::Changed(vec!["D"]), _ => unreachable!(), } }, |_|{})); @@ -266,7 +266,7 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D" => { d_count += 1; Ok(Some(vec![])) }, + "D" => { d_count += 1; ProcessResult::Changed(vec![]) }, _ => unreachable!(), } }, |_|{})); @@ -281,7 +281,7 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A'" => Ok(Some(vec!["A'.1", "A'.2"])), + "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]), _ => unreachable!(), } }, |_|{})); @@ -291,8 +291,8 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A'.1" => Ok(Some(vec!["D'", "A'"])), - "A'.2" => Ok(Some(vec!["D'"])), + "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]), + "A'.2" => ProcessResult::Changed(vec!["D'"]), _ => unreachable!(), } }, |_|{})); @@ -303,7 +303,7 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D'" => { d_count += 1; Err("operation failed") }, + "D'" => { d_count += 1; ProcessResult::Error("operation failed") }, _ => unreachable!(), } }, |_|{})); @@ -329,7 +329,7 @@ fn done_dependency() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A: Sized" | "B: Sized" | "C: Sized" => Ok(Some(vec![])), + "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_|{})); @@ -340,11 +340,11 @@ fn done_dependency() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "(A,B,C): Sized" => Ok(Some(vec![ + "(A,B,C): Sized" => ProcessResult::Changed(vec![ "A: Sized", "B: Sized", "C: Sized" - ])), + ]), _ => unreachable!(), } }, |_|{})); @@ -367,10 +367,10 @@ fn orphan() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["D", "E"])), - "B" => Ok(None), - "C1" => Ok(Some(vec![])), - "C2" => Ok(Some(vec![])), + "A" => ProcessResult::Changed(vec!["D", "E"]), + "B" => ProcessResult::Unchanged, + "C1" => ProcessResult::Changed(vec![]), + "C2" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_|{})); @@ -380,8 +380,8 @@ fn orphan() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D" | "E" => Ok(None), - "B" => Ok(Some(vec!["D"])), + "D" | "E" => ProcessResult::Unchanged, + "B" => ProcessResult::Changed(vec!["D"]), _ => unreachable!(), } }, |_|{})); @@ -391,8 +391,8 @@ fn orphan() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D" => Ok(None), - "E" => Err("E is for error"), + "D" => ProcessResult::Unchanged, + "E" => ProcessResult::Error("E is for error"), _ => unreachable!(), } }, |_|{})); @@ -405,7 +405,7 @@ fn orphan() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D" => Err("D is dead"), + "D" => ProcessResult::Error("D is dead"), _ => unreachable!(), } }, |_|{})); @@ -429,8 +429,8 @@ fn simultaneous_register_and_error() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Err("An error"), - "B" => Ok(Some(vec!["A"])), + "A" => ProcessResult::Error("An error"), + "B" => ProcessResult::Changed(vec!["A"]), _ => unreachable!(), } }, |_|{})); @@ -447,8 +447,8 @@ fn simultaneous_register_and_error() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Err("An error"), - "B" => Ok(Some(vec!["A"])), + "A" => ProcessResult::Error("An error"), + "B" => ProcessResult::Changed(vec!["A"]), _ => unreachable!(), } }, |_|{})); -- cgit 1.4.1-3-g733a5 From b0440d359b0dab992e8f01d63523799a72c81285 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 19 Apr 2018 15:13:20 +1000 Subject: Avoid useless Vec clones in pending_obligations(). The only instance of `ObligationForest` in use has an obligation type of `PendingPredicateObligation`, which contains a `PredicateObligation` and a `Vec`. `FulfillmentContext::pending_obligations()` calls `ObligationForest::pending_obligations()`, which clones all the `PendingPredicateObligation`s. But the `Vec` field of those cloned obligations is never touched. This patch changes `ObligationForest::pending_obligations()` to `map_pending_obligations` -- which gives callers control about which part of the obligation to clone -- and takes advantage of the change to avoid cloning the `Vec`. The change speeds up runs of a few rustc-perf benchmarks, the best by 1%. --- src/librustc/traits/engine.rs | 4 ++-- src/librustc/traits/fulfill.rs | 4 ++-- src/librustc_data_structures/obligation_forest/mod.rs | 6 +++--- src/librustc_typeck/check/closure.rs | 2 -- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index 8eee6f35ab9..40d54885619 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -13,7 +13,7 @@ use ty::{self, Ty, TyCtxt}; use hir::def_id::DefId; use super::{FulfillmentContext, FulfillmentError}; -use super::{ObligationCause, PendingPredicateObligation, PredicateObligation}; +use super::{ObligationCause, PredicateObligation}; pub trait TraitEngine<'tcx>: 'tcx { fn normalize_projection_type<'a, 'gcx>( @@ -49,7 +49,7 @@ pub trait TraitEngine<'tcx>: 'tcx { infcx: &InferCtxt<'a, 'gcx, 'tcx>, ) -> Result<(), Vec>>; - fn pending_obligations(&self) -> Vec>; + fn pending_obligations(&self) -> Vec>; } impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> { diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 4447a2b6ed1..7c31d8cc060 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -241,8 +241,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.select(&mut selcx) } - fn pending_obligations(&self) -> Vec> { - self.predicates.pending_obligations() + fn pending_obligations(&self) -> Vec> { + self.predicates.map_pending_obligations(|o| o.obligation.clone()) } } diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 612f44f09cf..c3934c4e1b8 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -229,13 +229,13 @@ impl ObligationForest { } /// Returns the set of obligations that are in a pending state. - pub fn pending_obligations(&self) -> Vec - where O: Clone + pub fn map_pending_obligations(&self, f: F) -> Vec

    + where F: Fn(&O) -> P { self.nodes .iter() .filter(|n| n.state.get() == NodeState::Pending) - .map(|n| n.obligation.clone()) + .map(|n| f(&n.obligation)) .collect() } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 67245bec7fb..439c1b34227 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -225,7 +225,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_sig = fulfillment_cx .pending_obligations() .iter() - .map(|obligation| &obligation.obligation) .filter_map(|obligation| { debug!( "deduce_expectations_from_obligations: obligation.predicate={:?}", @@ -257,7 +256,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_kind = fulfillment_cx .pending_obligations() .iter() - .map(|obligation| &obligation.obligation) .filter_map(|obligation| { let opt_trait_ref = match obligation.predicate { ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)), -- cgit 1.4.1-3-g733a5 From 6a5a4874a07767eb2f21b9fa2a3a7f71daaeb130 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 5 Jun 2018 11:06:38 -0400 Subject: convert type-check constraints into NLL constraints on the fly We used to accumulate a vector of type-check constraints, but now we generate them as we go, and just store the NLL-style `OutlivesConstraint` and `TypeTest` information. --- src/librustc_data_structures/indexed_vec.rs | 5 + .../borrow_check/nll/constraint_generation.rs | 47 ++++- src/librustc_mir/borrow_check/nll/mod.rs | 48 ++--- .../borrow_check/nll/region_infer/mod.rs | 53 +++--- .../nll/subtype_constraint_generation.rs | 199 --------------------- .../nll/type_check/constraint_conversion.rs | 190 ++++++++++++++++++++ .../borrow_check/nll/type_check/mod.rs | 63 ++++--- 7 files changed, 339 insertions(+), 266 deletions(-) delete mode 100644 src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs create mode 100644 src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 1fb63afc72f..ad3710e9536 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -367,6 +367,11 @@ impl IndexVec { IndexVec { raw: Vec::new(), _marker: PhantomData } } + #[inline] + pub fn from_raw(raw: Vec) -> Self { + IndexVec { raw, _marker: PhantomData } + } + #[inline] pub fn with_capacity(capacity: usize) -> Self { IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData } diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 4f87a2b30ae..72db9f8da98 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -11,6 +11,8 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::LocationTable; use borrow_check::nll::facts::AllFacts; +use borrow_check::nll::region_infer::{Cause, RegionInferenceContext}; +use borrow_check::nll::ToRegionVid; use rustc::hir; use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; @@ -21,9 +23,7 @@ use rustc::mir::{Local, PlaceProjection, ProjectionElem, Statement, Terminator}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts}; - -use super::region_infer::{Cause, RegionInferenceContext}; -use super::ToRegionVid; +use std::iter; pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( infcx: &InferCtxt<'cx, 'gcx, 'tcx>, @@ -32,6 +32,7 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( location_table: &LocationTable, mir: &Mir<'tcx>, borrow_set: &BorrowSet<'tcx>, + liveness_set_from_typeck: &[(ty::Region<'tcx>, Location, Cause)], ) { let mut cg = ConstraintGeneration { borrow_set, @@ -42,6 +43,8 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( mir, }; + cg.add_region_liveness_constraints_from_type_check(liveness_set_from_typeck); + for (bb, data) in mir.basic_blocks().iter_enumerated() { cg.visit_basic_block_data(bb, data); } @@ -209,7 +212,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx self.add_reborrow_constraint(location, region, borrowed_place); } - _ => { } + _ => {} } self.super_rvalue(rvalue, location); @@ -225,6 +228,42 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx } impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { + /// The MIR type checker generates region liveness constraints + /// that we also have to respect. + fn add_region_liveness_constraints_from_type_check( + &mut self, + liveness_set: &[(ty::Region<'tcx>, Location, Cause)], + ) { + debug!( + "add_region_liveness_constraints_from_type_check(liveness_set={} items)", + liveness_set.len(), + ); + + let ConstraintGeneration { + regioncx, + location_table, + all_facts, + .. + } = self; + + for (region, location, cause) in liveness_set { + debug!("generate: {:#?} is live at {:#?}", region, location); + let region_vid = regioncx.to_region_vid(region); + regioncx.add_live_point(region_vid, *location, &cause); + } + + if let Some(all_facts) = all_facts { + all_facts + .region_live_at + .extend(liveness_set.into_iter().flat_map(|(region, location, _)| { + let r = regioncx.to_region_vid(region); + let p1 = location_table.start_index(*location); + let p2 = location_table.mid_index(*location); + iter::once((r, p1)).chain(iter::once((r, p2))) + })); + } + } + /// Some variable with type `live_ty` is "regular live" at /// `location` -- i.e., it may be used later. This means that all /// regions appearing in the type `live_ty` must be live at diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index c3d9dd8378d..dcb52a3b18a 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -11,6 +11,7 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::{LocationIndex, LocationTable}; use borrow_check::nll::facts::AllFactsExt; +use borrow_check::nll::type_check::MirTypeckRegionConstraints; use dataflow::indexes::BorrowIndex; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; @@ -41,7 +42,6 @@ mod facts; mod invalidation; crate mod region_infer; mod renumber; -mod subtype_constraint_generation; crate mod type_check; mod universal_regions; @@ -91,46 +91,53 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( Option>>, Option>, ) { + let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts + || infcx.tcx.sess.opts.debugging_opts.polonius + { + Some(AllFacts::default()) + } else { + None + }; + // Run the MIR type-checker. let liveness = &LivenessResults::compute(mir); - let constraint_sets = &type_check::type_check( + let constraint_sets = type_check::type_check( infcx, param_env, mir, def_id, &universal_regions, + location_table, &liveness, + &mut all_facts, flow_inits, move_data, ); - let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts - || infcx.tcx.sess.opts.debugging_opts.polonius - { - Some(AllFacts::default()) - } else { - None - }; - if let Some(all_facts) = &mut all_facts { all_facts .universal_region .extend(universal_regions.universal_regions()); } - // Create the region inference context, taking ownership of the region inference - // data that was contained in `infcx`. + // Create the region inference context, taking ownership of the + // region inference data that was contained in `infcx`, and the + // base constraints generated by the type-check. let var_origins = infcx.take_region_var_origins(); - let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir); - - // Generate various constraints. - subtype_constraint_generation::generate( - &mut regioncx, - &mut all_facts, - location_table, + let MirTypeckRegionConstraints { + liveness_set, + outlives_constraints, + type_tests, + } = constraint_sets; + let mut regioncx = RegionInferenceContext::new( + var_origins, + universal_regions, mir, - constraint_sets, + outlives_constraints, + type_tests, ); + + // Generate various additional constraints. constraint_generation::generate_constraints( infcx, &mut regioncx, @@ -138,6 +145,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( location_table, &mir, borrow_set, + &liveness_set, ); invalidation::generate_invalidates( infcx, diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index d974a60c15c..f123d421700 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -123,15 +123,14 @@ pub struct OutlivesConstraint { // it is for convenience. Before we dump the constraints in the // debugging logs, we sort them, and we'd like the "super region" // to be first, etc. (In particular, span should remain last.) - /// The region SUP must outlive SUB... - sup: RegionVid, + pub sup: RegionVid, /// Region that must be outlived. - sub: RegionVid, + pub sub: RegionVid, /// At this location. - point: Location, + pub point: Location, /// Later on, we thread the constraints onto a linked list /// grouped by their `sub` field. So if you had: @@ -141,10 +140,10 @@ pub struct OutlivesConstraint { /// 0 | `'a: 'b` | Some(2) /// 1 | `'b: 'c` | None /// 2 | `'c: 'b` | None - next: Option, + pub next: Option, /// Where did this constraint arise? - span: Span, + pub span: Span, } newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); @@ -240,11 +239,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// `num_region_variables` valid inference variables; the first N /// of those will be constant regions representing the free /// regions defined in `universal_regions`. + /// + /// The `outlives_constraints` and `type_tests` are an initial set + /// of constraints produced by the MIR type check. pub(crate) fn new( var_infos: VarInfos, universal_regions: UniversalRegions<'tcx>, mir: &Mir<'tcx>, + outlives_constraints: Vec, + type_tests: Vec>, ) -> Self { + // The `next` field should not yet have been initialized: + debug_assert!(outlives_constraints.iter().all(|c| c.next.is_none())); + let num_region_variables = var_infos.len(); let num_universal_regions = universal_regions.len(); @@ -262,8 +269,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { liveness_constraints: RegionValues::new(elements, num_region_variables), inferred_values: None, dependency_map: None, - constraints: IndexVec::new(), - type_tests: Vec::new(), + constraints: IndexVec::from_raw(outlives_constraints), + type_tests, universal_regions, }; @@ -346,7 +353,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { where R: ToRegionVid, { - let inferred_values = self.inferred_values + let inferred_values = self + .inferred_values .as_ref() .expect("region values not yet inferred"); inferred_values.contains(r.to_region_vid(), p) @@ -354,7 +362,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Returns access to the value of `r` for debugging purposes. crate fn region_value_str(&self, r: RegionVid) -> String { - let inferred_values = self.inferred_values + let inferred_values = self + .inferred_values .as_ref() .expect("region values not yet inferred"); @@ -397,11 +406,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); } - /// Add a "type test" that must be satisfied. - pub(super) fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { - self.type_tests.push(type_test); - } - /// Perform region inference and report errors if we see any /// unsatisfiable constraints. If this is a closure, returns the /// region requirements to propagate to our creator, if any. @@ -596,7 +600,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { if self.universal_regions.is_universal_region(r) { return self.definitions[r].external_name; } else { - let inferred_values = self.inferred_values + let inferred_values = self + .inferred_values .as_ref() .expect("region values not yet inferred"); let upper_bound = self.universal_upper_bound(r); @@ -635,8 +640,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { // region, which ensures it can be encoded in a `ClosureOutlivesRequirement`. let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound); assert!(self.universal_regions.is_universal_region(lower_bound_plus)); - assert!(!self.universal_regions - .is_local_free_region(lower_bound_plus)); + assert!( + !self + .universal_regions + .is_local_free_region(lower_bound_plus) + ); propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject, @@ -664,7 +672,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Option> { let tcx = infcx.tcx; let gcx = tcx.global_tcx(); - let inferred_values = self.inferred_values + let inferred_values = self + .inferred_values .as_ref() .expect("region values not yet inferred"); @@ -845,7 +854,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { sup_region, sub_region, point ); - let inferred_values = self.inferred_values + let inferred_values = self + .inferred_values .as_ref() .expect("values for regions not yet inferred"); @@ -912,7 +922,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) { // The universal regions are always found in a prefix of the // full list. - let universal_definitions = self.definitions + let universal_definitions = self + .definitions .iter_enumerated() .take_while(|(_, fr_definition)| fr_definition.is_universal); diff --git a/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs deleted file mode 100644 index fd445c62e4e..00000000000 --- a/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2017 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. - -use borrow_check::location::LocationTable; -use borrow_check::nll::facts::AllFacts; -use rustc::infer::region_constraints::Constraint; -use rustc::infer::region_constraints::RegionConstraintData; -use rustc::infer::region_constraints::{Verify, VerifyBound}; -use rustc::mir::{Location, Mir}; -use rustc::ty; -use std::iter; -use syntax::codemap::Span; - -use super::region_infer::{RegionInferenceContext, RegionTest, TypeTest}; -use super::type_check::Locations; -use super::type_check::MirTypeckRegionConstraints; -use super::type_check::OutlivesSet; - -/// When the MIR type-checker executes, it validates all the types in -/// the MIR, and in the process generates a set of constraints that -/// must hold regarding the regions in the MIR, along with locations -/// *where* they must hold. This code takes those constriants and adds -/// them into the NLL `RegionInferenceContext`. -pub(super) fn generate<'tcx>( - regioncx: &mut RegionInferenceContext<'tcx>, - all_facts: &mut Option, - location_table: &LocationTable, - mir: &Mir<'tcx>, - constraints: &MirTypeckRegionConstraints<'tcx>, -) { - SubtypeConstraintGenerator { - regioncx, - location_table, - mir, - }.generate(constraints, all_facts); -} - -struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> { - regioncx: &'cx mut RegionInferenceContext<'tcx>, - location_table: &'cx LocationTable, - mir: &'cx Mir<'tcx>, -} - -impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { - fn generate( - &mut self, - constraints: &MirTypeckRegionConstraints<'tcx>, - all_facts: &mut Option, - ) { - let MirTypeckRegionConstraints { - liveness_set, - outlives_sets, - } = constraints; - - debug!( - "generate(liveness_set={} items, outlives_sets={} items)", - liveness_set.len(), - outlives_sets.len() - ); - - for (region, location, cause) in liveness_set { - debug!("generate: {:#?} is live at {:#?}", region, location); - let region_vid = self.to_region_vid(region); - self.regioncx.add_live_point(region_vid, *location, &cause); - } - - if let Some(all_facts) = all_facts { - all_facts - .region_live_at - .extend(liveness_set.into_iter().flat_map(|(region, location, _)| { - let r = self.to_region_vid(region); - let p1 = self.location_table.start_index(*location); - let p2 = self.location_table.mid_index(*location); - iter::once((r, p1)).chain(iter::once((r, p2))) - })); - } - - for OutlivesSet { locations, data } in outlives_sets { - debug!("generate: constraints at: {:#?}", locations); - let RegionConstraintData { - constraints, - verifys, - givens, - } = &**data; - - let span = self.mir - .source_info(locations.from_location().unwrap_or(Location::START)) - .span; - - let at_location = locations.at_location().unwrap_or(Location::START); - - for constraint in constraints.keys() { - debug!("generate: constraint: {:?}", constraint); - let (a_vid, b_vid) = match constraint { - Constraint::VarSubVar(a_vid, b_vid) => (*a_vid, *b_vid), - Constraint::RegSubVar(a_r, b_vid) => (self.to_region_vid(a_r), *b_vid), - Constraint::VarSubReg(a_vid, b_r) => (*a_vid, self.to_region_vid(b_r)), - Constraint::RegSubReg(a_r, b_r) => { - (self.to_region_vid(a_r), self.to_region_vid(b_r)) - } - }; - - // We have the constraint that `a_vid <= b_vid`. Add - // `b_vid: a_vid` to our region checker. Note that we - // reverse direction, because `regioncx` talks about - // "outlives" (`>=`) whereas the region constraints - // talk about `<=`. - self.regioncx.add_outlives(span, b_vid, a_vid, at_location); - - // In the new analysis, all outlives relations etc - // "take effect" at the mid point of the statement - // that requires them, so ignore the `at_location`. - if let Some(all_facts) = all_facts { - if let Some(from_location) = locations.from_location() { - all_facts.outlives.push(( - b_vid, - a_vid, - self.location_table.mid_index(from_location), - )); - } else { - for location in self.location_table.all_points() { - all_facts.outlives.push((b_vid, a_vid, location)); - } - } - } - } - - for verify in verifys { - let type_test = self.verify_to_type_test(verify, span, locations); - self.regioncx.add_type_test(type_test); - } - - assert!( - givens.is_empty(), - "MIR type-checker does not use givens (thank goodness)" - ); - } - } - - fn verify_to_type_test( - &self, - verify: &Verify<'tcx>, - span: Span, - locations: &Locations, - ) -> TypeTest<'tcx> { - let generic_kind = verify.kind; - - let lower_bound = self.to_region_vid(verify.region); - - let point = locations.at_location().unwrap_or(Location::START); - - let test = self.verify_bound_to_region_test(&verify.bound); - - TypeTest { - generic_kind, - lower_bound, - point, - span, - test, - } - } - - fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> RegionTest { - match verify_bound { - VerifyBound::AnyRegion(regions) => RegionTest::IsOutlivedByAnyRegionIn( - regions.iter().map(|r| self.to_region_vid(r)).collect(), - ), - - VerifyBound::AllRegions(regions) => RegionTest::IsOutlivedByAllRegionsIn( - regions.iter().map(|r| self.to_region_vid(r)).collect(), - ), - - VerifyBound::AnyBound(bounds) => RegionTest::Any( - bounds - .iter() - .map(|b| self.verify_bound_to_region_test(b)) - .collect(), - ), - - VerifyBound::AllBounds(bounds) => RegionTest::All( - bounds - .iter() - .map(|b| self.verify_bound_to_region_test(b)) - .collect(), - ), - } - } - - fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid { - self.regioncx.to_region_vid(r) - } -} diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs new file mode 100644 index 00000000000..06aaf6810fa --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -0,0 +1,190 @@ +// Copyright 2017 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. + +use borrow_check::location::LocationTable; +use borrow_check::nll::facts::AllFacts; +use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest}; +use borrow_check::nll::type_check::Locations; +use borrow_check::nll::universal_regions::UniversalRegions; +use rustc::infer::region_constraints::Constraint; +use rustc::infer::region_constraints::RegionConstraintData; +use rustc::infer::region_constraints::{Verify, VerifyBound}; +use rustc::mir::{Location, Mir}; +use rustc::ty; +use syntax::codemap::Span; + +crate struct ConstraintConversion<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, + universal_regions: &'a UniversalRegions<'tcx>, + location_table: &'a LocationTable, + outlives_constraints: &'a mut Vec, + type_tests: &'a mut Vec>, + all_facts: &'a mut Option, + +} + +impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { + crate fn new( + mir: &'a Mir<'tcx>, + universal_regions: &'a UniversalRegions<'tcx>, + location_table: &'a LocationTable, + outlives_constraints: &'a mut Vec, + type_tests: &'a mut Vec>, + all_facts: &'a mut Option, + ) -> Self { + Self { + mir, + universal_regions, + location_table, + outlives_constraints, + type_tests, + all_facts, + } + } + + crate fn convert( + &mut self, + locations: Locations, + data: &RegionConstraintData<'tcx>, + ) { + debug!("generate: constraints at: {:#?}", locations); + let RegionConstraintData { + constraints, + verifys, + givens, + } = data; + + let span = self + .mir + .source_info(locations.from_location().unwrap_or(Location::START)) + .span; + + let at_location = locations.at_location().unwrap_or(Location::START); + + for constraint in constraints.keys() { + debug!("generate: constraint: {:?}", constraint); + let (a_vid, b_vid) = match constraint { + Constraint::VarSubVar(a_vid, b_vid) => (*a_vid, *b_vid), + Constraint::RegSubVar(a_r, b_vid) => (self.to_region_vid(a_r), *b_vid), + Constraint::VarSubReg(a_vid, b_r) => (*a_vid, self.to_region_vid(b_r)), + Constraint::RegSubReg(a_r, b_r) => { + (self.to_region_vid(a_r), self.to_region_vid(b_r)) + } + }; + + // We have the constraint that `a_vid <= b_vid`. Add + // `b_vid: a_vid` to our region checker. Note that we + // reverse direction, because `regioncx` talks about + // "outlives" (`>=`) whereas the region constraints + // talk about `<=`. + self.add_outlives(span, b_vid, a_vid, at_location); + + // In the new analysis, all outlives relations etc + // "take effect" at the mid point of the statement + // that requires them, so ignore the `at_location`. + if let Some(all_facts) = &mut self.all_facts { + if let Some(from_location) = locations.from_location() { + all_facts.outlives.push(( + b_vid, + a_vid, + self.location_table.mid_index(from_location), + )); + } else { + for location in self.location_table.all_points() { + all_facts.outlives.push((b_vid, a_vid, location)); + } + } + } + } + + for verify in verifys { + let type_test = self.verify_to_type_test(verify, span, locations); + self.add_type_test(type_test); + } + + assert!( + givens.is_empty(), + "MIR type-checker does not use givens (thank goodness)" + ); + } + + fn verify_to_type_test( + &self, + verify: &Verify<'tcx>, + span: Span, + locations: Locations, + ) -> TypeTest<'tcx> { + let generic_kind = verify.kind; + + let lower_bound = self.to_region_vid(verify.region); + + let point = locations.at_location().unwrap_or(Location::START); + + let test = self.verify_bound_to_region_test(&verify.bound); + + TypeTest { + generic_kind, + lower_bound, + point, + span, + test, + } + } + + fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> RegionTest { + match verify_bound { + VerifyBound::AnyRegion(regions) => RegionTest::IsOutlivedByAnyRegionIn( + regions.iter().map(|r| self.to_region_vid(r)).collect(), + ), + + VerifyBound::AllRegions(regions) => RegionTest::IsOutlivedByAllRegionsIn( + regions.iter().map(|r| self.to_region_vid(r)).collect(), + ), + + VerifyBound::AnyBound(bounds) => RegionTest::Any( + bounds + .iter() + .map(|b| self.verify_bound_to_region_test(b)) + .collect(), + ), + + VerifyBound::AllBounds(bounds) => RegionTest::All( + bounds + .iter() + .map(|b| self.verify_bound_to_region_test(b)) + .collect(), + ), + } + } + + fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid { + self.universal_regions.to_region_vid(r) + } + + fn add_outlives( + &mut self, + span: Span, + sup: ty::RegionVid, + sub: ty::RegionVid, + point: Location, + ) { + self.outlives_constraints.push(OutlivesConstraint { + span, + sub, + sup, + point, + next: None, + }); + } + + fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { + self.type_tests.push(type_test); + } +} diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index a8ae614d619..bed0fec4d4d 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -11,8 +11,10 @@ //! This pass type-checks the MIR to ensure it is not broken. #![allow(unreachable_code)] +use borrow_check::location::LocationTable; +use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::Cause; -use borrow_check::nll::region_infer::ClosureRegionRequirementsExt; +use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, OutlivesConstraint, TypeTest}; use borrow_check::nll::universal_regions::UniversalRegions; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; @@ -63,6 +65,7 @@ macro_rules! span_mirbug_and_err { }) } +mod constraint_conversion; mod input_output; mod liveness; @@ -101,7 +104,9 @@ pub(crate) fn type_check<'gcx, 'tcx>( mir: &Mir<'tcx>, mir_def_id: DefId, universal_regions: &UniversalRegions<'tcx>, + location_table: &LocationTable, liveness: &LivenessResults, + all_facts: &mut Option, flow_inits: &mut FlowAtLocation>, move_data: &MoveData<'tcx>, ) -> MirTypeckRegionConstraints<'tcx> { @@ -114,6 +119,11 @@ pub(crate) fn type_check<'gcx, 'tcx>( mir, &universal_regions.region_bound_pairs, Some(implicit_region_bound), + Some(BorrowCheckContext { + universal_regions, + location_table, + all_facts, + }), &mut |cx| { liveness::generate(cx, mir, liveness, flow_inits, move_data); @@ -129,6 +139,7 @@ fn type_check_internal<'gcx, 'tcx>( mir: &Mir<'tcx>, region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, + borrowck_context: Option>, extra: &mut dyn FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>), ) -> MirTypeckRegionConstraints<'tcx> { let mut checker = TypeChecker::new( @@ -137,6 +148,8 @@ fn type_check_internal<'gcx, 'tcx>( param_env, region_bound_pairs, implicit_region_bound, + borrowck_context, + mir, ); let errors_reported = { let mut verifier = TypeVerifier::new(&mut checker, mir); @@ -587,12 +600,20 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { implicit_region_bound: Option>, reported_errors: FxHashSet<(Ty<'tcx>, Span)>, constraints: MirTypeckRegionConstraints<'tcx>, + borrowck_context: Option>, + mir: &'a Mir<'tcx>, +} + +struct BorrowCheckContext<'a, 'tcx: 'a> { + universal_regions: &'a UniversalRegions<'tcx>, + location_table: &'a LocationTable, + all_facts: &'a mut Option, } /// A collection of region constraints that must be satisfied for the /// program to be considered well-typed. #[derive(Default)] -pub(crate) struct MirTypeckRegionConstraints<'tcx> { +crate struct MirTypeckRegionConstraints<'tcx> { /// In general, the type-checker is not responsible for enforcing /// liveness constraints; this job falls to the region inferencer, /// which performs a liveness analysis. However, in some limited @@ -600,24 +621,11 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { /// not otherwise appear in the MIR -- in particular, the /// late-bound regions that it instantiates at call-sites -- and /// hence it must report on their liveness constraints. - pub liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>, + crate liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>, - /// During the course of type-checking, we will accumulate region - /// constraints due to performing subtyping operations or solving - /// traits. These are accumulated into this vector for later use. - pub outlives_sets: Vec>, -} - -/// Outlives relationships between regions and types created at a -/// particular point within the control-flow graph. -pub struct OutlivesSet<'tcx> { - /// The locations associated with these constraints. - pub locations: Locations, + crate outlives_constraints: Vec, - /// Constraints generated. In terms of the NLL RFC, when you have - /// a constraint `R1: R2 @ P`, the data in there specifies things - /// like `R1: R2`. - pub data: Rc>, + crate type_tests: Vec>, } /// The `Locations` type summarizes *where* region constraints are @@ -695,6 +703,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { param_env: ty::ParamEnv<'gcx>, region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, + borrowck_context: Option>, + mir: &'a Mir<'tcx>, ) -> Self { TypeChecker { infcx, @@ -703,6 +713,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { param_env, region_bound_pairs, implicit_region_bound, + borrowck_context, + mir, reported_errors: FxHashSet(), constraints: MirTypeckRegionConstraints::default(), } @@ -750,9 +762,16 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { locations, data ); - self.constraints - .outlives_sets - .push(OutlivesSet { locations, data }); + if let Some(borrowck_context) = &mut self.borrowck_context { + constraint_conversion::ConstraintConversion::new( + self.mir, + borrowck_context.universal_regions, + borrowck_context.location_table, + &mut self.constraints.outlives_constraints, + &mut self.constraints.type_tests, + &mut borrowck_context.all_facts, + ).convert(locations, &data); + } } /// Helper for `fully_perform_op`, but also used on its own @@ -1712,7 +1731,7 @@ impl MirPass for TypeckMir { } let param_env = tcx.param_env(def_id); tcx.infer_ctxt().enter(|infcx| { - let _ = type_check_internal(&infcx, id, param_env, mir, &[], None, &mut |_| ()); + let _ = type_check_internal(&infcx, id, param_env, mir, &[], None, None, &mut |_| ()); // For verification purposes, we just ignore the resulting // region constraint sets. Not our problem. =) -- cgit 1.4.1-3-g733a5 From 6151bab8e1b94510eeb3929eb969ef8679a24294 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 7 Jun 2018 15:35:10 +1000 Subject: Improve pushing to `Node::dependents`. This patch makes it impossible for a node to end up in both `node.parent` and `node.dependents`. --- src/librustc_data_structures/obligation_forest/mod.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 990dc66c66a..c66011d4118 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -193,15 +193,18 @@ impl ObligationForest { Entry::Occupied(o) => { debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!", obligation, parent, o.get()); + let node = &mut self.nodes[o.get().get()]; if let Some(parent) = parent { - if self.nodes[o.get().get()].dependents.contains(&parent) { - debug!("register_obligation_at({:?}, {:?}) - duplicate subobligation", - obligation, parent); - } else { - self.nodes[o.get().get()].dependents.push(parent); + // If the node is already in `waiting_cache`, it's already + // been marked with a parent. (It's possible that parent + // has been cleared by `apply_rewrites`, though.) So just + // dump `parent` into `node.dependents`... unless it's + // already in `node.dependents` or `node.parent`. + if !node.dependents.contains(&parent) && Some(parent) != node.parent { + node.dependents.push(parent); } } - if let NodeState::Error = self.nodes[o.get().get()].state.get() { + if let NodeState::Error = node.state.get() { Err(()) } else { Ok(()) -- cgit 1.4.1-3-g733a5 From 70d22fa0519c8970cecbae400e7f6ebf69704d92 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 7 Jun 2018 16:19:52 +1000 Subject: Improve `Node::{parent,dependents}` interplay. This patch: - Reorders things a bit so that `parent` is always handled before `dependents`. - Uses iterator chaining to avoid some code duplication. --- .../obligation_forest/mod.rs | 24 ++++++++-------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index c66011d4118..df34891ff03 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -91,13 +91,14 @@ struct Node { obligation: O, state: Cell, - /// Obligations that depend on this obligation for their - /// completion. They must all be in a non-pending state. - dependents: Vec, /// The parent of a node - the original obligation of /// which it is a subobligation. Except for error reporting, - /// this is just another member of `dependents`. + /// it is just like any member of `dependents`. parent: Option, + + /// Obligations that depend on this obligation for their + /// completion. They must all be in a non-pending state. + dependents: Vec, } /// The state of one node in some tree within the forest. This @@ -383,10 +384,7 @@ impl ObligationForest { NodeState::Success => { node.state.set(NodeState::OnDfsStack); stack.push(index); - if let Some(parent) = node.parent { - self.find_cycles_from_node(stack, processor, parent.get()); - } - for dependent in &node.dependents { + for dependent in node.parent.iter().chain(node.dependents.iter()) { self.find_cycles_from_node(stack, processor, dependent.get()); } stack.pop(); @@ -430,7 +428,7 @@ impl ObligationForest { } error_stack.extend( - node.dependents.iter().cloned().chain(node.parent).map(|x| x.get()) + node.parent.iter().chain(node.dependents.iter()).map(|x| x.get()) ); } @@ -440,11 +438,7 @@ impl ObligationForest { #[inline] fn mark_neighbors_as_waiting_from(&self, node: &Node) { - if let Some(parent) = node.parent { - self.mark_as_waiting_from(&self.nodes[parent.get()]); - } - - for dependent in &node.dependents { + for dependent in node.parent.iter().chain(node.dependents.iter()) { self.mark_as_waiting_from(&self.nodes[dependent.get()]); } } @@ -591,8 +585,8 @@ impl Node { fn new(parent: Option, obligation: O) -> Node { Node { obligation, - parent, state: Cell::new(NodeState::Pending), + parent, dependents: vec![], } } -- cgit 1.4.1-3-g733a5 From 8368f364e3ae1245a4f95040487d1781570f455a Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Fri, 8 Jun 2018 17:48:31 +0200 Subject: Add MTRef and a lock_mut function to MTLock --- src/librustc_data_structures/sync.rs | 45 +++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 33f6eda2a87..b82fe3ec60c 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -26,6 +26,8 @@ //! //! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false. //! +//! `MTRef` is a immutable refernce if cfg!(parallel_queries), and an mutable reference otherwise. +//! //! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync //! depending on the value of cfg!(parallel_queries). @@ -126,6 +128,8 @@ cfg_if! { } } + pub type MTRef<'a, T> = &'a mut T; + #[derive(Debug)] pub struct MTLock(T); @@ -151,13 +155,8 @@ cfg_if! { } #[inline(always)] - pub fn borrow(&self) -> &T { - &self.0 - } - - #[inline(always)] - pub fn borrow_mut(&self) -> &T { - &self.0 + pub fn lock_mut(&mut self) -> &mut T { + &mut self.0 } } @@ -221,7 +220,37 @@ cfg_if! { pub use std::sync::Arc as Lrc; pub use std::sync::Weak as Weak; - pub use self::Lock as MTLock; + pub type MTRef<'a, T> = &'a T; + + #[derive(Debug)] + pub struct MTLock(Lock); + + impl MTLock { + #[inline(always)] + pub fn new(inner: T) -> Self { + MTLock(Lock::new(inner)) + } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0.into_inner() + } + + #[inline(always)] + pub fn get_mut(&mut self) -> &mut T { + self.0.get_mut() + } + + #[inline(always)] + pub fn lock(&self) -> LockGuard { + self.0.lock() + } + + #[inline(always)] + pub fn lock_mut(&self) -> LockGuard { + self.lock() + } + } use parking_lot::Mutex as InnerLock; use parking_lot::RwLock as InnerRwLock; -- cgit 1.4.1-3-g733a5 From 08683f003cab472efc0481c349cb69dfb137c4c1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Jun 2018 16:20:32 +1000 Subject: Rename `IdxSet::clone_from`. The current situation is something of a mess. - `IdxSetBuf` derefs to `IdxSet`. - `IdxSetBuf` implements `Clone`, and therefore has a provided `clone_from` method, which does allocation and so is expensive. - `IdxSet` has a `clone_from` method that is non-allocating and therefore cheap, but this method is not from the `Clone` trait. As a result, if you have an `IdxSetBuf` called `b`, if you call `b.clone_from(b2)` you'll get the expensive `IdxSetBuf` method, but if you call `(*b).clone_from(b2)` you'll get the cheap `IdxSetBuf` method. `liveness_of_locals()` does the former, presumably unintentionally, and therefore does lots of unnecessary allocations. Having a `clone_from` method that isn't from the `Clone` trait is a bad idea in general, so this patch renames it as `overwrite`. This avoids the unnecessary allocations in `liveness_of_locals()`, speeding up most NLL benchmarks, the best by 1.5%. It also means that calls of the form `(*b).clone_from(b2)` can be rewritten as `b.overwrite(b2)`. --- src/librustc_data_structures/indexed_set.rs | 4 +++- src/librustc_mir/dataflow/at_location.rs | 2 +- src/librustc_mir/dataflow/mod.rs | 2 +- src/librustc_mir/util/liveness.rs | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index c9495587c46..30b87c0390a 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -233,7 +233,9 @@ impl IdxSet { &mut self.bits } - pub fn clone_from(&mut self, other: &IdxSet) { + /// Efficiently overwrite `self` with `other`. Panics if `self` and `other` + /// don't have the same length. + pub fn overwrite(&mut self, other: &IdxSet) { self.words_mut().clone_from_slice(other.words()); } diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index a89d1afae86..05453bd58c4 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -139,7 +139,7 @@ impl FlowsAtLocation for FlowAtLocation where BD: BitDenotation { fn reset_to_entry_of(&mut self, bb: BasicBlock) { - (*self.curr_state).clone_from(self.base_results.sets().on_entry_set_for(bb.index())); + self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index())); } fn reconstruct_statement_effect(&mut self, loc: Location) { diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 85458c7d684..98cd9c35d88 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -242,7 +242,7 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: Bi { let sets = builder.flow_state.sets.for_block(bb_idx); debug_assert!(in_out.words().len() == sets.on_entry.words().len()); - in_out.clone_from(sets.on_entry); + in_out.overwrite(sets.on_entry); in_out.union(sets.gen_set); in_out.subtract(sets.kill_set); } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index cfb1a2cd28b..34f8141141d 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -141,14 +141,14 @@ pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>, mode: LivenessMode) -> Liveness for &successor in mir.basic_blocks()[b].terminator().successors() { bits.union(&ins[successor]); } - outs[b].clone_from(&bits); + outs[b].overwrite(&bits); // bits = use ∪ (bits - def) def_use[b].apply(&mut bits); // update bits on entry and flag if they have changed if ins[b] != bits { - ins[b].clone_from(&bits); + ins[b].overwrite(&bits); changed = true; } } -- cgit 1.4.1-3-g733a5 From 388ff03248f15b6266f8614e1a3f10e28fcbb1e3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 29 Jun 2018 06:38:48 -0400 Subject: create a new `WorkQueue` data structure --- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/work_queue.rs | 72 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 src/librustc_data_structures/work_queue.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 5844edf000a..e4d0bc596cb 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -77,6 +77,7 @@ pub mod sync; pub mod owning_ref; pub mod tiny_list; pub mod sorted_map; +pub mod work_queue; pub struct OnDrop(pub F); diff --git a/src/librustc_data_structures/work_queue.rs b/src/librustc_data_structures/work_queue.rs new file mode 100644 index 00000000000..b8e8b249bb5 --- /dev/null +++ b/src/librustc_data_structures/work_queue.rs @@ -0,0 +1,72 @@ +// 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. + +use indexed_set::IdxSetBuf; +use indexed_vec::Idx; +use std::collections::VecDeque; + +/// A work queue is a handy data structure for tracking work left to +/// do. (For example, basic blocks left to process.) It is basically a +/// de-duplicating queue; so attempting to insert X if X is already +/// enqueued has no effect. This implementation assumes that the +/// elements are dense indices, so it can allocate the queue to size +/// and also use a bit set to track occupancy. +pub struct WorkQueue { + deque: VecDeque, + set: IdxSetBuf, +} + +impl WorkQueue { + /// Create a new work queue with all the elements from (0..len). + #[inline] + pub fn with_all(len: usize) -> Self { + WorkQueue { + deque: (0..len).map(T::new).collect(), + set: IdxSetBuf::new_filled(len), + } + } + + /// Create a new work queue that starts empty, where elements range from (0..len). + #[inline] + pub fn with_none(len: usize) -> Self { + WorkQueue { + deque: VecDeque::with_capacity(len), + set: IdxSetBuf::new_empty(len), + } + } + + /// Attempt to enqueue `element` in the work queue. Returns false if it was already present. + #[inline] + pub fn insert(&mut self, element: T) -> bool { + if self.set.add(&element) { + self.deque.push_back(element); + true + } else { + false + } + } + + /// Attempt to enqueue `element` in the work queue. Returns false if it was already present. + #[inline] + pub fn pop(&mut self) -> Option { + if let Some(element) = self.deque.pop_front() { + self.set.remove(&element); + Some(element) + } else { + None + } + } + + /// True if nothing is enqueued. + #[inline] + pub fn is_empty(&self) -> bool { + self.deque.is_empty() + } +} -- cgit 1.4.1-3-g733a5 From 78ea95258d6e3f603713ffde001334305044a4fb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Jul 2018 11:40:49 -0400 Subject: improve comments --- src/librustc_data_structures/indexed_set.rs | 6 ++++++ src/librustc_mir/util/liveness.rs | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 30b87c0390a..2e95a45479c 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -239,14 +239,20 @@ impl IdxSet { self.words_mut().clone_from_slice(other.words()); } + /// Set `self = self | other` and return true if `self` changed + /// (i.e., if new bits were added). pub fn union(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Union) } + /// Set `self = self - other` and return true if `self` changed. + /// (i.e., if any bits were removed). pub fn subtract(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Subtract) } + /// Set `self = self & other` and return true if `self` changed. + /// (i.e., if any bits were removed). pub fn intersect(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Intersect) } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index d4b93b896de..4630cdae47d 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -140,9 +140,12 @@ pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>, mode: LivenessMode) -> Liveness bits.overwrite(&outs[bb]); def_use[bb].apply(&mut bits); - // add `bits` to the out set for each predecessor; if those + // `bits` now contains the live variables on entry. Therefore, + // add `bits` to the `out` set for each predecessor; if those // bits were not already present, then enqueue the predecessor // as dirty. + // + // (note that `union` returns true if the `self` set changed) for &pred_bb in &predecessors[bb] { if outs[pred_bb].union(&bits) { dirty_queue.insert(pred_bb); -- cgit 1.4.1-3-g733a5 From ff65bbe96a4ef301673eb5934649019991dbef0a Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 11 Jul 2018 13:58:27 +0200 Subject: Deny bare trait objects in in src/librustc_data_structures --- src/librustc_data_structures/lib.rs | 2 ++ src/librustc_data_structures/owning_ref/mod.rs | 24 ++++++++++++------------ src/librustc_data_structures/sync.rs | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index e4d0bc596cb..2cca31f70a0 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -16,6 +16,8 @@ //! //! This API is completely unstable and subject to change. +#![deny(bare_trait_objects)] + #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index aa113fac9fb..7bd297b1551 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -1046,7 +1046,7 @@ unsafe impl Send for OwningRefMut unsafe impl Sync for OwningRefMut where O: Sync, for<'a> (&'a mut T): Sync {} -impl Debug for Erased { +impl Debug for dyn Erased { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "",) } @@ -1166,35 +1166,35 @@ pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut, U>; pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRef, U>; unsafe impl<'a, T: 'a> IntoErased<'a> for Box { - type Erased = Box; + type Erased = Box; fn into_erased(self) -> Self::Erased { self } } unsafe impl<'a, T: 'a> IntoErased<'a> for Rc { - type Erased = Rc; + type Erased = Rc; fn into_erased(self) -> Self::Erased { self } } unsafe impl<'a, T: 'a> IntoErased<'a> for Arc { - type Erased = Arc; + type Erased = Arc; fn into_erased(self) -> Self::Erased { self } } unsafe impl<'a, T: Send + 'a> IntoErasedSend<'a> for Box { - type Erased = Box; + type Erased = Box; fn into_erased_send(self) -> Self::Erased { self } } unsafe impl<'a, T: Send + 'a> IntoErasedSendSync<'a> for Box { - type Erased = Box; + type Erased = Box; fn into_erased_send_sync(self) -> Self::Erased { - let result: Box = self; + let result: Box = self; // This is safe since Erased can always implement Sync // Only the destructor is available and it takes &mut self unsafe { @@ -1204,21 +1204,21 @@ unsafe impl<'a, T: Send + 'a> IntoErasedSendSync<'a> for Box { } unsafe impl<'a, T: Send + Sync + 'a> IntoErasedSendSync<'a> for Arc { - type Erased = Arc; + type Erased = Arc; fn into_erased_send_sync(self) -> Self::Erased { self } } /// Typedef of a owning reference that uses an erased `Box` as the owner. -pub type ErasedBoxRef = OwningRef, U>; +pub type ErasedBoxRef = OwningRef, U>; /// Typedef of a owning reference that uses an erased `Rc` as the owner. -pub type ErasedRcRef = OwningRef, U>; +pub type ErasedRcRef = OwningRef, U>; /// Typedef of a owning reference that uses an erased `Arc` as the owner. -pub type ErasedArcRef = OwningRef, U>; +pub type ErasedArcRef = OwningRef, U>; /// Typedef of a mutable owning reference that uses an erased `Box` as the owner. -pub type ErasedBoxRefMut = OwningRefMut, U>; +pub type ErasedBoxRefMut = OwningRefMut, U>; #[cfg(test)] mod tests { diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index b82fe3ec60c..7668225627f 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -88,7 +88,7 @@ cfg_if! { t.into_iter() } - pub type MetadataRef = OwningRef, [u8]>; + pub type MetadataRef = OwningRef, [u8]>; pub use std::rc::Rc as Lrc; pub use std::rc::Weak as Weak; -- cgit 1.4.1-3-g733a5 From bbaf45d0f5214e5b175603cefeda9d04bc00b6b3 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 11 Jul 2018 14:21:26 +0200 Subject: Enforce #![deny(bare_trait_objects)] in src/librustc_data_structures tests --- src/librustc_data_structures/owning_ref/mod.rs | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index 7bd297b1551..02640a71010 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -1443,8 +1443,8 @@ mod tests { let c: OwningRef>, [u8]> = unsafe {a.map_owner(Rc::new)}; let d: OwningRef>, [u8]> = unsafe {b.map_owner(Rc::new)}; - let e: OwningRef, [u8]> = c.erase_owner(); - let f: OwningRef, [u8]> = d.erase_owner(); + let e: OwningRef, [u8]> = c.erase_owner(); + let f: OwningRef, [u8]> = d.erase_owner(); let _g = e.clone(); let _h = f.clone(); @@ -1460,8 +1460,8 @@ mod tests { let c: OwningRef>, [u8]> = a.map_owner_box(); let d: OwningRef>, [u8]> = b.map_owner_box(); - let _e: OwningRef, [u8]> = c.erase_owner(); - let _f: OwningRef, [u8]> = d.erase_owner(); + let _e: OwningRef, [u8]> = c.erase_owner(); + let _f: OwningRef, [u8]> = d.erase_owner(); } #[test] @@ -1469,7 +1469,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok(); } @@ -1479,7 +1479,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err(); } @@ -1843,8 +1843,8 @@ mod tests { let c: OwningRefMut>, [u8]> = unsafe {a.map_owner(Box::new)}; let d: OwningRefMut>, [u8]> = unsafe {b.map_owner(Box::new)}; - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); + let _e: OwningRefMut, [u8]> = c.erase_owner(); + let _f: OwningRefMut, [u8]> = d.erase_owner(); } #[test] @@ -1857,8 +1857,8 @@ mod tests { let c: OwningRefMut>, [u8]> = a.map_owner_box(); let d: OwningRefMut>, [u8]> = b.map_owner_box(); - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); + let _e: OwningRefMut, [u8]> = c.erase_owner(); + let _f: OwningRefMut, [u8]> = d.erase_owner(); } #[test] @@ -1866,7 +1866,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_ok(); } @@ -1876,7 +1876,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_err(); } @@ -1886,7 +1886,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok(); } @@ -1896,7 +1896,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err(); } -- cgit 1.4.1-3-g733a5 From 6cfd49e8dd8c09122c8b4f98ca3e7a33080e6e80 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 11 Jul 2018 16:08:38 +0200 Subject: add a missing `dyn` --- src/librustc_data_structures/sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 7668225627f..d4c6b1c2ced 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -268,7 +268,7 @@ cfg_if! { t.into_par_iter() } - pub type MetadataRef = OwningRef, [u8]>; + pub type MetadataRef = OwningRef, [u8]>; /// This makes locks panic if they are already held. /// It is only useful when you are running in a single thread -- cgit 1.4.1-3-g733a5 From 28c483b9462327bcda109e327251b5800ceb3fe5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 1 Jul 2018 16:54:01 -0400 Subject: deconstruct the `ControlFlowGraph` trait into more granular traits --- src/librustc/mir/mod.rs | 17 ++++-- .../control_flow_graph/dominators/mod.rs | 67 ++++++++++++---------- .../control_flow_graph/iterate/mod.rs | 31 ++++++---- .../control_flow_graph/mod.rs | 57 ++++++++++++++---- .../control_flow_graph/reference.rs | 22 ++++--- 5 files changed, 130 insertions(+), 64 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index cd4b32735e5..1ce5742b464 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -22,7 +22,7 @@ use mir::visit::MirVisitable; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_data_structures::control_flow_graph::dominators::{dominators, Dominators}; -use rustc_data_structures::control_flow_graph::ControlFlowGraph; +use rustc_data_structures::control_flow_graph; use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::small_vec::SmallVec; @@ -2289,23 +2289,32 @@ fn item_path_str(def_id: DefId) -> String { ty::tls::with(|tcx| tcx.item_path_str(def_id)) } -impl<'tcx> ControlFlowGraph for Mir<'tcx> { +impl<'tcx> control_flow_graph::DirectedGraph for Mir<'tcx> { type Node = BasicBlock; +} +impl<'tcx> control_flow_graph::WithNumNodes for Mir<'tcx> { fn num_nodes(&self) -> usize { self.basic_blocks.len() } +} +impl<'tcx> control_flow_graph::WithStartNode for Mir<'tcx> { fn start_node(&self) -> Self::Node { START_BLOCK } +} +impl<'tcx> control_flow_graph::WithPredecessors for Mir<'tcx> { fn predecessors<'graph>( &'graph self, node: Self::Node, ) -> >::Iter { self.predecessors_for(node).clone().into_iter() } +} + +impl<'tcx> control_flow_graph::WithSuccessors for Mir<'tcx> { fn successors<'graph>( &'graph self, node: Self::Node, @@ -2314,12 +2323,12 @@ impl<'tcx> ControlFlowGraph for Mir<'tcx> { } } -impl<'a, 'b> GraphPredecessors<'b> for Mir<'a> { +impl<'a, 'b> control_flow_graph::GraphPredecessors<'b> for Mir<'a> { type Item = BasicBlock; type Iter = IntoIter; } -impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { +impl<'a, 'b> control_flow_graph::GraphSuccessors<'b> for Mir<'a> { type Item = BasicBlock; type Iter = iter::Cloned>; } diff --git a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs index 54407658e6c..d134fad2855 100644 --- a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs @@ -14,9 +14,9 @@ //! Rice Computer Science TS-06-33870 //! -use super::ControlFlowGraph; +use super::super::indexed_vec::{Idx, IndexVec}; use super::iterate::reverse_post_order; -use super::super::indexed_vec::{IndexVec, Idx}; +use super::ControlFlowGraph; use std::fmt; @@ -29,15 +29,16 @@ pub fn dominators(graph: &G) -> Dominators { dominators_given_rpo(graph, &rpo) } -pub fn dominators_given_rpo(graph: &G, - rpo: &[G::Node]) - -> Dominators { +pub fn dominators_given_rpo( + graph: &G, + rpo: &[G::Node], +) -> Dominators { let start_node = graph.start_node(); assert_eq!(rpo[0], start_node); // compute the post order index (rank) for each node - let mut post_order_rank: IndexVec = IndexVec::from_elem_n(usize::default(), - graph.num_nodes()); + let mut post_order_rank: IndexVec = + IndexVec::from_elem_n(usize::default(), graph.num_nodes()); for (index, node) in rpo.iter().rev().cloned().enumerate() { post_order_rank[node] = index; } @@ -56,10 +57,12 @@ pub fn dominators_given_rpo(graph: &G, if immediate_dominators[pred].is_some() { // (*) // (*) dominators for `pred` have been calculated - new_idom = intersect_opt(&post_order_rank, - &immediate_dominators, - new_idom, - Some(pred)); + new_idom = intersect_opt( + &post_order_rank, + &immediate_dominators, + new_idom, + Some(pred), + ); } } @@ -76,11 +79,12 @@ pub fn dominators_given_rpo(graph: &G, } } -fn intersect_opt(post_order_rank: &IndexVec, - immediate_dominators: &IndexVec>, - node1: Option, - node2: Option) - -> Option { +fn intersect_opt( + post_order_rank: &IndexVec, + immediate_dominators: &IndexVec>, + node1: Option, + node2: Option, +) -> Option { match (node1, node2) { (None, None) => None, (Some(n), None) | (None, Some(n)) => Some(n), @@ -88,11 +92,12 @@ fn intersect_opt(post_order_rank: &IndexVec, } } -fn intersect(post_order_rank: &IndexVec, - immediate_dominators: &IndexVec>, - mut node1: Node, - mut node2: Node) - -> Node { +fn intersect( + post_order_rank: &IndexVec, + immediate_dominators: &IndexVec>, + mut node1: Node, + mut node2: Node, +) -> Node { while node1 != node2 { while post_order_rank[node1] < post_order_rank[node2] { node1 = immediate_dominators[node1].unwrap(); @@ -176,11 +181,13 @@ impl DominatorTree { impl fmt::Debug for DominatorTree { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&DominatorTreeNode { - tree: self, - node: self.root, - }, - fmt) + fmt::Debug::fmt( + &DominatorTreeNode { + tree: self, + node: self.root, + }, + fmt, + ) } } @@ -194,11 +201,9 @@ impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { let subtrees: Vec<_> = self.tree .children(self.node) .iter() - .map(|&child| { - DominatorTreeNode { - tree: self.tree, - node: child, - } + .map(|&child| DominatorTreeNode { + tree: self.tree, + node: child, }) .collect(); fmt.debug_tuple("") diff --git a/src/librustc_data_structures/control_flow_graph/iterate/mod.rs b/src/librustc_data_structures/control_flow_graph/iterate/mod.rs index 2d70b406342..3afdc88d602 100644 --- a/src/librustc_data_structures/control_flow_graph/iterate/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/iterate/mod.rs @@ -8,20 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::ControlFlowGraph; use super::super::indexed_vec::IndexVec; +use super::{DirectedGraph, WithSuccessors, WithNumNodes}; #[cfg(test)] mod test; -pub fn post_order_from(graph: &G, start_node: G::Node) -> Vec { +pub fn post_order_from( + graph: &G, + start_node: G::Node, +) -> Vec { post_order_from_to(graph, start_node, None) } -pub fn post_order_from_to(graph: &G, - start_node: G::Node, - end_node: Option) - -> Vec { +pub fn post_order_from_to( + graph: &G, + start_node: G::Node, + end_node: Option, +) -> Vec { let mut visited: IndexVec = IndexVec::from_elem_n(false, graph.num_nodes()); let mut result: Vec = Vec::with_capacity(graph.num_nodes()); if let Some(end_node) = end_node { @@ -31,10 +35,12 @@ pub fn post_order_from_to(graph: &G, result } -fn post_order_walk(graph: &G, - node: G::Node, - result: &mut Vec, - visited: &mut IndexVec) { +fn post_order_walk( + graph: &G, + node: G::Node, + result: &mut Vec, + visited: &mut IndexVec, +) { if visited[node] { return; } @@ -47,7 +53,10 @@ fn post_order_walk(graph: &G, result.push(node); } -pub fn reverse_post_order(graph: &G, start_node: G::Node) -> Vec { +pub fn reverse_post_order( + graph: &G, + start_node: G::Node, +) -> Vec { let mut vec = post_order_from(graph, start_node); vec.reverse(); vec diff --git a/src/librustc_data_structures/control_flow_graph/mod.rs b/src/librustc_data_structures/control_flow_graph/mod.rs index 7bf776675c6..cfb4b07b505 100644 --- a/src/librustc_data_structures/control_flow_graph/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/mod.rs @@ -17,26 +17,61 @@ mod reference; #[cfg(test)] mod test; -pub trait ControlFlowGraph - where Self: for<'graph> GraphPredecessors<'graph, Item=::Node>, - Self: for<'graph> GraphSuccessors<'graph, Item=::Node> -{ +pub trait DirectedGraph { type Node: Idx; +} +pub trait WithNumNodes: DirectedGraph { fn num_nodes(&self) -> usize; - fn start_node(&self) -> Self::Node; - fn predecessors<'graph>(&'graph self, node: Self::Node) - -> >::Iter; - fn successors<'graph>(&'graph self, node: Self::Node) - -> >::Iter; } -pub trait GraphPredecessors<'graph> { +pub trait WithSuccessors: DirectedGraph +where + Self: for<'graph> GraphSuccessors<'graph, Item = ::Node>, +{ + fn successors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter; +} + +pub trait GraphSuccessors<'graph> { type Item; type Iter: Iterator; } -pub trait GraphSuccessors<'graph> { +pub trait WithPredecessors: DirectedGraph +where + Self: for<'graph> GraphPredecessors<'graph, Item = ::Node>, +{ + fn predecessors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter; +} + +pub trait GraphPredecessors<'graph> { type Item; type Iter: Iterator; } + +pub trait WithStartNode: DirectedGraph { + fn start_node(&self) -> Self::Node; +} + +pub trait ControlFlowGraph: + DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes +{ + // convenient trait +} + +impl ControlFlowGraph for T +where + T: DirectedGraph + + WithStartNode + + WithPredecessors + + WithStartNode + + WithSuccessors + + WithNumNodes, +{ +} diff --git a/src/librustc_data_structures/control_flow_graph/reference.rs b/src/librustc_data_structures/control_flow_graph/reference.rs index 3b8b01f2ff4..a7b763db8da 100644 --- a/src/librustc_data_structures/control_flow_graph/reference.rs +++ b/src/librustc_data_structures/control_flow_graph/reference.rs @@ -10,34 +10,42 @@ use super::*; -impl<'graph, G: ControlFlowGraph> ControlFlowGraph for &'graph G { +impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G { type Node = G::Node; +} +impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G { fn num_nodes(&self) -> usize { (**self).num_nodes() } +} +impl<'graph, G: WithStartNode> WithStartNode for &'graph G { fn start_node(&self) -> Self::Node { (**self).start_node() } +} + +impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G { + fn successors<'iter>(&'iter self, node: Self::Node) -> >::Iter { + (**self).successors(node) + } +} +impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G { fn predecessors<'iter>(&'iter self, node: Self::Node) -> >::Iter { (**self).predecessors(node) } - - fn successors<'iter>(&'iter self, node: Self::Node) -> >::Iter { - (**self).successors(node) - } } -impl<'iter, 'graph, G: ControlFlowGraph> GraphPredecessors<'iter> for &'graph G { +impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G { type Item = G::Node; type Iter = >::Iter; } -impl<'iter, 'graph, G: ControlFlowGraph> GraphSuccessors<'iter> for &'graph G { +impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G { type Item = G::Node; type Iter = >::Iter; } -- cgit 1.4.1-3-g733a5 From 3c30415e96b2152ce0c1e0474d3e7be0e597abc0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 1 Jul 2018 17:06:00 -0400 Subject: rename `graph` to `control_flow_graph::implementation` --- src/librustc/cfg/construct.rs | 4 +- src/librustc/cfg/mod.rs | 2 +- src/librustc/dep_graph/query.rs | 4 +- src/librustc/infer/lexical_region_resolve/mod.rs | 10 +- src/librustc/middle/dataflow.rs | 2 +- .../control_flow_graph/implementation/mod.rs | 417 +++++++++++++++++++++ .../control_flow_graph/implementation/tests.rs | 139 +++++++ .../control_flow_graph/mod.rs | 1 + src/librustc_data_structures/graph/mod.rs | 417 --------------------- src/librustc_data_structures/graph/tests.rs | 139 ------- src/librustc_data_structures/lib.rs | 1 - src/librustc_incremental/assert_dep_graph.rs | 4 +- 12 files changed, 572 insertions(+), 568 deletions(-) create mode 100644 src/librustc_data_structures/control_flow_graph/implementation/mod.rs create mode 100644 src/librustc_data_structures/control_flow_graph/implementation/tests.rs delete mode 100644 src/librustc_data_structures/graph/mod.rs delete mode 100644 src/librustc_data_structures/graph/tests.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index f52d201abec..9712a4aa0f8 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::graph; use cfg::*; use middle::region; -use ty::{self, TyCtxt}; +use rustc_data_structures::control_flow_graph::implementation as graph; use syntax::ptr::P; +use ty::{self, TyCtxt}; use hir::{self, PatKind}; use hir::def_id::DefId; diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index b379d3956e9..70e86c454f7 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -11,7 +11,7 @@ //! Module that constructs a control-flow graph representing an item. //! Uses `Graph` as the underlying representation. -use rustc_data_structures::graph; +use rustc_data_structures::control_flow_graph::implementation as graph; use ty::TyCtxt; use hir; use hir::def_id::DefId; diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index ea83a4f8b31..c877a8b9bf8 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -9,7 +9,9 @@ // except according to those terms. use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING}; +use rustc_data_structures::control_flow_graph::implementation::{ + Direction, INCOMING, Graph, NodeIndex, OUTGOING +}; use super::DepNode; diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 5984a831e6f..fff1550fdbf 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -20,7 +20,7 @@ use infer::region_constraints::VerifyBound; use middle::free_region::RegionRelations; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING}; +use rustc_data_structures::control_flow_graph::implementation::{Graph, Direction, NodeIndex, INCOMING, OUTGOING}; use std::fmt; use std::u32; use ty::{self, TyCtxt}; @@ -99,7 +99,7 @@ struct RegionAndOrigin<'tcx> { origin: SubregionOrigin<'tcx>, } -type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>; +type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>; struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> { region_rels: &'cx RegionRelations<'cx, 'gcx, 'tcx>, @@ -501,7 +501,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { fn construct_graph(&self) -> RegionGraph<'tcx> { let num_vars = self.num_vars(); - let mut graph = graph::Graph::new(); + let mut graph = Graph::new(); for _ in 0..num_vars { graph.add_node(()); @@ -550,9 +550,9 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. let (mut lower_bounds, lower_dup) = - self.collect_concrete_regions(graph, node_idx, graph::INCOMING, dup_vec); + self.collect_concrete_regions(graph, node_idx, INCOMING, dup_vec); let (mut upper_bounds, upper_dup) = - self.collect_concrete_regions(graph, node_idx, graph::OUTGOING, dup_vec); + self.collect_concrete_regions(graph, node_idx, OUTGOING, dup_vec); if lower_dup || upper_dup { return; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 5c86554f907..78e8f5f9ef3 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -22,7 +22,7 @@ use std::mem; use std::usize; use syntax::print::pprust::PrintState; -use rustc_data_structures::graph::OUTGOING; +use rustc_data_structures::control_flow_graph::implementation::OUTGOING; use util::nodemap::FxHashMap; use hir; diff --git a/src/librustc_data_structures/control_flow_graph/implementation/mod.rs b/src/librustc_data_structures/control_flow_graph/implementation/mod.rs new file mode 100644 index 00000000000..e2b393071ff --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/implementation/mod.rs @@ -0,0 +1,417 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A graph module for use in dataflow, region resolution, and elsewhere. +//! +//! # Interface details +//! +//! You customize the graph by specifying a "node data" type `N` and an +//! "edge data" type `E`. You can then later gain access (mutable or +//! immutable) to these "user-data" bits. Currently, you can only add +//! nodes or edges to the graph. You cannot remove or modify them once +//! added. This could be changed if we have a need. +//! +//! # Implementation details +//! +//! The main tricky thing about this code is the way that edges are +//! stored. The edges are stored in a central array, but they are also +//! threaded onto two linked lists for each node, one for incoming edges +//! and one for outgoing edges. Note that every edge is a member of some +//! incoming list and some outgoing list. Basically you can load the +//! first index of the linked list from the node data structures (the +//! field `first_edge`) and then, for each edge, load the next index from +//! the field `next_edge`). Each of those fields is an array that should +//! be indexed by the direction (see the type `Direction`). + +use bitvec::BitVector; +use std::fmt::Debug; +use std::usize; +use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; + +#[cfg(test)] +mod tests; + +pub struct Graph { + nodes: SnapshotVec>, + edges: SnapshotVec>, +} + +pub struct Node { + first_edge: [EdgeIndex; 2], // see module comment + pub data: N, +} + +#[derive(Debug)] +pub struct Edge { + next_edge: [EdgeIndex; 2], // see module comment + source: NodeIndex, + target: NodeIndex, + pub data: E, +} + +impl SnapshotVecDelegate for Node { + type Value = Node; + type Undo = (); + + fn reverse(_: &mut Vec>, _: ()) {} +} + +impl SnapshotVecDelegate for Edge { + type Value = Edge; + type Undo = (); + + fn reverse(_: &mut Vec>, _: ()) {} +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub struct NodeIndex(pub usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub struct EdgeIndex(pub usize); + +pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); + +// Use a private field here to guarantee no more instances are created: +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Direction { + repr: usize, +} + +pub const OUTGOING: Direction = Direction { repr: 0 }; + +pub const INCOMING: Direction = Direction { repr: 1 }; + +impl NodeIndex { + /// Returns unique id (unique with respect to the graph holding associated node). + pub fn node_id(&self) -> usize { + self.0 + } +} + +impl Graph { + pub fn new() -> Graph { + Graph { + nodes: SnapshotVec::new(), + edges: SnapshotVec::new(), + } + } + + pub fn with_capacity(nodes: usize, edges: usize) -> Graph { + Graph { + nodes: SnapshotVec::with_capacity(nodes), + edges: SnapshotVec::with_capacity(edges), + } + } + + // # Simple accessors + + #[inline] + pub fn all_nodes(&self) -> &[Node] { + &self.nodes + } + + #[inline] + pub fn len_nodes(&self) -> usize { + self.nodes.len() + } + + #[inline] + pub fn all_edges(&self) -> &[Edge] { + &self.edges + } + + #[inline] + pub fn len_edges(&self) -> usize { + self.edges.len() + } + + // # Node construction + + pub fn next_node_index(&self) -> NodeIndex { + NodeIndex(self.nodes.len()) + } + + pub fn add_node(&mut self, data: N) -> NodeIndex { + let idx = self.next_node_index(); + self.nodes.push(Node { + first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], + data, + }); + idx + } + + pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { + &mut self.nodes[idx.0].data + } + + pub fn node_data(&self, idx: NodeIndex) -> &N { + &self.nodes[idx.0].data + } + + pub fn node(&self, idx: NodeIndex) -> &Node { + &self.nodes[idx.0] + } + + // # Edge construction and queries + + pub fn next_edge_index(&self) -> EdgeIndex { + EdgeIndex(self.edges.len()) + } + + pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { + debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); + + let idx = self.next_edge_index(); + + // read current first of the list of edges from each node + let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; + let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; + + // create the new edge, with the previous firsts from each node + // as the next pointers + self.edges.push(Edge { + next_edge: [source_first, target_first], + source, + target, + data, + }); + + // adjust the firsts for each node target be the next object. + self.nodes[source.0].first_edge[OUTGOING.repr] = idx; + self.nodes[target.0].first_edge[INCOMING.repr] = idx; + + return idx; + } + + pub fn edge(&self, idx: EdgeIndex) -> &Edge { + &self.edges[idx.0] + } + + // # Iterating over nodes, edges + + pub fn enumerated_nodes(&self) -> impl Iterator)> { + self.nodes + .iter() + .enumerate() + .map(|(idx, n)| (NodeIndex(idx), n)) + } + + pub fn enumerated_edges(&self) -> impl Iterator)> { + self.edges + .iter() + .enumerate() + .map(|(idx, e)| (EdgeIndex(idx), e)) + } + + pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { + //! Iterates over all edges defined in the graph. + self.enumerated_nodes() + .all(|(node_idx, node)| f(node_idx, node)) + } + + pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { + //! Iterates over all edges defined in the graph + self.enumerated_edges() + .all(|(edge_idx, edge)| f(edge_idx, edge)) + } + + pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { + self.adjacent_edges(source, OUTGOING) + } + + pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges { + self.adjacent_edges(source, INCOMING) + } + + pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges { + let first_edge = self.node(source).first_edge[direction.repr]; + AdjacentEdges { + graph: self, + direction, + next: first_edge, + } + } + + pub fn successor_nodes<'a>( + &'a self, + source: NodeIndex, + ) -> impl Iterator + 'a { + self.outgoing_edges(source).targets() + } + + pub fn predecessor_nodes<'a>( + &'a self, + target: NodeIndex, + ) -> impl Iterator + 'a { + self.incoming_edges(target).sources() + } + + pub fn depth_traverse<'a>( + &'a self, + start: NodeIndex, + direction: Direction, + ) -> DepthFirstTraversal<'a, N, E> { + DepthFirstTraversal::with_start_node(self, start, direction) + } + + pub fn nodes_in_postorder<'a>( + &'a self, + direction: Direction, + entry_node: NodeIndex, + ) -> Vec { + let mut visited = BitVector::new(self.len_nodes()); + let mut stack = vec![]; + let mut result = Vec::with_capacity(self.len_nodes()); + let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { + if visited.insert(node.0) { + stack.push((node, self.adjacent_edges(node, direction))); + } + }; + + for node in Some(entry_node) + .into_iter() + .chain(self.enumerated_nodes().map(|(node, _)| node)) + { + push_node(&mut stack, node); + while let Some((node, mut iter)) = stack.pop() { + if let Some((_, child)) = iter.next() { + let target = child.source_or_target(direction); + // the current node needs more processing, so + // add it back to the stack + stack.push((node, iter)); + // and then push the new node + push_node(&mut stack, target); + } else { + result.push(node); + } + } + } + + assert_eq!(result.len(), self.len_nodes()); + result + } +} + +// # Iterators + +pub struct AdjacentEdges<'g, N, E> +where + N: 'g, + E: 'g, +{ + graph: &'g Graph, + direction: Direction, + next: EdgeIndex, +} + +impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { + fn targets(self) -> impl Iterator + 'g { + self.into_iter().map(|(_, edge)| edge.target) + } + + fn sources(self) -> impl Iterator + 'g { + self.into_iter().map(|(_, edge)| edge.source) + } +} + +impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { + type Item = (EdgeIndex, &'g Edge); + + fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { + let edge_index = self.next; + if edge_index == INVALID_EDGE_INDEX { + return None; + } + + let edge = self.graph.edge(edge_index); + self.next = edge.next_edge[self.direction.repr]; + Some((edge_index, edge)) + } + + fn size_hint(&self) -> (usize, Option) { + // At most, all the edges in the graph. + (0, Some(self.graph.len_edges())) + } +} + +pub struct DepthFirstTraversal<'g, N, E> +where + N: 'g, + E: 'g, +{ + graph: &'g Graph, + stack: Vec, + visited: BitVector, + direction: Direction, +} + +impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { + pub fn with_start_node( + graph: &'g Graph, + start_node: NodeIndex, + direction: Direction, + ) -> Self { + let mut visited = BitVector::new(graph.len_nodes()); + visited.insert(start_node.node_id()); + DepthFirstTraversal { + graph, + stack: vec![start_node], + visited, + direction, + } + } + + fn visit(&mut self, node: NodeIndex) { + if self.visited.insert(node.node_id()) { + self.stack.push(node); + } + } +} + +impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { + type Item = NodeIndex; + + fn next(&mut self) -> Option { + let next = self.stack.pop(); + if let Some(idx) = next { + for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { + let target = edge.source_or_target(self.direction); + self.visit(target); + } + } + next + } + + fn size_hint(&self) -> (usize, Option) { + // We will visit every node in the graph exactly once. + let remaining = self.graph.len_nodes() - self.visited.count(); + (remaining, Some(remaining)) + } +} + +impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} + +impl Edge { + pub fn source(&self) -> NodeIndex { + self.source + } + + pub fn target(&self) -> NodeIndex { + self.target + } + + pub fn source_or_target(&self, direction: Direction) -> NodeIndex { + if direction == OUTGOING { + self.target + } else { + self.source + } + } +} diff --git a/src/librustc_data_structures/control_flow_graph/implementation/tests.rs b/src/librustc_data_structures/control_flow_graph/implementation/tests.rs new file mode 100644 index 00000000000..007704357af --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/implementation/tests.rs @@ -0,0 +1,139 @@ +// 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. + +use graph::*; +use std::fmt::Debug; + +type TestGraph = Graph<&'static str, &'static str>; + +fn create_graph() -> TestGraph { + let mut graph = Graph::new(); + + // Create a simple graph + // + // F + // | + // V + // A --> B --> C + // | ^ + // v | + // D --> E + + let a = graph.add_node("A"); + let b = graph.add_node("B"); + let c = graph.add_node("C"); + let d = graph.add_node("D"); + let e = graph.add_node("E"); + let f = graph.add_node("F"); + + graph.add_edge(a, b, "AB"); + graph.add_edge(b, c, "BC"); + graph.add_edge(b, d, "BD"); + graph.add_edge(d, e, "DE"); + graph.add_edge(e, c, "EC"); + graph.add_edge(f, b, "FB"); + + return graph; +} + +#[test] +fn each_node() { + let graph = create_graph(); + let expected = ["A", "B", "C", "D", "E", "F"]; + graph.each_node(|idx, node| { + assert_eq!(&expected[idx.0], graph.node_data(idx)); + assert_eq!(expected[idx.0], node.data); + true + }); +} + +#[test] +fn each_edge() { + let graph = create_graph(); + let expected = ["AB", "BC", "BD", "DE", "EC", "FB"]; + graph.each_edge(|idx, edge| { + assert_eq!(expected[idx.0], edge.data); + true + }); +} + +fn test_adjacent_edges(graph: &Graph, + start_index: NodeIndex, + start_data: N, + expected_incoming: &[(E, N)], + expected_outgoing: &[(E, N)]) { + assert!(graph.node_data(start_index) == &start_data); + + let mut counter = 0; + for (edge_index, edge) in graph.incoming_edges(start_index) { + assert!(counter < expected_incoming.len()); + debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", + counter, + expected_incoming[counter], + edge_index, + edge); + match expected_incoming[counter] { + (ref e, ref n) => { + assert!(e == &edge.data); + assert!(n == graph.node_data(edge.source())); + assert!(start_index == edge.target); + } + } + counter += 1; + } + assert_eq!(counter, expected_incoming.len()); + + let mut counter = 0; + for (edge_index, edge) in graph.outgoing_edges(start_index) { + assert!(counter < expected_outgoing.len()); + debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", + counter, + expected_outgoing[counter], + edge_index, + edge); + match expected_outgoing[counter] { + (ref e, ref n) => { + assert!(e == &edge.data); + assert!(start_index == edge.source); + assert!(n == graph.node_data(edge.target)); + } + } + counter += 1; + } + assert_eq!(counter, expected_outgoing.len()); +} + +#[test] +fn each_adjacent_from_a() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(0), "A", &[], &[("AB", "B")]); +} + +#[test] +fn each_adjacent_from_b() { + let graph = create_graph(); + test_adjacent_edges(&graph, + NodeIndex(1), + "B", + &[("FB", "F"), ("AB", "A")], + &[("BD", "D"), ("BC", "C")]); +} + +#[test] +fn each_adjacent_from_c() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(2), "C", &[("EC", "E"), ("BC", "B")], &[]); +} + +#[test] +fn each_adjacent_from_d() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]); +} diff --git a/src/librustc_data_structures/control_flow_graph/mod.rs b/src/librustc_data_structures/control_flow_graph/mod.rs index cfb4b07b505..bd933e57b39 100644 --- a/src/librustc_data_structures/control_flow_graph/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/mod.rs @@ -11,6 +11,7 @@ use super::indexed_vec::Idx; pub mod dominators; +pub mod implementation; pub mod iterate; mod reference; diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs deleted file mode 100644 index e2b393071ff..00000000000 --- a/src/librustc_data_structures/graph/mod.rs +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A graph module for use in dataflow, region resolution, and elsewhere. -//! -//! # Interface details -//! -//! You customize the graph by specifying a "node data" type `N` and an -//! "edge data" type `E`. You can then later gain access (mutable or -//! immutable) to these "user-data" bits. Currently, you can only add -//! nodes or edges to the graph. You cannot remove or modify them once -//! added. This could be changed if we have a need. -//! -//! # Implementation details -//! -//! The main tricky thing about this code is the way that edges are -//! stored. The edges are stored in a central array, but they are also -//! threaded onto two linked lists for each node, one for incoming edges -//! and one for outgoing edges. Note that every edge is a member of some -//! incoming list and some outgoing list. Basically you can load the -//! first index of the linked list from the node data structures (the -//! field `first_edge`) and then, for each edge, load the next index from -//! the field `next_edge`). Each of those fields is an array that should -//! be indexed by the direction (see the type `Direction`). - -use bitvec::BitVector; -use std::fmt::Debug; -use std::usize; -use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; - -#[cfg(test)] -mod tests; - -pub struct Graph { - nodes: SnapshotVec>, - edges: SnapshotVec>, -} - -pub struct Node { - first_edge: [EdgeIndex; 2], // see module comment - pub data: N, -} - -#[derive(Debug)] -pub struct Edge { - next_edge: [EdgeIndex; 2], // see module comment - source: NodeIndex, - target: NodeIndex, - pub data: E, -} - -impl SnapshotVecDelegate for Node { - type Value = Node; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -impl SnapshotVecDelegate for Edge { - type Value = Edge; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub struct NodeIndex(pub usize); - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub struct EdgeIndex(pub usize); - -pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); - -// Use a private field here to guarantee no more instances are created: -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Direction { - repr: usize, -} - -pub const OUTGOING: Direction = Direction { repr: 0 }; - -pub const INCOMING: Direction = Direction { repr: 1 }; - -impl NodeIndex { - /// Returns unique id (unique with respect to the graph holding associated node). - pub fn node_id(&self) -> usize { - self.0 - } -} - -impl Graph { - pub fn new() -> Graph { - Graph { - nodes: SnapshotVec::new(), - edges: SnapshotVec::new(), - } - } - - pub fn with_capacity(nodes: usize, edges: usize) -> Graph { - Graph { - nodes: SnapshotVec::with_capacity(nodes), - edges: SnapshotVec::with_capacity(edges), - } - } - - // # Simple accessors - - #[inline] - pub fn all_nodes(&self) -> &[Node] { - &self.nodes - } - - #[inline] - pub fn len_nodes(&self) -> usize { - self.nodes.len() - } - - #[inline] - pub fn all_edges(&self) -> &[Edge] { - &self.edges - } - - #[inline] - pub fn len_edges(&self) -> usize { - self.edges.len() - } - - // # Node construction - - pub fn next_node_index(&self) -> NodeIndex { - NodeIndex(self.nodes.len()) - } - - pub fn add_node(&mut self, data: N) -> NodeIndex { - let idx = self.next_node_index(); - self.nodes.push(Node { - first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], - data, - }); - idx - } - - pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { - &mut self.nodes[idx.0].data - } - - pub fn node_data(&self, idx: NodeIndex) -> &N { - &self.nodes[idx.0].data - } - - pub fn node(&self, idx: NodeIndex) -> &Node { - &self.nodes[idx.0] - } - - // # Edge construction and queries - - pub fn next_edge_index(&self) -> EdgeIndex { - EdgeIndex(self.edges.len()) - } - - pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { - debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); - - let idx = self.next_edge_index(); - - // read current first of the list of edges from each node - let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; - let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; - - // create the new edge, with the previous firsts from each node - // as the next pointers - self.edges.push(Edge { - next_edge: [source_first, target_first], - source, - target, - data, - }); - - // adjust the firsts for each node target be the next object. - self.nodes[source.0].first_edge[OUTGOING.repr] = idx; - self.nodes[target.0].first_edge[INCOMING.repr] = idx; - - return idx; - } - - pub fn edge(&self, idx: EdgeIndex) -> &Edge { - &self.edges[idx.0] - } - - // # Iterating over nodes, edges - - pub fn enumerated_nodes(&self) -> impl Iterator)> { - self.nodes - .iter() - .enumerate() - .map(|(idx, n)| (NodeIndex(idx), n)) - } - - pub fn enumerated_edges(&self) -> impl Iterator)> { - self.edges - .iter() - .enumerate() - .map(|(idx, e)| (EdgeIndex(idx), e)) - } - - pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { - //! Iterates over all edges defined in the graph. - self.enumerated_nodes() - .all(|(node_idx, node)| f(node_idx, node)) - } - - pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { - //! Iterates over all edges defined in the graph - self.enumerated_edges() - .all(|(edge_idx, edge)| f(edge_idx, edge)) - } - - pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { - self.adjacent_edges(source, OUTGOING) - } - - pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges { - self.adjacent_edges(source, INCOMING) - } - - pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges { - let first_edge = self.node(source).first_edge[direction.repr]; - AdjacentEdges { - graph: self, - direction, - next: first_edge, - } - } - - pub fn successor_nodes<'a>( - &'a self, - source: NodeIndex, - ) -> impl Iterator + 'a { - self.outgoing_edges(source).targets() - } - - pub fn predecessor_nodes<'a>( - &'a self, - target: NodeIndex, - ) -> impl Iterator + 'a { - self.incoming_edges(target).sources() - } - - pub fn depth_traverse<'a>( - &'a self, - start: NodeIndex, - direction: Direction, - ) -> DepthFirstTraversal<'a, N, E> { - DepthFirstTraversal::with_start_node(self, start, direction) - } - - pub fn nodes_in_postorder<'a>( - &'a self, - direction: Direction, - entry_node: NodeIndex, - ) -> Vec { - let mut visited = BitVector::new(self.len_nodes()); - let mut stack = vec![]; - let mut result = Vec::with_capacity(self.len_nodes()); - let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { - if visited.insert(node.0) { - stack.push((node, self.adjacent_edges(node, direction))); - } - }; - - for node in Some(entry_node) - .into_iter() - .chain(self.enumerated_nodes().map(|(node, _)| node)) - { - push_node(&mut stack, node); - while let Some((node, mut iter)) = stack.pop() { - if let Some((_, child)) = iter.next() { - let target = child.source_or_target(direction); - // the current node needs more processing, so - // add it back to the stack - stack.push((node, iter)); - // and then push the new node - push_node(&mut stack, target); - } else { - result.push(node); - } - } - } - - assert_eq!(result.len(), self.len_nodes()); - result - } -} - -// # Iterators - -pub struct AdjacentEdges<'g, N, E> -where - N: 'g, - E: 'g, -{ - graph: &'g Graph, - direction: Direction, - next: EdgeIndex, -} - -impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { - fn targets(self) -> impl Iterator + 'g { - self.into_iter().map(|(_, edge)| edge.target) - } - - fn sources(self) -> impl Iterator + 'g { - self.into_iter().map(|(_, edge)| edge.source) - } -} - -impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { - type Item = (EdgeIndex, &'g Edge); - - fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { - let edge_index = self.next; - if edge_index == INVALID_EDGE_INDEX { - return None; - } - - let edge = self.graph.edge(edge_index); - self.next = edge.next_edge[self.direction.repr]; - Some((edge_index, edge)) - } - - fn size_hint(&self) -> (usize, Option) { - // At most, all the edges in the graph. - (0, Some(self.graph.len_edges())) - } -} - -pub struct DepthFirstTraversal<'g, N, E> -where - N: 'g, - E: 'g, -{ - graph: &'g Graph, - stack: Vec, - visited: BitVector, - direction: Direction, -} - -impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { - pub fn with_start_node( - graph: &'g Graph, - start_node: NodeIndex, - direction: Direction, - ) -> Self { - let mut visited = BitVector::new(graph.len_nodes()); - visited.insert(start_node.node_id()); - DepthFirstTraversal { - graph, - stack: vec![start_node], - visited, - direction, - } - } - - fn visit(&mut self, node: NodeIndex) { - if self.visited.insert(node.node_id()) { - self.stack.push(node); - } - } -} - -impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { - type Item = NodeIndex; - - fn next(&mut self) -> Option { - let next = self.stack.pop(); - if let Some(idx) = next { - for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { - let target = edge.source_or_target(self.direction); - self.visit(target); - } - } - next - } - - fn size_hint(&self) -> (usize, Option) { - // We will visit every node in the graph exactly once. - let remaining = self.graph.len_nodes() - self.visited.count(); - (remaining, Some(remaining)) - } -} - -impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} - -impl Edge { - pub fn source(&self) -> NodeIndex { - self.source - } - - pub fn target(&self) -> NodeIndex { - self.target - } - - pub fn source_or_target(&self, direction: Direction) -> NodeIndex { - if direction == OUTGOING { - self.target - } else { - self.source - } - } -} diff --git a/src/librustc_data_structures/graph/tests.rs b/src/librustc_data_structures/graph/tests.rs deleted file mode 100644 index 007704357af..00000000000 --- a/src/librustc_data_structures/graph/tests.rs +++ /dev/null @@ -1,139 +0,0 @@ -// 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. - -use graph::*; -use std::fmt::Debug; - -type TestGraph = Graph<&'static str, &'static str>; - -fn create_graph() -> TestGraph { - let mut graph = Graph::new(); - - // Create a simple graph - // - // F - // | - // V - // A --> B --> C - // | ^ - // v | - // D --> E - - let a = graph.add_node("A"); - let b = graph.add_node("B"); - let c = graph.add_node("C"); - let d = graph.add_node("D"); - let e = graph.add_node("E"); - let f = graph.add_node("F"); - - graph.add_edge(a, b, "AB"); - graph.add_edge(b, c, "BC"); - graph.add_edge(b, d, "BD"); - graph.add_edge(d, e, "DE"); - graph.add_edge(e, c, "EC"); - graph.add_edge(f, b, "FB"); - - return graph; -} - -#[test] -fn each_node() { - let graph = create_graph(); - let expected = ["A", "B", "C", "D", "E", "F"]; - graph.each_node(|idx, node| { - assert_eq!(&expected[idx.0], graph.node_data(idx)); - assert_eq!(expected[idx.0], node.data); - true - }); -} - -#[test] -fn each_edge() { - let graph = create_graph(); - let expected = ["AB", "BC", "BD", "DE", "EC", "FB"]; - graph.each_edge(|idx, edge| { - assert_eq!(expected[idx.0], edge.data); - true - }); -} - -fn test_adjacent_edges(graph: &Graph, - start_index: NodeIndex, - start_data: N, - expected_incoming: &[(E, N)], - expected_outgoing: &[(E, N)]) { - assert!(graph.node_data(start_index) == &start_data); - - let mut counter = 0; - for (edge_index, edge) in graph.incoming_edges(start_index) { - assert!(counter < expected_incoming.len()); - debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, - expected_incoming[counter], - edge_index, - edge); - match expected_incoming[counter] { - (ref e, ref n) => { - assert!(e == &edge.data); - assert!(n == graph.node_data(edge.source())); - assert!(start_index == edge.target); - } - } - counter += 1; - } - assert_eq!(counter, expected_incoming.len()); - - let mut counter = 0; - for (edge_index, edge) in graph.outgoing_edges(start_index) { - assert!(counter < expected_outgoing.len()); - debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, - expected_outgoing[counter], - edge_index, - edge); - match expected_outgoing[counter] { - (ref e, ref n) => { - assert!(e == &edge.data); - assert!(start_index == edge.source); - assert!(n == graph.node_data(edge.target)); - } - } - counter += 1; - } - assert_eq!(counter, expected_outgoing.len()); -} - -#[test] -fn each_adjacent_from_a() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(0), "A", &[], &[("AB", "B")]); -} - -#[test] -fn each_adjacent_from_b() { - let graph = create_graph(); - test_adjacent_edges(&graph, - NodeIndex(1), - "B", - &[("FB", "F"), ("AB", "A")], - &[("BD", "D"), ("BC", "C")]); -} - -#[test] -fn each_adjacent_from_c() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(2), "C", &[("EC", "E"), ("BC", "B")], &[]); -} - -#[test] -fn each_adjacent_from_d() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]); -} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index e4d0bc596cb..59b7b430083 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -59,7 +59,6 @@ pub mod small_vec; pub mod base_n; pub mod bitslice; pub mod bitvec; -pub mod graph; pub mod indexed_set; pub mod indexed_vec; pub mod obligation_forest; diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index c317d31b95a..39cb952a385 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -49,7 +49,9 @@ use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex}; +use rustc_data_structures::control_flow_graph::implementation::{ + Direction, INCOMING, OUTGOING, NodeIndex +}; use rustc::hir; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::ich::{ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED}; -- cgit 1.4.1-3-g733a5 From 90c90ba542635c3f2d1da71cb42569b6e7eeb6a9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Jul 2018 06:14:49 -0400 Subject: rename `control_flow_graph` to `graph` --- src/librustc/cfg/construct.rs | 2 +- src/librustc/cfg/mod.rs | 2 +- src/librustc/dep_graph/query.rs | 2 +- src/librustc/infer/lexical_region_resolve/mod.rs | 2 +- src/librustc/middle/dataflow.rs | 2 +- src/librustc/mir/mod.rs | 20 +- src/librustc_codegen_llvm/mir/analyze.rs | 2 +- .../control_flow_graph/dominators/mod.rs | 214 ----------- .../control_flow_graph/dominators/test.rs | 43 --- .../control_flow_graph/implementation/mod.rs | 417 --------------------- .../control_flow_graph/implementation/tests.rs | 139 ------- .../control_flow_graph/iterate/mod.rs | 63 ---- .../control_flow_graph/iterate/test.rs | 21 -- .../control_flow_graph/mod.rs | 78 ---- .../control_flow_graph/reference.rs | 51 --- .../control_flow_graph/test.rs | 77 ---- .../graph/dominators/mod.rs | 214 +++++++++++ .../graph/dominators/test.rs | 43 +++ .../graph/implementation/mod.rs | 417 +++++++++++++++++++++ .../graph/implementation/tests.rs | 139 +++++++ src/librustc_data_structures/graph/iterate/mod.rs | 63 ++++ src/librustc_data_structures/graph/iterate/test.rs | 21 ++ src/librustc_data_structures/graph/mod.rs | 78 ++++ src/librustc_data_structures/graph/reference.rs | 51 +++ src/librustc_data_structures/graph/test.rs | 77 ++++ src/librustc_data_structures/lib.rs | 2 +- src/librustc_incremental/assert_dep_graph.rs | 2 +- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_mir/borrow_check/nll/invalidation.rs | 2 +- src/librustc_mir/borrow_check/path_utils.rs | 2 +- 30 files changed, 1124 insertions(+), 1124 deletions(-) delete mode 100644 src/librustc_data_structures/control_flow_graph/dominators/mod.rs delete mode 100644 src/librustc_data_structures/control_flow_graph/dominators/test.rs delete mode 100644 src/librustc_data_structures/control_flow_graph/implementation/mod.rs delete mode 100644 src/librustc_data_structures/control_flow_graph/implementation/tests.rs delete mode 100644 src/librustc_data_structures/control_flow_graph/iterate/mod.rs delete mode 100644 src/librustc_data_structures/control_flow_graph/iterate/test.rs delete mode 100644 src/librustc_data_structures/control_flow_graph/mod.rs delete mode 100644 src/librustc_data_structures/control_flow_graph/reference.rs delete mode 100644 src/librustc_data_structures/control_flow_graph/test.rs create mode 100644 src/librustc_data_structures/graph/dominators/mod.rs create mode 100644 src/librustc_data_structures/graph/dominators/test.rs create mode 100644 src/librustc_data_structures/graph/implementation/mod.rs create mode 100644 src/librustc_data_structures/graph/implementation/tests.rs create mode 100644 src/librustc_data_structures/graph/iterate/mod.rs create mode 100644 src/librustc_data_structures/graph/iterate/test.rs create mode 100644 src/librustc_data_structures/graph/mod.rs create mode 100644 src/librustc_data_structures/graph/reference.rs create mode 100644 src/librustc_data_structures/graph/test.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 9712a4aa0f8..aab70456dc1 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -10,7 +10,7 @@ use cfg::*; use middle::region; -use rustc_data_structures::control_flow_graph::implementation as graph; +use rustc_data_structures::graph::implementation as graph; use syntax::ptr::P; use ty::{self, TyCtxt}; diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index 70e86c454f7..cf9c24cc58a 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -11,7 +11,7 @@ //! Module that constructs a control-flow graph representing an item. //! Uses `Graph` as the underlying representation. -use rustc_data_structures::control_flow_graph::implementation as graph; +use rustc_data_structures::graph::implementation as graph; use ty::TyCtxt; use hir; use hir::def_id::DefId; diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index c877a8b9bf8..ce0b5557a34 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::control_flow_graph::implementation::{ +use rustc_data_structures::graph::implementation::{ Direction, INCOMING, Graph, NodeIndex, OUTGOING }; diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index fff1550fdbf..120b45ec01e 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -20,7 +20,7 @@ use infer::region_constraints::VerifyBound; use middle::free_region::RegionRelations; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::control_flow_graph::implementation::{Graph, Direction, NodeIndex, INCOMING, OUTGOING}; +use rustc_data_structures::graph::implementation::{Graph, Direction, NodeIndex, INCOMING, OUTGOING}; use std::fmt; use std::u32; use ty::{self, TyCtxt}; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 78e8f5f9ef3..b949fd02126 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -22,7 +22,7 @@ use std::mem; use std::usize; use syntax::print::pprust::PrintState; -use rustc_data_structures::control_flow_graph::implementation::OUTGOING; +use rustc_data_structures::graph::implementation::OUTGOING; use util::nodemap::FxHashMap; use hir; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 1ce5742b464..ea6ddd9e55a 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -21,9 +21,9 @@ use mir::interpret::{EvalErrorKind, Scalar, Value}; use mir::visit::MirVisitable; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; -use rustc_data_structures::control_flow_graph::dominators::{dominators, Dominators}; -use rustc_data_structures::control_flow_graph; -use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; +use rustc_data_structures::graph::dominators::{dominators, Dominators}; +use rustc_data_structures::graph; +use rustc_data_structures::graph::{GraphPredecessors, GraphSuccessors}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::sync::Lrc; @@ -2289,23 +2289,23 @@ fn item_path_str(def_id: DefId) -> String { ty::tls::with(|tcx| tcx.item_path_str(def_id)) } -impl<'tcx> control_flow_graph::DirectedGraph for Mir<'tcx> { +impl<'tcx> graph::DirectedGraph for Mir<'tcx> { type Node = BasicBlock; } -impl<'tcx> control_flow_graph::WithNumNodes for Mir<'tcx> { +impl<'tcx> graph::WithNumNodes for Mir<'tcx> { fn num_nodes(&self) -> usize { self.basic_blocks.len() } } -impl<'tcx> control_flow_graph::WithStartNode for Mir<'tcx> { +impl<'tcx> graph::WithStartNode for Mir<'tcx> { fn start_node(&self) -> Self::Node { START_BLOCK } } -impl<'tcx> control_flow_graph::WithPredecessors for Mir<'tcx> { +impl<'tcx> graph::WithPredecessors for Mir<'tcx> { fn predecessors<'graph>( &'graph self, node: Self::Node, @@ -2314,7 +2314,7 @@ impl<'tcx> control_flow_graph::WithPredecessors for Mir<'tcx> { } } -impl<'tcx> control_flow_graph::WithSuccessors for Mir<'tcx> { +impl<'tcx> graph::WithSuccessors for Mir<'tcx> { fn successors<'graph>( &'graph self, node: Self::Node, @@ -2323,12 +2323,12 @@ impl<'tcx> control_flow_graph::WithSuccessors for Mir<'tcx> { } } -impl<'a, 'b> control_flow_graph::GraphPredecessors<'b> for Mir<'a> { +impl<'a, 'b> graph::GraphPredecessors<'b> for Mir<'a> { type Item = BasicBlock; type Iter = IntoIter; } -impl<'a, 'b> control_flow_graph::GraphSuccessors<'b> for Mir<'a> { +impl<'a, 'b> graph::GraphSuccessors<'b> for Mir<'a> { type Item = BasicBlock; type Iter = iter::Cloned>; } diff --git a/src/librustc_codegen_llvm/mir/analyze.rs b/src/librustc_codegen_llvm/mir/analyze.rs index 9e5298eb736..efd829c283f 100644 --- a/src/librustc_codegen_llvm/mir/analyze.rs +++ b/src/librustc_codegen_llvm/mir/analyze.rs @@ -12,7 +12,7 @@ //! which do not. use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::control_flow_graph::dominators::Dominators; +use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::{self, Location, TerminatorKind}; use rustc::mir::visit::{Visitor, PlaceContext}; diff --git a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs deleted file mode 100644 index d134fad2855..00000000000 --- a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs +++ /dev/null @@ -1,214 +0,0 @@ -// 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. - -//! Algorithm citation: -//! A Simple, Fast Dominance Algorithm. -//! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy -//! Rice Computer Science TS-06-33870 -//! - -use super::super::indexed_vec::{Idx, IndexVec}; -use super::iterate::reverse_post_order; -use super::ControlFlowGraph; - -use std::fmt; - -#[cfg(test)] -mod test; - -pub fn dominators(graph: &G) -> Dominators { - let start_node = graph.start_node(); - let rpo = reverse_post_order(graph, start_node); - dominators_given_rpo(graph, &rpo) -} - -pub fn dominators_given_rpo( - graph: &G, - rpo: &[G::Node], -) -> Dominators { - let start_node = graph.start_node(); - assert_eq!(rpo[0], start_node); - - // compute the post order index (rank) for each node - let mut post_order_rank: IndexVec = - IndexVec::from_elem_n(usize::default(), graph.num_nodes()); - for (index, node) in rpo.iter().rev().cloned().enumerate() { - post_order_rank[node] = index; - } - - let mut immediate_dominators: IndexVec> = - IndexVec::from_elem_n(Option::default(), graph.num_nodes()); - immediate_dominators[start_node] = Some(start_node); - - let mut changed = true; - while changed { - changed = false; - - for &node in &rpo[1..] { - let mut new_idom = None; - for pred in graph.predecessors(node) { - if immediate_dominators[pred].is_some() { - // (*) - // (*) dominators for `pred` have been calculated - new_idom = intersect_opt( - &post_order_rank, - &immediate_dominators, - new_idom, - Some(pred), - ); - } - } - - if new_idom != immediate_dominators[node] { - immediate_dominators[node] = new_idom; - changed = true; - } - } - } - - Dominators { - post_order_rank, - immediate_dominators, - } -} - -fn intersect_opt( - post_order_rank: &IndexVec, - immediate_dominators: &IndexVec>, - node1: Option, - node2: Option, -) -> Option { - match (node1, node2) { - (None, None) => None, - (Some(n), None) | (None, Some(n)) => Some(n), - (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)), - } -} - -fn intersect( - post_order_rank: &IndexVec, - immediate_dominators: &IndexVec>, - mut node1: Node, - mut node2: Node, -) -> Node { - while node1 != node2 { - while post_order_rank[node1] < post_order_rank[node2] { - node1 = immediate_dominators[node1].unwrap(); - } - - while post_order_rank[node2] < post_order_rank[node1] { - node2 = immediate_dominators[node2].unwrap(); - } - } - return node1; -} - -#[derive(Clone, Debug)] -pub struct Dominators { - post_order_rank: IndexVec, - immediate_dominators: IndexVec>, -} - -impl Dominators { - pub fn is_reachable(&self, node: Node) -> bool { - self.immediate_dominators[node].is_some() - } - - pub fn immediate_dominator(&self, node: Node) -> Node { - assert!(self.is_reachable(node), "node {:?} is not reachable", node); - self.immediate_dominators[node].unwrap() - } - - pub fn dominators(&self, node: Node) -> Iter { - assert!(self.is_reachable(node), "node {:?} is not reachable", node); - Iter { - dominators: self, - node: Some(node), - } - } - - pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool { - // FIXME -- could be optimized by using post-order-rank - self.dominators(node).any(|n| n == dom) - } - - #[cfg(test)] - fn all_immediate_dominators(&self) -> &IndexVec> { - &self.immediate_dominators - } -} - -pub struct Iter<'dom, Node: Idx + 'dom> { - dominators: &'dom Dominators, - node: Option, -} - -impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { - type Item = Node; - - fn next(&mut self) -> Option { - if let Some(node) = self.node { - let dom = self.dominators.immediate_dominator(node); - if dom == node { - self.node = None; // reached the root - } else { - self.node = Some(dom); - } - return Some(node); - } else { - return None; - } - } -} - -pub struct DominatorTree { - root: N, - children: IndexVec>, -} - -impl DominatorTree { - pub fn children(&self, node: Node) -> &[Node] { - &self.children[node] - } -} - -impl fmt::Debug for DominatorTree { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt( - &DominatorTreeNode { - tree: self, - node: self.root, - }, - fmt, - ) - } -} - -struct DominatorTreeNode<'tree, Node: Idx> { - tree: &'tree DominatorTree, - node: Node, -} - -impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let subtrees: Vec<_> = self.tree - .children(self.node) - .iter() - .map(|&child| DominatorTreeNode { - tree: self.tree, - node: child, - }) - .collect(); - fmt.debug_tuple("") - .field(&self.node) - .field(&subtrees) - .finish() - } -} diff --git a/src/librustc_data_structures/control_flow_graph/dominators/test.rs b/src/librustc_data_structures/control_flow_graph/dominators/test.rs deleted file mode 100644 index 0af878cac2d..00000000000 --- a/src/librustc_data_structures/control_flow_graph/dominators/test.rs +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -use super::super::test::TestGraph; - -use super::*; - -#[test] -fn diamond() { - let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); - - let dominators = dominators(&graph); - let immediate_dominators = dominators.all_immediate_dominators(); - assert_eq!(immediate_dominators[0], Some(0)); - assert_eq!(immediate_dominators[1], Some(0)); - assert_eq!(immediate_dominators[2], Some(0)); - assert_eq!(immediate_dominators[3], Some(0)); -} - -#[test] -fn paper() { - // example from the paper: - let graph = TestGraph::new(6, - &[(6, 5), (6, 4), (5, 1), (4, 2), (4, 3), (1, 2), (2, 3), (3, 2), - (2, 1)]); - - let dominators = dominators(&graph); - let immediate_dominators = dominators.all_immediate_dominators(); - assert_eq!(immediate_dominators[0], None); // <-- note that 0 is not in graph - assert_eq!(immediate_dominators[1], Some(6)); - assert_eq!(immediate_dominators[2], Some(6)); - assert_eq!(immediate_dominators[3], Some(6)); - assert_eq!(immediate_dominators[4], Some(6)); - assert_eq!(immediate_dominators[5], Some(6)); - assert_eq!(immediate_dominators[6], Some(6)); -} diff --git a/src/librustc_data_structures/control_flow_graph/implementation/mod.rs b/src/librustc_data_structures/control_flow_graph/implementation/mod.rs deleted file mode 100644 index e2b393071ff..00000000000 --- a/src/librustc_data_structures/control_flow_graph/implementation/mod.rs +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A graph module for use in dataflow, region resolution, and elsewhere. -//! -//! # Interface details -//! -//! You customize the graph by specifying a "node data" type `N` and an -//! "edge data" type `E`. You can then later gain access (mutable or -//! immutable) to these "user-data" bits. Currently, you can only add -//! nodes or edges to the graph. You cannot remove or modify them once -//! added. This could be changed if we have a need. -//! -//! # Implementation details -//! -//! The main tricky thing about this code is the way that edges are -//! stored. The edges are stored in a central array, but they are also -//! threaded onto two linked lists for each node, one for incoming edges -//! and one for outgoing edges. Note that every edge is a member of some -//! incoming list and some outgoing list. Basically you can load the -//! first index of the linked list from the node data structures (the -//! field `first_edge`) and then, for each edge, load the next index from -//! the field `next_edge`). Each of those fields is an array that should -//! be indexed by the direction (see the type `Direction`). - -use bitvec::BitVector; -use std::fmt::Debug; -use std::usize; -use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; - -#[cfg(test)] -mod tests; - -pub struct Graph { - nodes: SnapshotVec>, - edges: SnapshotVec>, -} - -pub struct Node { - first_edge: [EdgeIndex; 2], // see module comment - pub data: N, -} - -#[derive(Debug)] -pub struct Edge { - next_edge: [EdgeIndex; 2], // see module comment - source: NodeIndex, - target: NodeIndex, - pub data: E, -} - -impl SnapshotVecDelegate for Node { - type Value = Node; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -impl SnapshotVecDelegate for Edge { - type Value = Edge; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub struct NodeIndex(pub usize); - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub struct EdgeIndex(pub usize); - -pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); - -// Use a private field here to guarantee no more instances are created: -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Direction { - repr: usize, -} - -pub const OUTGOING: Direction = Direction { repr: 0 }; - -pub const INCOMING: Direction = Direction { repr: 1 }; - -impl NodeIndex { - /// Returns unique id (unique with respect to the graph holding associated node). - pub fn node_id(&self) -> usize { - self.0 - } -} - -impl Graph { - pub fn new() -> Graph { - Graph { - nodes: SnapshotVec::new(), - edges: SnapshotVec::new(), - } - } - - pub fn with_capacity(nodes: usize, edges: usize) -> Graph { - Graph { - nodes: SnapshotVec::with_capacity(nodes), - edges: SnapshotVec::with_capacity(edges), - } - } - - // # Simple accessors - - #[inline] - pub fn all_nodes(&self) -> &[Node] { - &self.nodes - } - - #[inline] - pub fn len_nodes(&self) -> usize { - self.nodes.len() - } - - #[inline] - pub fn all_edges(&self) -> &[Edge] { - &self.edges - } - - #[inline] - pub fn len_edges(&self) -> usize { - self.edges.len() - } - - // # Node construction - - pub fn next_node_index(&self) -> NodeIndex { - NodeIndex(self.nodes.len()) - } - - pub fn add_node(&mut self, data: N) -> NodeIndex { - let idx = self.next_node_index(); - self.nodes.push(Node { - first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], - data, - }); - idx - } - - pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { - &mut self.nodes[idx.0].data - } - - pub fn node_data(&self, idx: NodeIndex) -> &N { - &self.nodes[idx.0].data - } - - pub fn node(&self, idx: NodeIndex) -> &Node { - &self.nodes[idx.0] - } - - // # Edge construction and queries - - pub fn next_edge_index(&self) -> EdgeIndex { - EdgeIndex(self.edges.len()) - } - - pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { - debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); - - let idx = self.next_edge_index(); - - // read current first of the list of edges from each node - let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; - let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; - - // create the new edge, with the previous firsts from each node - // as the next pointers - self.edges.push(Edge { - next_edge: [source_first, target_first], - source, - target, - data, - }); - - // adjust the firsts for each node target be the next object. - self.nodes[source.0].first_edge[OUTGOING.repr] = idx; - self.nodes[target.0].first_edge[INCOMING.repr] = idx; - - return idx; - } - - pub fn edge(&self, idx: EdgeIndex) -> &Edge { - &self.edges[idx.0] - } - - // # Iterating over nodes, edges - - pub fn enumerated_nodes(&self) -> impl Iterator)> { - self.nodes - .iter() - .enumerate() - .map(|(idx, n)| (NodeIndex(idx), n)) - } - - pub fn enumerated_edges(&self) -> impl Iterator)> { - self.edges - .iter() - .enumerate() - .map(|(idx, e)| (EdgeIndex(idx), e)) - } - - pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { - //! Iterates over all edges defined in the graph. - self.enumerated_nodes() - .all(|(node_idx, node)| f(node_idx, node)) - } - - pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { - //! Iterates over all edges defined in the graph - self.enumerated_edges() - .all(|(edge_idx, edge)| f(edge_idx, edge)) - } - - pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { - self.adjacent_edges(source, OUTGOING) - } - - pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges { - self.adjacent_edges(source, INCOMING) - } - - pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges { - let first_edge = self.node(source).first_edge[direction.repr]; - AdjacentEdges { - graph: self, - direction, - next: first_edge, - } - } - - pub fn successor_nodes<'a>( - &'a self, - source: NodeIndex, - ) -> impl Iterator + 'a { - self.outgoing_edges(source).targets() - } - - pub fn predecessor_nodes<'a>( - &'a self, - target: NodeIndex, - ) -> impl Iterator + 'a { - self.incoming_edges(target).sources() - } - - pub fn depth_traverse<'a>( - &'a self, - start: NodeIndex, - direction: Direction, - ) -> DepthFirstTraversal<'a, N, E> { - DepthFirstTraversal::with_start_node(self, start, direction) - } - - pub fn nodes_in_postorder<'a>( - &'a self, - direction: Direction, - entry_node: NodeIndex, - ) -> Vec { - let mut visited = BitVector::new(self.len_nodes()); - let mut stack = vec![]; - let mut result = Vec::with_capacity(self.len_nodes()); - let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { - if visited.insert(node.0) { - stack.push((node, self.adjacent_edges(node, direction))); - } - }; - - for node in Some(entry_node) - .into_iter() - .chain(self.enumerated_nodes().map(|(node, _)| node)) - { - push_node(&mut stack, node); - while let Some((node, mut iter)) = stack.pop() { - if let Some((_, child)) = iter.next() { - let target = child.source_or_target(direction); - // the current node needs more processing, so - // add it back to the stack - stack.push((node, iter)); - // and then push the new node - push_node(&mut stack, target); - } else { - result.push(node); - } - } - } - - assert_eq!(result.len(), self.len_nodes()); - result - } -} - -// # Iterators - -pub struct AdjacentEdges<'g, N, E> -where - N: 'g, - E: 'g, -{ - graph: &'g Graph, - direction: Direction, - next: EdgeIndex, -} - -impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { - fn targets(self) -> impl Iterator + 'g { - self.into_iter().map(|(_, edge)| edge.target) - } - - fn sources(self) -> impl Iterator + 'g { - self.into_iter().map(|(_, edge)| edge.source) - } -} - -impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { - type Item = (EdgeIndex, &'g Edge); - - fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { - let edge_index = self.next; - if edge_index == INVALID_EDGE_INDEX { - return None; - } - - let edge = self.graph.edge(edge_index); - self.next = edge.next_edge[self.direction.repr]; - Some((edge_index, edge)) - } - - fn size_hint(&self) -> (usize, Option) { - // At most, all the edges in the graph. - (0, Some(self.graph.len_edges())) - } -} - -pub struct DepthFirstTraversal<'g, N, E> -where - N: 'g, - E: 'g, -{ - graph: &'g Graph, - stack: Vec, - visited: BitVector, - direction: Direction, -} - -impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { - pub fn with_start_node( - graph: &'g Graph, - start_node: NodeIndex, - direction: Direction, - ) -> Self { - let mut visited = BitVector::new(graph.len_nodes()); - visited.insert(start_node.node_id()); - DepthFirstTraversal { - graph, - stack: vec![start_node], - visited, - direction, - } - } - - fn visit(&mut self, node: NodeIndex) { - if self.visited.insert(node.node_id()) { - self.stack.push(node); - } - } -} - -impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { - type Item = NodeIndex; - - fn next(&mut self) -> Option { - let next = self.stack.pop(); - if let Some(idx) = next { - for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { - let target = edge.source_or_target(self.direction); - self.visit(target); - } - } - next - } - - fn size_hint(&self) -> (usize, Option) { - // We will visit every node in the graph exactly once. - let remaining = self.graph.len_nodes() - self.visited.count(); - (remaining, Some(remaining)) - } -} - -impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} - -impl Edge { - pub fn source(&self) -> NodeIndex { - self.source - } - - pub fn target(&self) -> NodeIndex { - self.target - } - - pub fn source_or_target(&self, direction: Direction) -> NodeIndex { - if direction == OUTGOING { - self.target - } else { - self.source - } - } -} diff --git a/src/librustc_data_structures/control_flow_graph/implementation/tests.rs b/src/librustc_data_structures/control_flow_graph/implementation/tests.rs deleted file mode 100644 index 007704357af..00000000000 --- a/src/librustc_data_structures/control_flow_graph/implementation/tests.rs +++ /dev/null @@ -1,139 +0,0 @@ -// 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. - -use graph::*; -use std::fmt::Debug; - -type TestGraph = Graph<&'static str, &'static str>; - -fn create_graph() -> TestGraph { - let mut graph = Graph::new(); - - // Create a simple graph - // - // F - // | - // V - // A --> B --> C - // | ^ - // v | - // D --> E - - let a = graph.add_node("A"); - let b = graph.add_node("B"); - let c = graph.add_node("C"); - let d = graph.add_node("D"); - let e = graph.add_node("E"); - let f = graph.add_node("F"); - - graph.add_edge(a, b, "AB"); - graph.add_edge(b, c, "BC"); - graph.add_edge(b, d, "BD"); - graph.add_edge(d, e, "DE"); - graph.add_edge(e, c, "EC"); - graph.add_edge(f, b, "FB"); - - return graph; -} - -#[test] -fn each_node() { - let graph = create_graph(); - let expected = ["A", "B", "C", "D", "E", "F"]; - graph.each_node(|idx, node| { - assert_eq!(&expected[idx.0], graph.node_data(idx)); - assert_eq!(expected[idx.0], node.data); - true - }); -} - -#[test] -fn each_edge() { - let graph = create_graph(); - let expected = ["AB", "BC", "BD", "DE", "EC", "FB"]; - graph.each_edge(|idx, edge| { - assert_eq!(expected[idx.0], edge.data); - true - }); -} - -fn test_adjacent_edges(graph: &Graph, - start_index: NodeIndex, - start_data: N, - expected_incoming: &[(E, N)], - expected_outgoing: &[(E, N)]) { - assert!(graph.node_data(start_index) == &start_data); - - let mut counter = 0; - for (edge_index, edge) in graph.incoming_edges(start_index) { - assert!(counter < expected_incoming.len()); - debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, - expected_incoming[counter], - edge_index, - edge); - match expected_incoming[counter] { - (ref e, ref n) => { - assert!(e == &edge.data); - assert!(n == graph.node_data(edge.source())); - assert!(start_index == edge.target); - } - } - counter += 1; - } - assert_eq!(counter, expected_incoming.len()); - - let mut counter = 0; - for (edge_index, edge) in graph.outgoing_edges(start_index) { - assert!(counter < expected_outgoing.len()); - debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, - expected_outgoing[counter], - edge_index, - edge); - match expected_outgoing[counter] { - (ref e, ref n) => { - assert!(e == &edge.data); - assert!(start_index == edge.source); - assert!(n == graph.node_data(edge.target)); - } - } - counter += 1; - } - assert_eq!(counter, expected_outgoing.len()); -} - -#[test] -fn each_adjacent_from_a() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(0), "A", &[], &[("AB", "B")]); -} - -#[test] -fn each_adjacent_from_b() { - let graph = create_graph(); - test_adjacent_edges(&graph, - NodeIndex(1), - "B", - &[("FB", "F"), ("AB", "A")], - &[("BD", "D"), ("BC", "C")]); -} - -#[test] -fn each_adjacent_from_c() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(2), "C", &[("EC", "E"), ("BC", "B")], &[]); -} - -#[test] -fn each_adjacent_from_d() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]); -} diff --git a/src/librustc_data_structures/control_flow_graph/iterate/mod.rs b/src/librustc_data_structures/control_flow_graph/iterate/mod.rs deleted file mode 100644 index 3afdc88d602..00000000000 --- a/src/librustc_data_structures/control_flow_graph/iterate/mod.rs +++ /dev/null @@ -1,63 +0,0 @@ -// 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. - -use super::super::indexed_vec::IndexVec; -use super::{DirectedGraph, WithSuccessors, WithNumNodes}; - -#[cfg(test)] -mod test; - -pub fn post_order_from( - graph: &G, - start_node: G::Node, -) -> Vec { - post_order_from_to(graph, start_node, None) -} - -pub fn post_order_from_to( - graph: &G, - start_node: G::Node, - end_node: Option, -) -> Vec { - let mut visited: IndexVec = IndexVec::from_elem_n(false, graph.num_nodes()); - let mut result: Vec = Vec::with_capacity(graph.num_nodes()); - if let Some(end_node) = end_node { - visited[end_node] = true; - } - post_order_walk(graph, start_node, &mut result, &mut visited); - result -} - -fn post_order_walk( - graph: &G, - node: G::Node, - result: &mut Vec, - visited: &mut IndexVec, -) { - if visited[node] { - return; - } - visited[node] = true; - - for successor in graph.successors(node) { - post_order_walk(graph, successor, result, visited); - } - - result.push(node); -} - -pub fn reverse_post_order( - graph: &G, - start_node: G::Node, -) -> Vec { - let mut vec = post_order_from(graph, start_node); - vec.reverse(); - vec -} diff --git a/src/librustc_data_structures/control_flow_graph/iterate/test.rs b/src/librustc_data_structures/control_flow_graph/iterate/test.rs deleted file mode 100644 index 100881ddfdd..00000000000 --- a/src/librustc_data_structures/control_flow_graph/iterate/test.rs +++ /dev/null @@ -1,21 +0,0 @@ -// 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. - -use super::super::test::TestGraph; - -use super::*; - -#[test] -fn diamond_post_order() { - let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); - - let result = post_order_from(&graph, 0); - assert_eq!(result, vec![3, 1, 2, 0]); -} diff --git a/src/librustc_data_structures/control_flow_graph/mod.rs b/src/librustc_data_structures/control_flow_graph/mod.rs deleted file mode 100644 index bd933e57b39..00000000000 --- a/src/librustc_data_structures/control_flow_graph/mod.rs +++ /dev/null @@ -1,78 +0,0 @@ -// 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. - -use super::indexed_vec::Idx; - -pub mod dominators; -pub mod implementation; -pub mod iterate; -mod reference; - -#[cfg(test)] -mod test; - -pub trait DirectedGraph { - type Node: Idx; -} - -pub trait WithNumNodes: DirectedGraph { - fn num_nodes(&self) -> usize; -} - -pub trait WithSuccessors: DirectedGraph -where - Self: for<'graph> GraphSuccessors<'graph, Item = ::Node>, -{ - fn successors<'graph>( - &'graph self, - node: Self::Node, - ) -> >::Iter; -} - -pub trait GraphSuccessors<'graph> { - type Item; - type Iter: Iterator; -} - -pub trait WithPredecessors: DirectedGraph -where - Self: for<'graph> GraphPredecessors<'graph, Item = ::Node>, -{ - fn predecessors<'graph>( - &'graph self, - node: Self::Node, - ) -> >::Iter; -} - -pub trait GraphPredecessors<'graph> { - type Item; - type Iter: Iterator; -} - -pub trait WithStartNode: DirectedGraph { - fn start_node(&self) -> Self::Node; -} - -pub trait ControlFlowGraph: - DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes -{ - // convenient trait -} - -impl ControlFlowGraph for T -where - T: DirectedGraph - + WithStartNode - + WithPredecessors - + WithStartNode - + WithSuccessors - + WithNumNodes, -{ -} diff --git a/src/librustc_data_structures/control_flow_graph/reference.rs b/src/librustc_data_structures/control_flow_graph/reference.rs deleted file mode 100644 index a7b763db8da..00000000000 --- a/src/librustc_data_structures/control_flow_graph/reference.rs +++ /dev/null @@ -1,51 +0,0 @@ -// 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. - -use super::*; - -impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G { - type Node = G::Node; -} - -impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G { - fn num_nodes(&self) -> usize { - (**self).num_nodes() - } -} - -impl<'graph, G: WithStartNode> WithStartNode for &'graph G { - fn start_node(&self) -> Self::Node { - (**self).start_node() - } -} - -impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G { - fn successors<'iter>(&'iter self, node: Self::Node) -> >::Iter { - (**self).successors(node) - } -} - -impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G { - fn predecessors<'iter>(&'iter self, - node: Self::Node) - -> >::Iter { - (**self).predecessors(node) - } -} - -impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = >::Iter; -} - -impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = >::Iter; -} diff --git a/src/librustc_data_structures/control_flow_graph/test.rs b/src/librustc_data_structures/control_flow_graph/test.rs deleted file mode 100644 index f04b536bc18..00000000000 --- a/src/librustc_data_structures/control_flow_graph/test.rs +++ /dev/null @@ -1,77 +0,0 @@ -// 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. - -use std::collections::HashMap; -use std::cmp::max; -use std::slice; -use std::iter; - -use super::{ControlFlowGraph, GraphPredecessors, GraphSuccessors}; - -pub struct TestGraph { - num_nodes: usize, - start_node: usize, - successors: HashMap>, - predecessors: HashMap>, -} - -impl TestGraph { - pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { - let mut graph = TestGraph { - num_nodes: start_node + 1, - start_node, - successors: HashMap::new(), - predecessors: HashMap::new(), - }; - for &(source, target) in edges { - graph.num_nodes = max(graph.num_nodes, source + 1); - graph.num_nodes = max(graph.num_nodes, target + 1); - graph.successors.entry(source).or_insert(vec![]).push(target); - graph.predecessors.entry(target).or_insert(vec![]).push(source); - } - for node in 0..graph.num_nodes { - graph.successors.entry(node).or_insert(vec![]); - graph.predecessors.entry(node).or_insert(vec![]); - } - graph - } -} - -impl ControlFlowGraph for TestGraph { - type Node = usize; - - fn start_node(&self) -> usize { - self.start_node - } - - fn num_nodes(&self) -> usize { - self.num_nodes - } - - fn predecessors<'graph>(&'graph self, - node: usize) - -> >::Iter { - self.predecessors[&node].iter().cloned() - } - - fn successors<'graph>(&'graph self, node: usize) -> >::Iter { - self.successors[&node].iter().cloned() - } -} - -impl<'graph> GraphPredecessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned>; -} - -impl<'graph> GraphSuccessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned>; -} diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs new file mode 100644 index 00000000000..d134fad2855 --- /dev/null +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -0,0 +1,214 @@ +// 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. + +//! Algorithm citation: +//! A Simple, Fast Dominance Algorithm. +//! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy +//! Rice Computer Science TS-06-33870 +//! + +use super::super::indexed_vec::{Idx, IndexVec}; +use super::iterate::reverse_post_order; +use super::ControlFlowGraph; + +use std::fmt; + +#[cfg(test)] +mod test; + +pub fn dominators(graph: &G) -> Dominators { + let start_node = graph.start_node(); + let rpo = reverse_post_order(graph, start_node); + dominators_given_rpo(graph, &rpo) +} + +pub fn dominators_given_rpo( + graph: &G, + rpo: &[G::Node], +) -> Dominators { + let start_node = graph.start_node(); + assert_eq!(rpo[0], start_node); + + // compute the post order index (rank) for each node + let mut post_order_rank: IndexVec = + IndexVec::from_elem_n(usize::default(), graph.num_nodes()); + for (index, node) in rpo.iter().rev().cloned().enumerate() { + post_order_rank[node] = index; + } + + let mut immediate_dominators: IndexVec> = + IndexVec::from_elem_n(Option::default(), graph.num_nodes()); + immediate_dominators[start_node] = Some(start_node); + + let mut changed = true; + while changed { + changed = false; + + for &node in &rpo[1..] { + let mut new_idom = None; + for pred in graph.predecessors(node) { + if immediate_dominators[pred].is_some() { + // (*) + // (*) dominators for `pred` have been calculated + new_idom = intersect_opt( + &post_order_rank, + &immediate_dominators, + new_idom, + Some(pred), + ); + } + } + + if new_idom != immediate_dominators[node] { + immediate_dominators[node] = new_idom; + changed = true; + } + } + } + + Dominators { + post_order_rank, + immediate_dominators, + } +} + +fn intersect_opt( + post_order_rank: &IndexVec, + immediate_dominators: &IndexVec>, + node1: Option, + node2: Option, +) -> Option { + match (node1, node2) { + (None, None) => None, + (Some(n), None) | (None, Some(n)) => Some(n), + (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)), + } +} + +fn intersect( + post_order_rank: &IndexVec, + immediate_dominators: &IndexVec>, + mut node1: Node, + mut node2: Node, +) -> Node { + while node1 != node2 { + while post_order_rank[node1] < post_order_rank[node2] { + node1 = immediate_dominators[node1].unwrap(); + } + + while post_order_rank[node2] < post_order_rank[node1] { + node2 = immediate_dominators[node2].unwrap(); + } + } + return node1; +} + +#[derive(Clone, Debug)] +pub struct Dominators { + post_order_rank: IndexVec, + immediate_dominators: IndexVec>, +} + +impl Dominators { + pub fn is_reachable(&self, node: Node) -> bool { + self.immediate_dominators[node].is_some() + } + + pub fn immediate_dominator(&self, node: Node) -> Node { + assert!(self.is_reachable(node), "node {:?} is not reachable", node); + self.immediate_dominators[node].unwrap() + } + + pub fn dominators(&self, node: Node) -> Iter { + assert!(self.is_reachable(node), "node {:?} is not reachable", node); + Iter { + dominators: self, + node: Some(node), + } + } + + pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool { + // FIXME -- could be optimized by using post-order-rank + self.dominators(node).any(|n| n == dom) + } + + #[cfg(test)] + fn all_immediate_dominators(&self) -> &IndexVec> { + &self.immediate_dominators + } +} + +pub struct Iter<'dom, Node: Idx + 'dom> { + dominators: &'dom Dominators, + node: Option, +} + +impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { + type Item = Node; + + fn next(&mut self) -> Option { + if let Some(node) = self.node { + let dom = self.dominators.immediate_dominator(node); + if dom == node { + self.node = None; // reached the root + } else { + self.node = Some(dom); + } + return Some(node); + } else { + return None; + } + } +} + +pub struct DominatorTree { + root: N, + children: IndexVec>, +} + +impl DominatorTree { + pub fn children(&self, node: Node) -> &[Node] { + &self.children[node] + } +} + +impl fmt::Debug for DominatorTree { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt( + &DominatorTreeNode { + tree: self, + node: self.root, + }, + fmt, + ) + } +} + +struct DominatorTreeNode<'tree, Node: Idx> { + tree: &'tree DominatorTree, + node: Node, +} + +impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let subtrees: Vec<_> = self.tree + .children(self.node) + .iter() + .map(|&child| DominatorTreeNode { + tree: self.tree, + node: child, + }) + .collect(); + fmt.debug_tuple("") + .field(&self.node) + .field(&subtrees) + .finish() + } +} diff --git a/src/librustc_data_structures/graph/dominators/test.rs b/src/librustc_data_structures/graph/dominators/test.rs new file mode 100644 index 00000000000..0af878cac2d --- /dev/null +++ b/src/librustc_data_structures/graph/dominators/test.rs @@ -0,0 +1,43 @@ +// 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. + +use super::super::test::TestGraph; + +use super::*; + +#[test] +fn diamond() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); + + let dominators = dominators(&graph); + let immediate_dominators = dominators.all_immediate_dominators(); + assert_eq!(immediate_dominators[0], Some(0)); + assert_eq!(immediate_dominators[1], Some(0)); + assert_eq!(immediate_dominators[2], Some(0)); + assert_eq!(immediate_dominators[3], Some(0)); +} + +#[test] +fn paper() { + // example from the paper: + let graph = TestGraph::new(6, + &[(6, 5), (6, 4), (5, 1), (4, 2), (4, 3), (1, 2), (2, 3), (3, 2), + (2, 1)]); + + let dominators = dominators(&graph); + let immediate_dominators = dominators.all_immediate_dominators(); + assert_eq!(immediate_dominators[0], None); // <-- note that 0 is not in graph + assert_eq!(immediate_dominators[1], Some(6)); + assert_eq!(immediate_dominators[2], Some(6)); + assert_eq!(immediate_dominators[3], Some(6)); + assert_eq!(immediate_dominators[4], Some(6)); + assert_eq!(immediate_dominators[5], Some(6)); + assert_eq!(immediate_dominators[6], Some(6)); +} diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs new file mode 100644 index 00000000000..e2b393071ff --- /dev/null +++ b/src/librustc_data_structures/graph/implementation/mod.rs @@ -0,0 +1,417 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A graph module for use in dataflow, region resolution, and elsewhere. +//! +//! # Interface details +//! +//! You customize the graph by specifying a "node data" type `N` and an +//! "edge data" type `E`. You can then later gain access (mutable or +//! immutable) to these "user-data" bits. Currently, you can only add +//! nodes or edges to the graph. You cannot remove or modify them once +//! added. This could be changed if we have a need. +//! +//! # Implementation details +//! +//! The main tricky thing about this code is the way that edges are +//! stored. The edges are stored in a central array, but they are also +//! threaded onto two linked lists for each node, one for incoming edges +//! and one for outgoing edges. Note that every edge is a member of some +//! incoming list and some outgoing list. Basically you can load the +//! first index of the linked list from the node data structures (the +//! field `first_edge`) and then, for each edge, load the next index from +//! the field `next_edge`). Each of those fields is an array that should +//! be indexed by the direction (see the type `Direction`). + +use bitvec::BitVector; +use std::fmt::Debug; +use std::usize; +use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; + +#[cfg(test)] +mod tests; + +pub struct Graph { + nodes: SnapshotVec>, + edges: SnapshotVec>, +} + +pub struct Node { + first_edge: [EdgeIndex; 2], // see module comment + pub data: N, +} + +#[derive(Debug)] +pub struct Edge { + next_edge: [EdgeIndex; 2], // see module comment + source: NodeIndex, + target: NodeIndex, + pub data: E, +} + +impl SnapshotVecDelegate for Node { + type Value = Node; + type Undo = (); + + fn reverse(_: &mut Vec>, _: ()) {} +} + +impl SnapshotVecDelegate for Edge { + type Value = Edge; + type Undo = (); + + fn reverse(_: &mut Vec>, _: ()) {} +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub struct NodeIndex(pub usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub struct EdgeIndex(pub usize); + +pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); + +// Use a private field here to guarantee no more instances are created: +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Direction { + repr: usize, +} + +pub const OUTGOING: Direction = Direction { repr: 0 }; + +pub const INCOMING: Direction = Direction { repr: 1 }; + +impl NodeIndex { + /// Returns unique id (unique with respect to the graph holding associated node). + pub fn node_id(&self) -> usize { + self.0 + } +} + +impl Graph { + pub fn new() -> Graph { + Graph { + nodes: SnapshotVec::new(), + edges: SnapshotVec::new(), + } + } + + pub fn with_capacity(nodes: usize, edges: usize) -> Graph { + Graph { + nodes: SnapshotVec::with_capacity(nodes), + edges: SnapshotVec::with_capacity(edges), + } + } + + // # Simple accessors + + #[inline] + pub fn all_nodes(&self) -> &[Node] { + &self.nodes + } + + #[inline] + pub fn len_nodes(&self) -> usize { + self.nodes.len() + } + + #[inline] + pub fn all_edges(&self) -> &[Edge] { + &self.edges + } + + #[inline] + pub fn len_edges(&self) -> usize { + self.edges.len() + } + + // # Node construction + + pub fn next_node_index(&self) -> NodeIndex { + NodeIndex(self.nodes.len()) + } + + pub fn add_node(&mut self, data: N) -> NodeIndex { + let idx = self.next_node_index(); + self.nodes.push(Node { + first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], + data, + }); + idx + } + + pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { + &mut self.nodes[idx.0].data + } + + pub fn node_data(&self, idx: NodeIndex) -> &N { + &self.nodes[idx.0].data + } + + pub fn node(&self, idx: NodeIndex) -> &Node { + &self.nodes[idx.0] + } + + // # Edge construction and queries + + pub fn next_edge_index(&self) -> EdgeIndex { + EdgeIndex(self.edges.len()) + } + + pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { + debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); + + let idx = self.next_edge_index(); + + // read current first of the list of edges from each node + let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; + let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; + + // create the new edge, with the previous firsts from each node + // as the next pointers + self.edges.push(Edge { + next_edge: [source_first, target_first], + source, + target, + data, + }); + + // adjust the firsts for each node target be the next object. + self.nodes[source.0].first_edge[OUTGOING.repr] = idx; + self.nodes[target.0].first_edge[INCOMING.repr] = idx; + + return idx; + } + + pub fn edge(&self, idx: EdgeIndex) -> &Edge { + &self.edges[idx.0] + } + + // # Iterating over nodes, edges + + pub fn enumerated_nodes(&self) -> impl Iterator)> { + self.nodes + .iter() + .enumerate() + .map(|(idx, n)| (NodeIndex(idx), n)) + } + + pub fn enumerated_edges(&self) -> impl Iterator)> { + self.edges + .iter() + .enumerate() + .map(|(idx, e)| (EdgeIndex(idx), e)) + } + + pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { + //! Iterates over all edges defined in the graph. + self.enumerated_nodes() + .all(|(node_idx, node)| f(node_idx, node)) + } + + pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { + //! Iterates over all edges defined in the graph + self.enumerated_edges() + .all(|(edge_idx, edge)| f(edge_idx, edge)) + } + + pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { + self.adjacent_edges(source, OUTGOING) + } + + pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges { + self.adjacent_edges(source, INCOMING) + } + + pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges { + let first_edge = self.node(source).first_edge[direction.repr]; + AdjacentEdges { + graph: self, + direction, + next: first_edge, + } + } + + pub fn successor_nodes<'a>( + &'a self, + source: NodeIndex, + ) -> impl Iterator + 'a { + self.outgoing_edges(source).targets() + } + + pub fn predecessor_nodes<'a>( + &'a self, + target: NodeIndex, + ) -> impl Iterator + 'a { + self.incoming_edges(target).sources() + } + + pub fn depth_traverse<'a>( + &'a self, + start: NodeIndex, + direction: Direction, + ) -> DepthFirstTraversal<'a, N, E> { + DepthFirstTraversal::with_start_node(self, start, direction) + } + + pub fn nodes_in_postorder<'a>( + &'a self, + direction: Direction, + entry_node: NodeIndex, + ) -> Vec { + let mut visited = BitVector::new(self.len_nodes()); + let mut stack = vec![]; + let mut result = Vec::with_capacity(self.len_nodes()); + let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { + if visited.insert(node.0) { + stack.push((node, self.adjacent_edges(node, direction))); + } + }; + + for node in Some(entry_node) + .into_iter() + .chain(self.enumerated_nodes().map(|(node, _)| node)) + { + push_node(&mut stack, node); + while let Some((node, mut iter)) = stack.pop() { + if let Some((_, child)) = iter.next() { + let target = child.source_or_target(direction); + // the current node needs more processing, so + // add it back to the stack + stack.push((node, iter)); + // and then push the new node + push_node(&mut stack, target); + } else { + result.push(node); + } + } + } + + assert_eq!(result.len(), self.len_nodes()); + result + } +} + +// # Iterators + +pub struct AdjacentEdges<'g, N, E> +where + N: 'g, + E: 'g, +{ + graph: &'g Graph, + direction: Direction, + next: EdgeIndex, +} + +impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { + fn targets(self) -> impl Iterator + 'g { + self.into_iter().map(|(_, edge)| edge.target) + } + + fn sources(self) -> impl Iterator + 'g { + self.into_iter().map(|(_, edge)| edge.source) + } +} + +impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { + type Item = (EdgeIndex, &'g Edge); + + fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { + let edge_index = self.next; + if edge_index == INVALID_EDGE_INDEX { + return None; + } + + let edge = self.graph.edge(edge_index); + self.next = edge.next_edge[self.direction.repr]; + Some((edge_index, edge)) + } + + fn size_hint(&self) -> (usize, Option) { + // At most, all the edges in the graph. + (0, Some(self.graph.len_edges())) + } +} + +pub struct DepthFirstTraversal<'g, N, E> +where + N: 'g, + E: 'g, +{ + graph: &'g Graph, + stack: Vec, + visited: BitVector, + direction: Direction, +} + +impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { + pub fn with_start_node( + graph: &'g Graph, + start_node: NodeIndex, + direction: Direction, + ) -> Self { + let mut visited = BitVector::new(graph.len_nodes()); + visited.insert(start_node.node_id()); + DepthFirstTraversal { + graph, + stack: vec![start_node], + visited, + direction, + } + } + + fn visit(&mut self, node: NodeIndex) { + if self.visited.insert(node.node_id()) { + self.stack.push(node); + } + } +} + +impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { + type Item = NodeIndex; + + fn next(&mut self) -> Option { + let next = self.stack.pop(); + if let Some(idx) = next { + for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { + let target = edge.source_or_target(self.direction); + self.visit(target); + } + } + next + } + + fn size_hint(&self) -> (usize, Option) { + // We will visit every node in the graph exactly once. + let remaining = self.graph.len_nodes() - self.visited.count(); + (remaining, Some(remaining)) + } +} + +impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} + +impl Edge { + pub fn source(&self) -> NodeIndex { + self.source + } + + pub fn target(&self) -> NodeIndex { + self.target + } + + pub fn source_or_target(&self, direction: Direction) -> NodeIndex { + if direction == OUTGOING { + self.target + } else { + self.source + } + } +} diff --git a/src/librustc_data_structures/graph/implementation/tests.rs b/src/librustc_data_structures/graph/implementation/tests.rs new file mode 100644 index 00000000000..007704357af --- /dev/null +++ b/src/librustc_data_structures/graph/implementation/tests.rs @@ -0,0 +1,139 @@ +// 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. + +use graph::*; +use std::fmt::Debug; + +type TestGraph = Graph<&'static str, &'static str>; + +fn create_graph() -> TestGraph { + let mut graph = Graph::new(); + + // Create a simple graph + // + // F + // | + // V + // A --> B --> C + // | ^ + // v | + // D --> E + + let a = graph.add_node("A"); + let b = graph.add_node("B"); + let c = graph.add_node("C"); + let d = graph.add_node("D"); + let e = graph.add_node("E"); + let f = graph.add_node("F"); + + graph.add_edge(a, b, "AB"); + graph.add_edge(b, c, "BC"); + graph.add_edge(b, d, "BD"); + graph.add_edge(d, e, "DE"); + graph.add_edge(e, c, "EC"); + graph.add_edge(f, b, "FB"); + + return graph; +} + +#[test] +fn each_node() { + let graph = create_graph(); + let expected = ["A", "B", "C", "D", "E", "F"]; + graph.each_node(|idx, node| { + assert_eq!(&expected[idx.0], graph.node_data(idx)); + assert_eq!(expected[idx.0], node.data); + true + }); +} + +#[test] +fn each_edge() { + let graph = create_graph(); + let expected = ["AB", "BC", "BD", "DE", "EC", "FB"]; + graph.each_edge(|idx, edge| { + assert_eq!(expected[idx.0], edge.data); + true + }); +} + +fn test_adjacent_edges(graph: &Graph, + start_index: NodeIndex, + start_data: N, + expected_incoming: &[(E, N)], + expected_outgoing: &[(E, N)]) { + assert!(graph.node_data(start_index) == &start_data); + + let mut counter = 0; + for (edge_index, edge) in graph.incoming_edges(start_index) { + assert!(counter < expected_incoming.len()); + debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", + counter, + expected_incoming[counter], + edge_index, + edge); + match expected_incoming[counter] { + (ref e, ref n) => { + assert!(e == &edge.data); + assert!(n == graph.node_data(edge.source())); + assert!(start_index == edge.target); + } + } + counter += 1; + } + assert_eq!(counter, expected_incoming.len()); + + let mut counter = 0; + for (edge_index, edge) in graph.outgoing_edges(start_index) { + assert!(counter < expected_outgoing.len()); + debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", + counter, + expected_outgoing[counter], + edge_index, + edge); + match expected_outgoing[counter] { + (ref e, ref n) => { + assert!(e == &edge.data); + assert!(start_index == edge.source); + assert!(n == graph.node_data(edge.target)); + } + } + counter += 1; + } + assert_eq!(counter, expected_outgoing.len()); +} + +#[test] +fn each_adjacent_from_a() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(0), "A", &[], &[("AB", "B")]); +} + +#[test] +fn each_adjacent_from_b() { + let graph = create_graph(); + test_adjacent_edges(&graph, + NodeIndex(1), + "B", + &[("FB", "F"), ("AB", "A")], + &[("BD", "D"), ("BC", "C")]); +} + +#[test] +fn each_adjacent_from_c() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(2), "C", &[("EC", "E"), ("BC", "B")], &[]); +} + +#[test] +fn each_adjacent_from_d() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]); +} diff --git a/src/librustc_data_structures/graph/iterate/mod.rs b/src/librustc_data_structures/graph/iterate/mod.rs new file mode 100644 index 00000000000..3afdc88d602 --- /dev/null +++ b/src/librustc_data_structures/graph/iterate/mod.rs @@ -0,0 +1,63 @@ +// 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. + +use super::super::indexed_vec::IndexVec; +use super::{DirectedGraph, WithSuccessors, WithNumNodes}; + +#[cfg(test)] +mod test; + +pub fn post_order_from( + graph: &G, + start_node: G::Node, +) -> Vec { + post_order_from_to(graph, start_node, None) +} + +pub fn post_order_from_to( + graph: &G, + start_node: G::Node, + end_node: Option, +) -> Vec { + let mut visited: IndexVec = IndexVec::from_elem_n(false, graph.num_nodes()); + let mut result: Vec = Vec::with_capacity(graph.num_nodes()); + if let Some(end_node) = end_node { + visited[end_node] = true; + } + post_order_walk(graph, start_node, &mut result, &mut visited); + result +} + +fn post_order_walk( + graph: &G, + node: G::Node, + result: &mut Vec, + visited: &mut IndexVec, +) { + if visited[node] { + return; + } + visited[node] = true; + + for successor in graph.successors(node) { + post_order_walk(graph, successor, result, visited); + } + + result.push(node); +} + +pub fn reverse_post_order( + graph: &G, + start_node: G::Node, +) -> Vec { + let mut vec = post_order_from(graph, start_node); + vec.reverse(); + vec +} diff --git a/src/librustc_data_structures/graph/iterate/test.rs b/src/librustc_data_structures/graph/iterate/test.rs new file mode 100644 index 00000000000..100881ddfdd --- /dev/null +++ b/src/librustc_data_structures/graph/iterate/test.rs @@ -0,0 +1,21 @@ +// 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. + +use super::super::test::TestGraph; + +use super::*; + +#[test] +fn diamond_post_order() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); + + let result = post_order_from(&graph, 0); + assert_eq!(result, vec![3, 1, 2, 0]); +} diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs new file mode 100644 index 00000000000..bd933e57b39 --- /dev/null +++ b/src/librustc_data_structures/graph/mod.rs @@ -0,0 +1,78 @@ +// 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. + +use super::indexed_vec::Idx; + +pub mod dominators; +pub mod implementation; +pub mod iterate; +mod reference; + +#[cfg(test)] +mod test; + +pub trait DirectedGraph { + type Node: Idx; +} + +pub trait WithNumNodes: DirectedGraph { + fn num_nodes(&self) -> usize; +} + +pub trait WithSuccessors: DirectedGraph +where + Self: for<'graph> GraphSuccessors<'graph, Item = ::Node>, +{ + fn successors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter; +} + +pub trait GraphSuccessors<'graph> { + type Item; + type Iter: Iterator; +} + +pub trait WithPredecessors: DirectedGraph +where + Self: for<'graph> GraphPredecessors<'graph, Item = ::Node>, +{ + fn predecessors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter; +} + +pub trait GraphPredecessors<'graph> { + type Item; + type Iter: Iterator; +} + +pub trait WithStartNode: DirectedGraph { + fn start_node(&self) -> Self::Node; +} + +pub trait ControlFlowGraph: + DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes +{ + // convenient trait +} + +impl ControlFlowGraph for T +where + T: DirectedGraph + + WithStartNode + + WithPredecessors + + WithStartNode + + WithSuccessors + + WithNumNodes, +{ +} diff --git a/src/librustc_data_structures/graph/reference.rs b/src/librustc_data_structures/graph/reference.rs new file mode 100644 index 00000000000..a7b763db8da --- /dev/null +++ b/src/librustc_data_structures/graph/reference.rs @@ -0,0 +1,51 @@ +// 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. + +use super::*; + +impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G { + type Node = G::Node; +} + +impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G { + fn num_nodes(&self) -> usize { + (**self).num_nodes() + } +} + +impl<'graph, G: WithStartNode> WithStartNode for &'graph G { + fn start_node(&self) -> Self::Node { + (**self).start_node() + } +} + +impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G { + fn successors<'iter>(&'iter self, node: Self::Node) -> >::Iter { + (**self).successors(node) + } +} + +impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G { + fn predecessors<'iter>(&'iter self, + node: Self::Node) + -> >::Iter { + (**self).predecessors(node) + } +} + +impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G { + type Item = G::Node; + type Iter = >::Iter; +} + +impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G { + type Item = G::Node; + type Iter = >::Iter; +} diff --git a/src/librustc_data_structures/graph/test.rs b/src/librustc_data_structures/graph/test.rs new file mode 100644 index 00000000000..f04b536bc18 --- /dev/null +++ b/src/librustc_data_structures/graph/test.rs @@ -0,0 +1,77 @@ +// 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. + +use std::collections::HashMap; +use std::cmp::max; +use std::slice; +use std::iter; + +use super::{ControlFlowGraph, GraphPredecessors, GraphSuccessors}; + +pub struct TestGraph { + num_nodes: usize, + start_node: usize, + successors: HashMap>, + predecessors: HashMap>, +} + +impl TestGraph { + pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { + let mut graph = TestGraph { + num_nodes: start_node + 1, + start_node, + successors: HashMap::new(), + predecessors: HashMap::new(), + }; + for &(source, target) in edges { + graph.num_nodes = max(graph.num_nodes, source + 1); + graph.num_nodes = max(graph.num_nodes, target + 1); + graph.successors.entry(source).or_insert(vec![]).push(target); + graph.predecessors.entry(target).or_insert(vec![]).push(source); + } + for node in 0..graph.num_nodes { + graph.successors.entry(node).or_insert(vec![]); + graph.predecessors.entry(node).or_insert(vec![]); + } + graph + } +} + +impl ControlFlowGraph for TestGraph { + type Node = usize; + + fn start_node(&self) -> usize { + self.start_node + } + + fn num_nodes(&self) -> usize { + self.num_nodes + } + + fn predecessors<'graph>(&'graph self, + node: usize) + -> >::Iter { + self.predecessors[&node].iter().cloned() + } + + fn successors<'graph>(&'graph self, node: usize) -> >::Iter { + self.successors[&node].iter().cloned() + } +} + +impl<'graph> GraphPredecessors<'graph> for TestGraph { + type Item = usize; + type Iter = iter::Cloned>; +} + +impl<'graph> GraphSuccessors<'graph> for TestGraph { + type Item = usize; + type Iter = iter::Cloned>; +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 59b7b430083..c4e04c75831 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -70,7 +70,7 @@ pub mod transitive_relation; pub use ena::unify; pub mod fx; pub mod tuple_slice; -pub mod control_flow_graph; +pub mod graph; pub mod flock; pub mod sync; pub mod owning_ref; diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 39cb952a385..a78a2008eec 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -49,7 +49,7 @@ use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::control_flow_graph::implementation::{ +use rustc_data_structures::graph::implementation::{ Direction, INCOMING, OUTGOING, NodeIndex }; use rustc::hir; diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index a5db0d15d8a..377b6475891 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -23,7 +23,7 @@ use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; use rustc::ty::{self, ParamEnv, TyCtxt}; -use rustc_data_structures::control_flow_graph::dominators::Dominators; +use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 46026cdc941..301999cc4a5 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -29,7 +29,7 @@ use rustc::mir::{Terminator, TerminatorKind}; use rustc::mir::{Field, Operand, BorrowKind}; use rustc::ty::{self, ParamEnv}; use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::control_flow_graph::dominators::Dominators; +use rustc_data_structures::graph::dominators::Dominators; pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>( infcx: &InferCtxt<'cx, 'gcx, 'tcx>, diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index ca2a120ceb7..499170acee3 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -16,7 +16,7 @@ use dataflow::indexes::BorrowIndex; use rustc::mir::{BasicBlock, Location, Mir, Place}; use rustc::mir::{ProjectionElem, BorrowKind}; use rustc::ty::TyCtxt; -use rustc_data_structures::control_flow_graph::dominators::Dominators; +use rustc_data_structures::graph::dominators::Dominators; /// Returns true if the borrow represented by `kind` is /// allowed to be split into separate Reservation and -- cgit 1.4.1-3-g733a5 From dab206f8b57bba507436e23e0e80a6d1ed80bfc4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Jul 2018 10:55:44 -0400 Subject: strengthen `Idx` to require `Ord + Hash` You should always be able to know that any `T` where `T: Idx` can be used in a `BTreeMap` and a `FxHashMap`. --- src/librustc_data_structures/indexed_vec.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index ad3710e9536..26de2191090 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -14,6 +14,7 @@ use std::slice; use std::marker::PhantomData; use std::ops::{Index, IndexMut, Range, RangeBounds}; use std::fmt; +use std::hash::Hash; use std::vec; use std::u32; @@ -22,7 +23,7 @@ use rustc_serialize as serialize; /// Represents some newtyped `usize` wrapper. /// /// (purpose: avoid mixing indexes for different bitvector domains.) -pub trait Idx: Copy + 'static + Eq + Debug { +pub trait Idx: Copy + 'static + Ord + Debug + Hash { fn new(idx: usize) -> Self; fn index(self) -> usize; } -- cgit 1.4.1-3-g733a5 From 0052ddd8aec0701aa8444ad780fa4ebb123301ff Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Jul 2018 10:40:03 -0400 Subject: introduce a generic SCC computation --- .../graph/implementation/tests.rs | 2 +- src/librustc_data_structures/graph/mod.rs | 1 + src/librustc_data_structures/graph/scc/mod.rs | 341 +++++++++++++++++++++ src/librustc_data_structures/graph/scc/test.rs | 178 +++++++++++ src/librustc_data_structures/graph/test.rs | 12 +- 5 files changed, 531 insertions(+), 3 deletions(-) create mode 100644 src/librustc_data_structures/graph/scc/mod.rs create mode 100644 src/librustc_data_structures/graph/scc/test.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/implementation/tests.rs b/src/librustc_data_structures/graph/implementation/tests.rs index 007704357af..3814827b5df 100644 --- a/src/librustc_data_structures/graph/implementation/tests.rs +++ b/src/librustc_data_structures/graph/implementation/tests.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use graph::*; +use graph::implementation::*; use std::fmt::Debug; type TestGraph = Graph<&'static str, &'static str>; diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index bd933e57b39..7265e4e8c7c 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -14,6 +14,7 @@ pub mod dominators; pub mod implementation; pub mod iterate; mod reference; +pub mod scc; #[cfg(test)] mod test; diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs new file mode 100644 index 00000000000..b0f098b3d20 --- /dev/null +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -0,0 +1,341 @@ +// Copyright 2017 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. + +//! Routine to compute the strongly connected components (SCCs) of a +//! graph, as well as the resulting DAG if each SCC is replaced with a +//! node in the graph. This uses Tarjan's algorithm that completes in +//! O(n) time. + +use fx::FxHashSet; +use graph::{DirectedGraph, WithNumNodes, WithSuccessors}; +use indexed_vec::{Idx, IndexVec}; +use std::ops::Range; + +mod test; + +/// Strongly connected components (SCC) of a graph. The type `N` is +/// the index type for the graph nodes and `S` is the index type for +/// the SCCs. We can map from each node to the SCC that it +/// participates in, and we also have the successors of each SCC. +pub struct Sccs { + /// For each node, what is the SCC index of the SCC to which it + /// belongs. + scc_indices: IndexVec, + + /// Data about each SCC. + scc_data: SccData, +} + +struct SccData { + /// For each SCC, the range of `all_successors` where its + /// successors can be found. + ranges: IndexVec>, + + /// Contains the succcessors for all the Sccs, concatenated. The + /// range of indices corresponding to a given SCC is found in its + /// SccData. + all_successors: Vec, +} + +impl Sccs { + pub fn new(graph: &(impl DirectedGraph + WithNumNodes + WithSuccessors)) -> Self { + SccsConstruction::construct(graph) + } + + /// Returns the number of SCCs in the graph. + pub fn num_sccs(&self) -> usize { + self.scc_data.len() + } + + /// Returns the SCC to which a node `r` belongs. + pub fn scc(&self, r: N) -> S { + self.scc_indices[r] + } + + /// Returns the successor of the given SCC. + pub fn successors(&self, scc: S) -> &[S] { + self.scc_data.successors(scc) + } +} + +impl SccData { + /// Number of SCCs, + fn len(&self) -> usize { + self.ranges.len() + } + + /// Returns the successor of the given SCC. + fn successors(&self, scc: S) -> &[S] { + // Annoyingly, `range` does not implement `Copy`, so we have + // to do `range.start..range.end`: + let range = &self.ranges[scc]; + &self.all_successors[range.start..range.end] + } + + /// Creates a new SCC with `successors` as its successors and + /// returns the resulting index. + fn create_scc(&mut self, successors: impl IntoIterator) -> S { + // Store the successors on `scc_successors_vec`, remembering + // the range of indices. + let all_successors_start = self.all_successors.len(); + self.all_successors.extend(successors); + let all_successors_end = self.all_successors.len(); + + debug!( + "create_scc({:?}) successors={:?}", + self.ranges.len(), + &self.all_successors[all_successors_start..all_successors_end], + ); + + self.ranges.push(all_successors_start..all_successors_end) + } +} + +struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors + 'c, S: Idx> { + graph: &'c G, + + /// The state of each node; used during walk to record the stack + /// and after walk to record what cycle each node ended up being + /// in. + node_states: IndexVec>, + + /// The stack of nodes that we are visiting as part of the DFS. + node_stack: Vec, + + /// The stack of successors: as we visit a node, we mark our + /// position in this stack, and when we encounter a successor SCC, + /// we push it on the stack. When we complete an SCC, we can pop + /// everything off the stack that was found along the way. + successors_stack: Vec, + + /// A set used to strip duplicates. As we accumulate successors + /// into the successors_stack, we sometimes get duplicate entries. + /// We use this set to remove those -- we keep it around between + /// successors to amortize memory allocation costs. + duplicate_set: FxHashSet, + + scc_data: SccData, +} + +#[derive(Copy, Clone, Debug)] +enum NodeState { + /// This node has not yet been visited as part of the DFS. + /// + /// After SCC construction is complete, this state ought to be + /// impossible. + NotVisited, + + /// This node is currently being walk as part of our DFS. It is on + /// the stack at the depth `depth`. + /// + /// After SCC construction is complete, this state ought to be + /// impossible. + BeingVisited { depth: usize }, + + /// Indicates that this node is a member of the given cycle. + InCycle { scc_index: S }, + + /// Indicates that this node is a member of whatever cycle + /// `parent` is a member of. This state is transient: whenever we + /// see it, we try to overwrite it with the current state of + /// `parent` (this is the "path compression" step of a union-find + /// algorithm). + InCycleWith { parent: N }, +} + +#[derive(Copy, Clone, Debug)] +enum WalkReturn { + Cycle { min_depth: usize }, + Complete { scc_index: S }, +} + +impl<'c, G, S> SccsConstruction<'c, G, S> +where + G: DirectedGraph + WithNumNodes + WithSuccessors, + S: Idx, +{ + /// Identifies SCCs in the graph `G` and computes the resulting + /// DAG. This uses a variant of [Tarjan's + /// algorithm][wikipedia]. The high-level summary of the algorithm + /// is that we do a depth-first search. Along the way, we keep a + /// stack of each node whose successors are being visited. We + /// track the depth of each node on this stack (there is no depth + /// if the node is not on the stack). When we find that some node + /// N with depth D can reach some other node N' with lower depth + /// D' (i.e., D' < D), we know that N, N', and all nodes in + /// between them on the stack are part of an SCC. + /// + /// For each node, we track the lowest depth of any successor we + /// have found, along with that + /// + /// [wikipedia]: https://bit.ly/2EZIx84 + fn construct(graph: &'c G) -> Sccs { + let num_nodes = graph.num_nodes(); + + let mut this = Self { + graph, + node_states: IndexVec::from_elem_n(NodeState::NotVisited, num_nodes), + node_stack: Vec::with_capacity(num_nodes), + successors_stack: Vec::new(), + scc_data: SccData { + ranges: IndexVec::new(), + all_successors: Vec::new(), + }, + duplicate_set: FxHashSet::default(), + }; + + let scc_indices = (0..num_nodes) + .map(G::Node::new) + .map(|node| match this.walk_node(0, node) { + WalkReturn::Complete { scc_index } => scc_index, + WalkReturn::Cycle { min_depth } => panic!( + "`walk_node(0, {:?})` returned cycle with depth {:?}", + node, min_depth + ), + }) + .collect(); + + Sccs { + scc_indices, + scc_data: this.scc_data, + } + } + + fn walk_node(&mut self, depth: usize, node: G::Node) -> WalkReturn { + debug!("walk_node(depth = {:?}, node = {:?})", depth, node); + match self.find_state(node) { + NodeState::InCycle { scc_index } => WalkReturn::Complete { scc_index }, + + NodeState::BeingVisited { depth: min_depth } => WalkReturn::Cycle { min_depth }, + + NodeState::NotVisited => self.walk_unvisited_node(depth, node), + + NodeState::InCycleWith { parent } => panic!( + "`find_state` returned `InCycleWith({:?})`, which ought to be impossible", + parent + ), + } + } + + /// Fetches the state of the node `r`. If `r` is recorded as being + /// in a cycle with some other node `r2`, then fetches the state + /// of `r2` (and updates `r` to reflect current result). This is + /// basically the "find" part of a standard union-find algorithm + /// (with path compression). + fn find_state(&mut self, r: G::Node) -> NodeState { + debug!("find_state(r = {:?} in state {:?})", r, self.node_states[r]); + match self.node_states[r] { + NodeState::InCycle { scc_index } => NodeState::InCycle { scc_index }, + NodeState::BeingVisited { depth } => NodeState::BeingVisited { depth }, + NodeState::NotVisited => NodeState::NotVisited, + NodeState::InCycleWith { parent } => { + let parent_state = self.find_state(parent); + debug!("find_state: parent_state = {:?}", parent_state); + match parent_state { + NodeState::InCycle { .. } => { + self.node_states[r] = parent_state; + parent_state + } + + NodeState::BeingVisited { depth } => { + self.node_states[r] = NodeState::InCycleWith { + parent: self.node_stack[depth], + }; + parent_state + } + + NodeState::NotVisited | NodeState::InCycleWith { .. } => { + panic!("invalid parent state: {:?}", parent_state) + } + } + } + } + } + + /// Walks a node that has never been visited before. + fn walk_unvisited_node(&mut self, depth: usize, node: G::Node) -> WalkReturn { + debug!( + "walk_unvisited_node(depth = {:?}, node = {:?})", + depth, node + ); + + debug_assert!(match self.node_states[node] { + NodeState::NotVisited => true, + _ => false, + }); + + self.node_states[node] = NodeState::BeingVisited { depth }; + self.node_stack.push(node); + + // Walk each successor of the node, looking to see if any of + // them can reach a node that is presently on the stack. If + // so, that means they can also reach us. + let mut min_depth = depth; + let mut min_cycle_root = node; + let successors_len = self.successors_stack.len(); + for successor_node in self.graph.successors(node) { + debug!( + "walk_unvisited_node: node = {:?} successor_ode = {:?}", + node, successor_node + ); + match self.walk_node(depth + 1, successor_node) { + WalkReturn::Cycle { + min_depth: successor_min_depth, + } => { + assert!(successor_min_depth <= depth); + if successor_min_depth < min_depth { + debug!( + "walk_unvisited_node: node = {:?} successor_min_depth = {:?}", + node, successor_min_depth + ); + min_depth = successor_min_depth; + min_cycle_root = successor_node; + } + } + + WalkReturn::Complete { + scc_index: successor_scc_index, + } => { + debug!( + "walk_unvisited_node: node = {:?} successor_scc_index = {:?}", + node, successor_scc_index + ); + self.successors_stack.push(successor_scc_index); + } + } + } + + let r = self.node_stack.pop(); + debug_assert_eq!(r, Some(node)); + + if min_depth == depth { + // Note that successor stack may have duplicates, so we + // want to remove those: + let deduplicated_successors = { + let duplicate_set = &mut self.duplicate_set; + duplicate_set.clear(); + self.successors_stack + .drain(successors_len..) + .filter(move |&i| duplicate_set.insert(i)) + }; + let scc_index = self.scc_data.create_scc(deduplicated_successors); + self.node_states[node] = NodeState::InCycle { scc_index }; + WalkReturn::Complete { scc_index } + } else { + // We are not the head of the cycle. Return back to our + // caller. They will take ownership of the + // `self.successors` data that we pushed. + self.node_states[node] = NodeState::InCycleWith { + parent: min_cycle_root, + }; + WalkReturn::Cycle { min_depth } + } + } +} diff --git a/src/librustc_data_structures/graph/scc/test.rs b/src/librustc_data_structures/graph/scc/test.rs new file mode 100644 index 00000000000..a273d64a40c --- /dev/null +++ b/src/librustc_data_structures/graph/scc/test.rs @@ -0,0 +1,178 @@ +// 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. + +#![cfg(test)] + +use graph::test::TestGraph; +use super::*; + +#[test] +fn diamond() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 4); + assert_eq!(sccs.num_sccs(), 4); +} + +#[test] +fn test_big_scc() { + // The order in which things will be visited is important to this + // test. + // + // We will visit: + // + // 0 -> 1 -> 2 -> 0 + // + // and at this point detect a cycle. 2 will return back to 1 which + // will visit 3. 3 will visit 2 before the cycle is complete, and + // hence it too will return a cycle. + + /* ++-> 0 +| | +| v +| 1 -> 3 +| | | +| v | ++-- 2 <--+ + */ + let graph = TestGraph::new(0, &[ + (0, 1), + (1, 2), + (1, 3), + (2, 0), + (3, 2), + ]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 1); +} + +#[test] +fn test_three_sccs() { + /* + 0 + | + v ++-> 1 3 +| | | +| v | ++-- 2 <--+ + */ + let graph = TestGraph::new(0, &[ + (0, 1), + (1, 2), + (2, 1), + (3, 2), + ]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 3); + assert_eq!(sccs.scc(0), 1); + assert_eq!(sccs.scc(1), 0); + assert_eq!(sccs.scc(2), 0); + assert_eq!(sccs.scc(3), 2); + assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(1), &[0]); + assert_eq!(sccs.successors(2), &[0]); +} + +#[test] +fn test_find_state_2() { + // The order in which things will be visited is important to this + // test. It tests part of the `find_state` behavior. + // + // We will start in our DFS by visiting: + // + // 0 -> 1 -> 2 -> 1 + // + // and at this point detect a cycle. The state of 2 will thus be + // `InCycleWith { 1 }`. We will then visit the 1 -> 3 edge, which + // will attempt to visit 0 as well, thus going to the state + // `InCycleWith { 0 }`. Finally, node 1 will complete; the lowest + // depth of any successor was 3 which had depth 0, and thus it + // will be in the state `InCycleWith { 3 }`. + // + // When we finally traverse the `0 -> 4` edge and then visit node 2, + // the states of the nodes are: + // + // 0 BeingVisited { 0 } + // 1 InCycleWith { 3 } + // 2 InCycleWith { 1 } + // 3 InCycleWith { 0 } + // + // and hence 4 will traverse the links, finding an ultimate depth of 0. + // If will also collapse the states to the following: + // + // 0 BeingVisited { 0 } + // 1 InCycleWith { 3 } + // 2 InCycleWith { 1 } + // 3 InCycleWith { 0 } + + /* + /----+ + 0 <--+ | + | | | + v | | ++-> 1 -> 3 4 +| | | +| v | ++-- 2 <----+ + */ + let graph = TestGraph::new(0, &[ + (0, 1), + (0, 4), + (1, 2), + (1, 3), + (2, 1), + (3, 0), + (4, 2), + ]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 1); + assert_eq!(sccs.scc(0), 0); + assert_eq!(sccs.scc(1), 0); + assert_eq!(sccs.scc(2), 0); + assert_eq!(sccs.scc(3), 0); + assert_eq!(sccs.scc(4), 0); + assert_eq!(sccs.successors(0), &[]); +} + +#[test] +fn test_find_state_3() { + /* + /----+ + 0 <--+ | + | | | + v | | ++-> 1 -> 3 4 5 +| | | | +| v | | ++-- 2 <----+-+ + */ + let graph = TestGraph::new(0, &[ + (0, 1), + (0, 4), + (1, 2), + (1, 3), + (2, 1), + (3, 0), + (4, 2), + (5, 2), + ]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 2); + assert_eq!(sccs.scc(0), 0); + assert_eq!(sccs.scc(1), 0); + assert_eq!(sccs.scc(2), 0); + assert_eq!(sccs.scc(3), 0); + assert_eq!(sccs.scc(4), 0); + assert_eq!(sccs.scc(5), 1); + assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(1), &[0]); +} diff --git a/src/librustc_data_structures/graph/test.rs b/src/librustc_data_structures/graph/test.rs index f04b536bc18..48b654726b8 100644 --- a/src/librustc_data_structures/graph/test.rs +++ b/src/librustc_data_structures/graph/test.rs @@ -13,7 +13,7 @@ use std::cmp::max; use std::slice; use std::iter; -use super::{ControlFlowGraph, GraphPredecessors, GraphSuccessors}; +use super::*; pub struct TestGraph { num_nodes: usize, @@ -44,23 +44,31 @@ impl TestGraph { } } -impl ControlFlowGraph for TestGraph { +impl DirectedGraph for TestGraph { type Node = usize; +} +impl WithStartNode for TestGraph { fn start_node(&self) -> usize { self.start_node } +} +impl WithNumNodes for TestGraph { fn num_nodes(&self) -> usize { self.num_nodes } +} +impl WithPredecessors for TestGraph { fn predecessors<'graph>(&'graph self, node: usize) -> >::Iter { self.predecessors[&node].iter().cloned() } +} +impl WithSuccessors for TestGraph { fn successors<'graph>(&'graph self, node: usize) -> >::Iter { self.successors[&node].iter().cloned() } -- cgit 1.4.1-3-g733a5 From f0c67951d076db8272f7a52f4d2596ae77b3311d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 13 Jul 2018 10:53:57 +1000 Subject: Make BitSlice's `Word` properly generic. Currently `Word` is `usize`, and there are various places in the code that assume this. This patch mostly just changes `usize` occurrences to `Word`. Most of the changes were found as compile errors when I changed `Word` to a type other than `usize`, but there was one non-obvious case in librustc_mir/dataflow/mod.rs that caused bounds check failures before I fixed it. --- src/librustc_data_structures/bitslice.rs | 14 +++++++------- src/librustc_mir/dataflow/impls/borrowed_locals.rs | 2 +- src/librustc_mir/dataflow/impls/borrows.rs | 4 ++-- src/librustc_mir/dataflow/impls/mod.rs | 12 ++++++------ src/librustc_mir/dataflow/impls/storage_liveness.rs | 2 +- src/librustc_mir/dataflow/mod.rs | 10 +++++----- 6 files changed, 22 insertions(+), 22 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitslice.rs b/src/librustc_data_structures/bitslice.rs index 2678861be06..5b5dd907cb7 100644 --- a/src/librustc_data_structures/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -79,7 +79,7 @@ fn bit_lookup(bit: usize) -> BitLookup { } -fn bit_str(bit: Word) -> String { +fn bit_str(bit: usize) -> String { let byte = bit >> 3; let lobits = 1 << (bit & 0b111); format!("[{}:{}-{:02x}]", bit, byte, lobits) @@ -116,8 +116,8 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String { } #[inline] -pub fn bitwise(out_vec: &mut [usize], - in_vec: &[usize], +pub fn bitwise(out_vec: &mut [Word], + in_vec: &[Word], op: &Op) -> bool { assert_eq!(out_vec.len(), in_vec.len()); let mut changed = false; @@ -132,21 +132,21 @@ pub fn bitwise(out_vec: &mut [usize], pub trait BitwiseOperator { /// Applies some bit-operation pointwise to each of the bits in the two inputs. - fn join(&self, pred1: usize, pred2: usize) -> usize; + fn join(&self, pred1: Word, pred2: Word) -> Word; } pub struct Intersect; impl BitwiseOperator for Intersect { #[inline] - fn join(&self, a: usize, b: usize) -> usize { a & b } + fn join(&self, a: Word, b: Word) -> Word { a & b } } pub struct Union; impl BitwiseOperator for Union { #[inline] - fn join(&self, a: usize, b: usize) -> usize { a | b } + fn join(&self, a: Word, b: Word) -> Word { a | b } } pub struct Subtract; impl BitwiseOperator for Subtract { #[inline] - fn join(&self, a: usize, b: usize) -> usize { a & !b } + fn join(&self, a: Word, b: Word) -> Word { a & !b } } diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index 244e8b5ccd7..c7513ac8816 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> { impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> { #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { + fn join(&self, pred1: Word, pred2: Word) -> Word { pred1 | pred2 // "maybe" means we union effects of both preds } } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index a109389aa31..dbdf5b4e096 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -20,7 +20,7 @@ use rustc::ty::TyCtxt; use rustc::ty::{RegionKind, RegionVid}; use rustc::ty::RegionKind::ReScope; -use rustc_data_structures::bitslice::BitwiseOperator; +use rustc_data_structures::bitslice::{BitwiseOperator, Word}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_set::IdxSet; use rustc_data_structures::indexed_vec::IndexVec; @@ -370,7 +370,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> { #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { + fn join(&self, pred1: Word, pred2: Word) -> Word { pred1 | pred2 // union effects of preds when computing reservations } } diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index f64fd64b283..ee3bba840c6 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -14,7 +14,7 @@ use rustc::ty::TyCtxt; use rustc::mir::{self, Mir, Location}; -use rustc_data_structures::bitslice::{BitwiseOperator}; +use rustc_data_structures::bitslice::{BitwiseOperator, Word}; use rustc_data_structures::indexed_set::{IdxSet}; use rustc_data_structures::indexed_vec::Idx; @@ -663,35 +663,35 @@ impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeInitializedPlaces<'a, 'gcx, 'tcx> { #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { + fn join(&self, pred1: Word, pred2: Word) -> Word { pred1 | pred2 // "maybe" means we union effects of both preds } } impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> { #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { + fn join(&self, pred1: Word, pred2: Word) -> Word { pred1 | pred2 // "maybe" means we union effects of both preds } } impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> { #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { + fn join(&self, pred1: Word, pred2: Word) -> Word { pred1 & pred2 // "definitely" means we intersect effects of both preds } } impl<'a, 'gcx, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'gcx, 'tcx> { #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { + fn join(&self, pred1: Word, pred2: Word) -> Word { pred1 | pred2 // moves from both preds are in scope } } impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> { #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { + fn join(&self, pred1: Word, pred2: Word) -> Word { pred1 | pred2 // inits from both preds are in scope } } diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index dea61542ac4..29548051a4d 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> { impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> { #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { + fn join(&self, pred1: Word, pred2: Word) -> Word { pred1 | pred2 // "maybe" means we union effects of both preds } } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index e59236c5168..f58609aa9a5 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -12,7 +12,7 @@ use syntax::ast::{self, MetaItem}; use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::bitslice::{bitwise, BitwiseOperator}; +use rustc_data_structures::bitslice::{bitwise, BitwiseOperator, Word}; use rustc_data_structures::work_queue::WorkQueue; use rustc::ty::{self, TyCtxt}; @@ -467,7 +467,7 @@ pub struct AllSets { bits_per_block: usize, /// Number of words associated with each block entry - /// equal to bits_per_block / usize::BITS, rounded up. + /// equal to bits_per_block / (mem::size_of:: * 8), rounded up. words_per_block: usize, /// For each block, bits generated by executing the statements in @@ -734,9 +734,9 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation dead_unwinds: &'a IdxSet, denotation: D) -> Self where D: InitialFlow { let bits_per_block = denotation.bits_per_block(); - let usize_bits = mem::size_of::() * 8; - let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits; - let bits_per_block_rounded_up = words_per_block * usize_bits; // a multiple of word size + let bits_per_word = mem::size_of::() * 8; + let words_per_block = (bits_per_block + bits_per_word - 1) / bits_per_word; + let bits_per_block_rounded_up = words_per_block * bits_per_word; // a multiple of word size let num_blocks = mir.basic_blocks().len(); let num_overall = num_blocks * bits_per_block_rounded_up; -- cgit 1.4.1-3-g733a5 From f2b0b6700ce984a38abd06e48e7884573688539b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 13 Jul 2018 13:05:22 +1000 Subject: Fix bitslice printing. In multiple ways: - Two calls to `bits_to_string()` passed in byte lengths rather than bit lengths, which meant only 1/8th of the `BitSlice` was printed. - `bit_str`'s purpose is entirely mysterious. I removed it and changed its callers to print the indices in the obvious way. - `bits_to_string`'s inner loop was totally wrong, such that it printed entirely bogus results. - `bits_to_string` now also adds a '|' between words, which makes the output easier to read, e.g.: `[ff-ff-ff-ff-ff-ff-ff-ff|ff-ff-ff-ff-ff-ff-ff-07]`. --- src/librustc_data_structures/bitslice.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitslice.rs b/src/librustc_data_structures/bitslice.rs index 5b5dd907cb7..79435aa3987 100644 --- a/src/librustc_data_structures/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -28,9 +28,9 @@ impl BitSlice for [Word] { fn clear_bit(&mut self, idx: usize) -> bool { let words = self; debug!("clear_bit: words={} idx={}", - bits_to_string(words, words.len() * mem::size_of::()), bit_str(idx)); + bits_to_string(words, words.len() * mem::size_of::() * 8), idx); let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx); - debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask); + debug!("word={} bit_in_word={} bit_mask=0x{:x}", word, bit_in_word, bit_mask); let oldv = words[word]; let newv = oldv & !bit_mask; words[word] = newv; @@ -42,7 +42,7 @@ impl BitSlice for [Word] { fn set_bit(&mut self, idx: usize) -> bool { let words = self; debug!("set_bit: words={} idx={}", - bits_to_string(words, words.len() * mem::size_of::()), bit_str(idx)); + bits_to_string(words, words.len() * mem::size_of::() * 8), idx); let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx); debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask); let oldv = words[word]; @@ -78,13 +78,6 @@ fn bit_lookup(bit: usize) -> BitLookup { BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask } } - -fn bit_str(bit: usize) -> String { - let byte = bit >> 3; - let lobits = 1 << (bit & 0b111); - format!("[{}:{}-{:02x}]", bit, byte, lobits) -} - pub fn bits_to_string(words: &[Word], bits: usize) -> String { let mut result = String::new(); let mut sep = '['; @@ -95,7 +88,7 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String { let mut i = 0; for &word in words.iter() { let mut v = word; - loop { // for each byte in `v`: + for _ in 0..mem::size_of::() { // for each byte in `v`: let remain = bits - i; // If less than a byte remains, then mask just that many bits. let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF }; @@ -110,6 +103,7 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String { i += 8; sep = '-'; } + sep = '|'; } result.push(']'); return result -- cgit 1.4.1-3-g733a5 From ed366980310c6bd77a5a879dc3726ad55d48c5fa Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Jul 2018 11:29:39 -0400 Subject: compute region values using SCCs not iterative flow The strategy is this: - we compute SCCs once all outlives constraints are known - we allocate a set of values **per region** for storing liveness - we allocate a set of values **per SCC** for storing the final values - when we add a liveness constraint to the region R, we also add it to the final value of the SCC to which R belongs - then we can apply the constraints by just walking the DAG for the SCCs and union'ing the children (which have their liveness constraints within) There are a few intermediate refactorings that I really ought to have broken out into their own commits: - reverse the constraint graph so that `R1: R2` means `R1 -> R2` and not `R2 -> R1`. This fits better with the SCC computation and new style of inference (`->` now means "take value from" and not "push value into") - this does affect some of the UI tests, since they traverse the graph, but mostly the artificial ones and they don't necessarily seem worse - put some things (constraint set, etc) into `Rc`. This lets us root them to permit mutation and iteration. It also guarantees they don't change, which is critical to the correctness of the algorithm. - Generalize various helpers that previously operated only on points to work on any sort of region element. --- src/librustc_data_structures/graph/scc/mod.rs | 5 + .../borrow_check/nll/constraint_generation.rs | 4 +- .../borrow_check/nll/constraints/graph.rs | 134 ++++++++++++ .../borrow_check/nll/constraints/mod.rs | 71 +++--- .../borrow_check/nll/explain_borrow/find_use.rs | 2 +- .../nll/region_infer/error_reporting/mod.rs | 24 +-- .../borrow_check/nll/region_infer/mod.rs | 240 +++++++++++---------- .../borrow_check/nll/region_infer/values.rs | 42 ++-- src/librustc_mir/dataflow/impls/borrows.rs | 2 +- .../propagate-approximated-fail-no-postdom.rs | 4 +- .../propagate-approximated-fail-no-postdom.stderr | 14 +- ...shorter-to-static-comparing-against-free.stderr | 4 +- ...ate-fail-to-approximate-longer-no-bounds.stderr | 4 +- ...-fail-to-approximate-longer-wrong-bounds.stderr | 4 +- 14 files changed, 340 insertions(+), 214 deletions(-) create mode 100644 src/librustc_mir/borrow_check/nll/constraints/graph.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index b0f098b3d20..e7a84e47797 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -54,6 +54,11 @@ impl Sccs { self.scc_data.len() } + /// Returns the number of SCCs in the graph. + pub fn all_sccs(&self) -> impl Iterator { + (0 .. self.scc_data.len()).map(S::new) + } + /// Returns the SCC to which a node `r` belongs. pub fn scc(&self, r: N) -> S { self.scc_indices[r] diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 9dcdf7de314..68484888477 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -210,7 +210,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { for (region, location) in liveness_set { debug!("generate: {:#?} is live at {:#?}", region, location); let region_vid = regioncx.to_region_vid(region); - regioncx.add_live_point(region_vid, *location); + regioncx.add_live_element(region_vid, *location); } if let Some(all_facts) = all_facts { @@ -242,7 +242,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { .tcx .for_each_free_region(&live_ty, |live_region| { let vid = live_region.to_region_vid(); - self.regioncx.add_live_point(vid, location); + self.regioncx.add_live_element(vid, location); }); } } diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/nll/constraints/graph.rs new file mode 100644 index 00000000000..45ed37a90ef --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/constraints/graph.rs @@ -0,0 +1,134 @@ +// Copyright 2017 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. + +use borrow_check::nll::constraints::{ConstraintIndex, ConstraintSet}; +use rustc::ty::RegionVid; +use rustc_data_structures::graph; +use rustc_data_structures::indexed_vec::IndexVec; + +crate struct ConstraintGraph { + first_constraints: IndexVec>, + next_constraints: IndexVec>, +} + +impl ConstraintGraph { + /// Create a "dependency graph" where each region constraint `R1: + /// R2` is treated as an edge `R1 -> R2`. We use this graph to + /// construct SCCs for region inference but also for error + /// reporting. + crate fn new(set: &ConstraintSet, num_region_vars: usize) -> Self { + let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars); + let mut next_constraints = IndexVec::from_elem(None, &set.constraints); + + for (idx, constraint) in set.constraints.iter_enumerated().rev() { + let mut head = &mut first_constraints[constraint.sup]; + let mut next = &mut next_constraints[idx]; + debug_assert!(next.is_none()); + *next = *head; + *head = Some(idx); + } + + Self { + first_constraints, + next_constraints, + } + } + + /// Given a region `R`, iterate over all constraints `R: R1`. + crate fn outgoing_edges(&self, region_sup: RegionVid) -> Edges<'_> { + let first = self.first_constraints[region_sup]; + Edges { + graph: self, + pointer: first, + } + } +} + +crate struct Edges<'s> { + graph: &'s ConstraintGraph, + pointer: Option, +} + +impl<'s> Iterator for Edges<'s> { + type Item = ConstraintIndex; + + fn next(&mut self) -> Option { + if let Some(p) = self.pointer { + self.pointer = self.graph.next_constraints[p]; + Some(p) + } else { + None + } + } +} + +crate struct RegionGraph<'s> { + set: &'s ConstraintSet, + constraint_graph: &'s ConstraintGraph, +} + +impl<'s> RegionGraph<'s> { + /// Create a "dependency graph" where each region constraint `R1: + /// R2` is treated as an edge `R1 -> R2`. We use this graph to + /// construct SCCs for region inference but also for error + /// reporting. + crate fn new(set: &'s ConstraintSet, constraint_graph: &'s ConstraintGraph) -> Self { + Self { + set, + constraint_graph, + } + } + + /// Given a region `R`, iterate over all regions `R1` such that + /// there exists a constraint `R: R1`. + crate fn sub_regions(&self, region_sup: RegionVid) -> Successors<'_> { + Successors { + set: self.set, + edges: self.constraint_graph.outgoing_edges(region_sup), + } + } +} + +crate struct Successors<'s> { + set: &'s ConstraintSet, + edges: Edges<'s>, +} + +impl<'s> Iterator for Successors<'s> { + type Item = RegionVid; + + fn next(&mut self) -> Option { + self.edges.next().map(|c| self.set[c].sub) + } +} + +impl<'s> graph::DirectedGraph for RegionGraph<'s> { + type Node = RegionVid; +} + +impl<'s> graph::WithNumNodes for RegionGraph<'s> { + fn num_nodes(&self) -> usize { + self.constraint_graph.first_constraints.len() + } +} + +impl<'s> graph::WithSuccessors for RegionGraph<'s> { + fn successors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter { + self.sub_regions(node) + } +} + +impl<'s, 'graph> graph::GraphSuccessors<'graph> for RegionGraph<'s> { + type Item = RegionVid; + type Iter = Successors<'graph>; +} diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs index eab1de07311..f20802c7d02 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs @@ -9,19 +9,22 @@ // except according to those terms. use rustc::ty::RegionVid; +use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use borrow_check::nll::type_check::Locations; use std::fmt; use std::ops::Deref; +crate mod graph; + #[derive(Clone, Default)] crate struct ConstraintSet { constraints: IndexVec, } impl ConstraintSet { - pub fn push(&mut self, constraint: OutlivesConstraint) { + crate fn push(&mut self, constraint: OutlivesConstraint) { debug!( "ConstraintSet::push({:?}: {:?} @ {:?}", constraint.sup, constraint.sub, constraint.locations @@ -32,12 +35,33 @@ impl ConstraintSet { } self.constraints.push(constraint); } + + /// Constructs a graph from the constraint set; the graph makes it + /// easy to find the constriants affecting a particular region + /// (you should not mutate the set once this graph is + /// constructed). + crate fn graph(&self, num_region_vars: usize) -> graph::ConstraintGraph { + graph::ConstraintGraph::new(self, num_region_vars) + } + + /// Compute cycles (SCCs) in the graph of regions. In particular, + /// find all regions R1, R2 such that R1: R2 and R2: R1 and group + /// them into an SCC, and find the relationships between SCCs. + crate fn compute_sccs( + &self, + constraint_graph: &graph::ConstraintGraph, + ) -> Sccs { + let region_graph = &graph::RegionGraph::new(self, constraint_graph); + Sccs::new(region_graph) + } } impl Deref for ConstraintSet { type Target = IndexVec; - fn deref(&self) -> &Self::Target { &self.constraints } + fn deref(&self) -> &Self::Target { + &self.constraints + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -68,45 +92,4 @@ impl fmt::Debug for OutlivesConstraint { newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); -crate struct ConstraintGraph { - first_constraints: IndexVec>, - next_constraints: IndexVec>, -} - -impl ConstraintGraph { - /// Constraint a graph where each region constraint `R1: R2` is - /// treated as an edge `R2 -> R1`. This is useful for cheaply - /// finding dirty constraints. - crate fn new(set: &ConstraintSet, num_region_vars: usize) -> Self { - let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars); - let mut next_constraints = IndexVec::from_elem(None, &set.constraints); - - for (idx, constraint) in set.constraints.iter_enumerated().rev() { - let mut head = &mut first_constraints[constraint.sub]; - let mut next = &mut next_constraints[idx]; - debug_assert!(next.is_none()); - *next = *head; - *head = Some(idx); - } - - ConstraintGraph { first_constraints, next_constraints } - } - - /// Invokes `op` with the index of any constraints of the form - /// `region_sup: region_sub`. These are the constraints that must - /// be reprocessed when the value of `R1` changes. If you think of - /// each constraint `R1: R2` as an edge `R2 -> R1`, then this - /// gives the set of successors to R2. - crate fn for_each_dependent( - &self, - region_sub: RegionVid, - mut op: impl FnMut(ConstraintIndex), - ) { - let mut p = self.first_constraints[region_sub]; - while let Some(dep_idx) = p { - op(dep_idx); - p = self.next_constraints[dep_idx]; - } - } -} - +newtype_index!(ConstraintSccIndex { DEBUG_FORMAT = "ConstraintSccIndex({})" }); diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs index a65019690e3..9fd9d6cd97c 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs @@ -57,7 +57,7 @@ impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> { queue.push_back(self.start_point); while let Some(p) = queue.pop_front() { - if !self.regioncx.region_contains_point(self.region_vid, p) { + if !self.regioncx.region_contains(self.region_vid, p) { continue; } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index 5405ad91296..c1b73fac893 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -50,18 +50,10 @@ impl fmt::Display for ConstraintCategory { impl<'tcx> RegionInferenceContext<'tcx> { /// Walks the graph of constraints (where `'a: 'b` is considered - /// an edge `'b -> 'a`) to find all paths from `from_region` to + /// an edge `'a -> 'b`) to find all paths from `from_region` to /// `to_region`. The paths are accumulated into the vector /// `results`. The paths are stored as a series of /// `ConstraintIndex` values -- in other words, a list of *edges*. - /// - /// # Parameters - /// - /// - `from_region` - /// When reporting an error, it is useful to be able to determine - /// which constraints influenced the region being reported as an - /// error. This function finds all of the paths from the - /// constraint. fn find_constraint_paths_between_regions( &self, from_region: RegionVid, @@ -97,25 +89,25 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Check if we reached the region we were looking for. if target_test(current_region) { if !stack.is_empty() { - assert_eq!(self.constraints[stack[0]].sub, from_region); + assert_eq!(self.constraints[stack[0]].sup, from_region); results.push(stack.clone()); } return; } - self.constraint_graph.for_each_dependent(current_region, |constraint| { - assert_eq!(self.constraints[constraint].sub, current_region); + for constraint in self.constraint_graph.outgoing_edges(current_region) { + assert_eq!(self.constraints[constraint].sup, current_region); stack.push(constraint); self.find_constraint_paths_between_regions_helper( from_region, - self.constraints[constraint].sup, + self.constraints[constraint].sub, target_test, visited, stack, results, ); stack.pop(); - }); + } } /// This function will return true if a constraint is interesting and false if a constraint @@ -207,7 +199,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Find all paths - let constraint_paths = self.find_constraint_paths_between_regions(outlived_fr, |r| r == fr); + let constraint_paths = self.find_constraint_paths_between_regions(fr, |r| r == outlived_fr); debug!("report_error: constraint_paths={:#?}", constraint_paths); // Find the shortest such path. @@ -316,7 +308,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { while changed { changed = false; - for constraint in &*self.constraints { + for constraint in self.constraints.iter() { if let Some(n) = result_set[constraint.sup] { let m = n + 1; if result_set[constraint.sub] diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 221da10e8e8..369f6bd36f8 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -10,8 +10,10 @@ use super::universal_regions::UniversalRegions; use borrow_check::nll::constraints::{ - ConstraintIndex, ConstraintGraph, ConstraintSet, OutlivesConstraint + ConstraintIndex, ConstraintSccIndex, ConstraintSet, OutlivesConstraint, }; +use borrow_check::nll::constraints::graph::ConstraintGraph; +use borrow_check::nll::region_infer::values::ToElementIndex; use borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; @@ -25,8 +27,9 @@ use rustc::mir::{ }; use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common; -use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::graph::scc::Sccs; +use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; +use rustc_data_structures::indexed_vec::IndexVec; use std::rc::Rc; @@ -55,22 +58,29 @@ pub struct RegionInferenceContext<'tcx> { /// the entire CFG and `end(R)`. liveness_constraints: RegionValues, - /// The final inferred values of the inference variables; `None` - /// until `solve` is invoked. - inferred_values: Option>, + /// The outlives constraints computed by the type-check. + constraints: Rc, - /// The constraints we have accumulated and used during solving. - constraints: ConstraintSet, + /// The constraint-set, but in graph form, making it easy to traverse + /// the constraints adjacent to a particular region. Used to construct + /// the SCC (see `constraint_sccs`) and for error reporting. + constraint_graph: Rc, - /// The constraint-set, but organized by regions. - constraint_graph: ConstraintGraph, + /// The SCC computed from `constraints` and + /// `constraint_graph`. Used to compute the values of each region. + constraint_sccs: Rc>, + + /// The final inferred values of the region variables; we compute + /// one value per SCC. To get the value for any given *region*, + /// you first find which scc it is a part of. + scc_values: RegionValues, /// Type constraints that we check after solving. type_tests: Vec>, /// Information about the universally quantified regions in scope /// on this function and their (known) relations to one another. - universal_regions: UniversalRegions<'tcx>, + universal_regions: Rc>, } struct RegionDefinition<'tcx> { @@ -201,6 +211,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { outlives_constraints: ConstraintSet, type_tests: Vec>, ) -> Self { + let universal_regions = Rc::new(universal_regions); let num_region_variables = var_infos.len(); let num_universal_regions = universal_regions.len(); @@ -212,15 +223,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { .map(|info| RegionDefinition::new(info.origin)) .collect(); - let constraint_graph = ConstraintGraph::new(&outlives_constraints, definitions.len()); + let constraints = Rc::new(outlives_constraints); // freeze constraints + let constraint_graph = Rc::new(constraints.graph(definitions.len())); + let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph)); + + let scc_values = RegionValues::new(elements, constraint_sccs.num_sccs()); let mut result = Self { definitions, elements: elements.clone(), liveness_constraints: RegionValues::new(elements, num_region_variables), - inferred_values: None, - constraints: outlives_constraints, + constraints, + constraint_sccs, constraint_graph, + scc_values, type_tests, universal_regions, }; @@ -262,7 +278,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // For each universally quantified region X: - for variable in self.universal_regions.universal_regions() { + let elements = self.elements.clone(); + let universal_regions = self.universal_regions.clone(); + for variable in universal_regions.universal_regions() { // These should be free-region variables. assert!(match self.definitions[variable].origin { RegionVariableOrigin::NLL(NLLRegionVariableOrigin::FreeRegion) => true, @@ -272,12 +290,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.definitions[variable].is_universal = true; // Add all nodes in the CFG to liveness constraints - for point_index in self.elements.all_point_indices() { - self.liveness_constraints.add_element(variable, point_index); + for point_index in elements.all_point_indices() { + self.add_live_element(variable, point_index); } // Add `end(X)` into the set for X. - self.liveness_constraints.add_element(variable, variable); + self.add_live_element(variable, variable); } } @@ -297,37 +315,38 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Returns true if the region `r` contains the point `p`. /// /// Panics if called before `solve()` executes, - pub fn region_contains_point(&self, r: R, p: Location) -> bool - where - R: ToRegionVid, - { - let inferred_values = self - .inferred_values - .as_ref() - .expect("region values not yet inferred"); - inferred_values.contains(r.to_region_vid(), p) + crate fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + self.scc_values.contains(scc, p) } /// Returns access to the value of `r` for debugging purposes. crate fn region_value_str(&self, r: RegionVid) -> String { - let inferred_values = self - .inferred_values - .as_ref() - .expect("region values not yet inferred"); - - inferred_values.region_value_str(r) + let scc = self.constraint_sccs.scc(r.to_region_vid()); + self.scc_values.region_value_str(scc) } /// Indicates that the region variable `v` is live at the point `point`. /// /// Returns `true` if this constraint is new and `false` is the /// constraint was already present. - pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location) -> bool { - debug!("add_live_point({:?}, {:?})", v, point); - assert!(self.inferred_values.is_none(), "values already inferred"); + pub(super) fn add_live_element( + &mut self, + v: RegionVid, + elem: impl ToElementIndex, + ) -> bool { + debug!("add_live_element({:?}, {:?})", v, elem); - let element = self.elements.index(point); - self.liveness_constraints.add_element(v, element) + // Add to the liveness values for `v`... + if self.liveness_constraints.add_element(v, elem) { + // ...but also add to the SCC in which `v` appears. + let scc = self.constraint_sccs.scc(v); + self.scc_values.add_element(scc, elem); + + true + } else { + false + } } /// Perform region inference and report errors if we see any @@ -352,8 +371,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir: &Mir<'tcx>, mir_def_id: DefId, ) -> Option> { - assert!(self.inferred_values.is_none(), "values already inferred"); - self.propagate_constraints(mir); // If this is a closure, we can propagate unsatisfied @@ -388,56 +405,62 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. - fn propagate_constraints(&mut self, mir: &Mir<'tcx>) { - assert!(self.inferred_values.is_none()); - let inferred_values = self.compute_region_values(mir); - self.inferred_values = Some(inferred_values); - } + fn propagate_constraints(&mut self, _mir: &Mir<'tcx>) { + debug!("propagate_constraints()"); - fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues { - debug!("compute_region_values()"); - debug!("compute_region_values: constraints={:#?}", { + debug!("propagate_constraints: constraints={:#?}", { let mut constraints: Vec<_> = self.constraints.iter().collect(); constraints.sort(); constraints }); - // The initial values for each region are derived from the liveness - // constraints we have accumulated. - let mut inferred_values = self.liveness_constraints.clone(); - - // Constraints that may need to be repropagated (initially all): - let mut dirty_list: Vec<_> = self.constraints.indices().collect(); - - // Set to 0 for each constraint that is on the dirty list: - let mut clean_bit_vec = BitVector::new(dirty_list.len()); + // To propagate constriants, we walk the DAG induced by the + // SCC. For each SCC, we visit its successors and compute + // their values, then we union all those values to get our + // own. + let visited = &mut IdxSetBuf::new_empty(self.constraint_sccs.num_sccs()); + for scc_index in self.constraint_sccs.all_sccs() { + self.propagate_constraint_sccs_if_new(scc_index, visited); + } + } - debug!("propagate_constraints: --------------------"); - while let Some(constraint_idx) = dirty_list.pop() { - clean_bit_vec.insert(constraint_idx.index()); + #[inline] + fn propagate_constraint_sccs_if_new( + &mut self, + scc_a: ConstraintSccIndex, + visited: &mut IdxSet, + ) { + if visited.add(&scc_a) { + self.propagate_constraint_sccs_new(scc_a, visited); + } + } - let constraint = &self.constraints[constraint_idx]; - debug!("propagate_constraints: constraint={:?}", constraint); + fn propagate_constraint_sccs_new( + &mut self, + scc_a: ConstraintSccIndex, + visited: &mut IdxSet, + ) { + let constraint_sccs = self.constraint_sccs.clone(); - if inferred_values.add_region(constraint.sup, constraint.sub) { - debug!("propagate_constraints: sub={:?}", constraint.sub); - debug!("propagate_constraints: sup={:?}", constraint.sup); + // Walk each SCC `B` such that `A: B`... + for &scc_b in constraint_sccs.successors(scc_a) { + debug!( + "propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", + scc_a, scc_b + ); - // The region of `constraint.sup` changed, so find all - // constraints of the form `R: constriant.sup` and - // enqueue them as dirty. We will have to reprocess - // them. - self.constraint_graph.for_each_dependent(constraint.sup, |dep_idx| { - if clean_bit_vec.remove(dep_idx.index()) { - dirty_list.push(dep_idx); - } - }); - } + // ...compute the value of `B`... + self.propagate_constraint_sccs_if_new(scc_b, visited); - debug!("\n"); + // ...and add elements from `B` into `A`. + self.scc_values.add_region(scc_a, scc_b); } - inferred_values + debug!( + "propagate_constraint_sccs: scc_a = {:?} has value {:?}", + scc_a, + self.scc_values.region_value_str(scc_a), + ); } /// Once regions have been propagated, this method is used to see @@ -512,12 +535,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { if self.universal_regions.is_universal_region(r) { return self.definitions[r].external_name; } else { - let inferred_values = self - .inferred_values - .as_ref() - .expect("region values not yet inferred"); + let r_scc = self.constraint_sccs.scc(r); let upper_bound = self.universal_upper_bound(r); - if inferred_values.contains(r, upper_bound) { + if self.scc_values.contains(r_scc, upper_bound) { self.to_error_region(upper_bound) } else { None @@ -552,11 +572,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // region, which ensures it can be encoded in a `ClosureOutlivesRequirement`. let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound); assert!(self.universal_regions.is_universal_region(lower_bound_plus)); - assert!( - !self - .universal_regions - .is_local_free_region(lower_bound_plus) - ); + assert!(!self.universal_regions + .is_local_free_region(lower_bound_plus)); propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject, @@ -584,10 +601,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Option> { let tcx = infcx.tcx; let gcx = tcx.global_tcx(); - let inferred_values = self - .inferred_values - .as_ref() - .expect("region values not yet inferred"); debug!("try_promote_type_test_subject(ty = {:?})", ty); @@ -630,7 +643,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // `'static` is not contained in `r`, we would fail to // find an equivalent. let upper_bound = self.non_local_universal_upper_bound(region_vid); - if inferred_values.contains(region_vid, upper_bound) { + if self.region_contains(region_vid, upper_bound) { tcx.mk_region(ty::ReClosureBound(upper_bound)) } else { // In the case of a failure, use a `ReVar` @@ -663,12 +676,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// except that it converts further takes the non-local upper /// bound of `'y`, so that the final result is non-local. fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid { - let inferred_values = self.inferred_values.as_ref().unwrap(); - debug!( "non_local_universal_upper_bound(r={:?}={})", r, - inferred_values.region_value_str(r) + self.region_value_str(r) ); let lub = self.universal_upper_bound(r); @@ -700,18 +711,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { - let inferred_values = self.inferred_values.as_ref().unwrap(); - debug!( "universal_upper_bound(r={:?}={})", r, - inferred_values.region_value_str(r) + self.region_value_str(r) ); // Find the smallest universal region that contains all other // universal regions within `region`. let mut lub = self.universal_regions.fr_fn_body; - for ur in inferred_values.universal_regions_outlived_by(r) { + let r_scc = self.constraint_sccs.scc(r); + for ur in self.scc_values.universal_regions_outlived_by(r_scc) { lub = self.universal_regions.postdom_upper_bound(lub, ur); } @@ -756,31 +766,29 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> bool { debug!("eval_outlives({:?}: {:?})", sup_region, sub_region); - let inferred_values = self - .inferred_values - .as_ref() - .expect("values for regions not yet inferred"); - debug!( "eval_outlives: sup_region's value = {:?}", - inferred_values.region_value_str(sup_region), + self.region_value_str(sup_region), ); debug!( "eval_outlives: sub_region's value = {:?}", - inferred_values.region_value_str(sub_region), + self.region_value_str(sub_region), ); + let sub_region_scc = self.constraint_sccs.scc(sub_region); + let sup_region_scc = self.constraint_sccs.scc(sup_region); + // Both the `sub_region` and `sup_region` consist of the union // of some number of universal regions (along with the union // of various points in the CFG; ignore those points for // now). Therefore, the sup-region outlives the sub-region if, // for each universal region R1 in the sub-region, there // exists some region R2 in the sup-region that outlives R1. - let universal_outlives = inferred_values - .universal_regions_outlived_by(sub_region) + let universal_outlives = self.scc_values + .universal_regions_outlived_by(sub_region_scc) .all(|r1| { - inferred_values - .universal_regions_outlived_by(sup_region) + self.scc_values + .universal_regions_outlived_by(sup_region_scc) .any(|r2| self.universal_regions.outlives(r2, r1)) }); @@ -796,7 +804,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { return true; } - inferred_values.contains_points(sup_region, sub_region) + self.scc_values + .contains_points(sup_region_scc, sub_region_scc) } /// Once regions have been propagated, this method is used to see @@ -825,8 +834,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) { // The universal regions are always found in a prefix of the // full list. - let universal_definitions = self - .definitions + let universal_definitions = self.definitions .iter_enumerated() .take_while(|(_, fr_definition)| fr_definition.is_universal); @@ -860,13 +868,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, ) { - let inferred_values = self.inferred_values.as_ref().unwrap(); - debug!("check_universal_region(fr={:?})", longer_fr); + let longer_fr_scc = self.constraint_sccs.scc(longer_fr); + // Find every region `o` such that `fr: o` // (because `fr` includes `end(o)`). - for shorter_fr in inferred_values.universal_regions_outlived_by(longer_fr) { + for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { // If it is known that `fr: o`, carry on. if self.universal_regions.outlives(longer_fr, shorter_fr) { continue; diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index bb4fa73ebb0..c5bfb1fc6a5 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -18,7 +18,7 @@ use std::rc::Rc; /// Maps between the various kinds of elements of a region value to /// the internal indices that w use. -pub(super) struct RegionValueElements { +crate struct RegionValueElements { /// For each basic block, how many points are contained within? statements_before_block: IndexVec, num_points: usize, @@ -26,7 +26,7 @@ pub(super) struct RegionValueElements { } impl RegionValueElements { - pub(super) fn new(mir: &Mir<'_>, num_universal_regions: usize) -> Self { + crate fn new(mir: &Mir<'_>, num_universal_regions: usize) -> Self { let mut num_points = 0; let statements_before_block = mir .basic_blocks() @@ -56,22 +56,22 @@ impl RegionValueElements { } /// Total number of element indices that exist. - pub(super) fn num_elements(&self) -> usize { + crate fn num_elements(&self) -> usize { self.num_points + self.num_universal_regions } /// Converts an element of a region value into a `RegionElementIndex`. - pub(super) fn index(&self, elem: T) -> RegionElementIndex { + crate fn index(&self, elem: T) -> RegionElementIndex { elem.to_element_index(self) } /// Iterates over the `RegionElementIndex` for all points in the CFG. - pub(super) fn all_point_indices<'a>(&'a self) -> impl Iterator + 'a { + crate fn all_point_indices<'a>(&'a self) -> impl Iterator + 'a { (0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions)) } /// Converts a particular `RegionElementIndex` to the `RegionElement` it represents. - pub(super) fn to_element(&self, i: RegionElementIndex) -> RegionElement { + crate fn to_element(&self, i: RegionElementIndex) -> RegionElement { debug!("to_element(i={:?})", i); if let Some(r) = self.to_universal_region(i) { @@ -114,7 +114,7 @@ impl RegionValueElements { /// Converts a particular `RegionElementIndex` to a universal /// region, if that is what it represents. Returns `None` /// otherwise. - pub(super) fn to_universal_region(&self, i: RegionElementIndex) -> Option { + crate fn to_universal_region(&self, i: RegionElementIndex) -> Option { if i.index() < self.num_universal_regions { Some(RegionVid::new(i.index())) } else { @@ -138,7 +138,7 @@ newtype_index!(RegionElementIndex { DEBUG_FORMAT = "RegionElementIndex({})" }); /// An individual element in a region value -- the value of a /// particular region variable consists of a set of these elements. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub(super) enum RegionElement { +crate enum RegionElement { /// A point in the control-flow graph. Location(Location), @@ -146,7 +146,7 @@ pub(super) enum RegionElement { UniversalRegion(RegionVid), } -pub(super) trait ToElementIndex: Debug + Copy { +crate trait ToElementIndex: Debug + Copy { fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex; } @@ -179,7 +179,7 @@ impl ToElementIndex for RegionElementIndex { /// variable. The columns consist of either universal regions or /// points in the CFG. #[derive(Clone)] -pub(super) struct RegionValues { +crate struct RegionValues { elements: Rc, matrix: SparseBitMatrix, } @@ -188,7 +188,7 @@ impl RegionValues { /// Creates a new set of "region values" that tracks causal information. /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. - pub(super) fn new(elements: &Rc, num_region_variables: usize) -> Self { + crate fn new(elements: &Rc, num_region_variables: usize) -> Self { assert!( elements.num_universal_regions <= num_region_variables, "universal regions are a subset of the region variables" @@ -205,7 +205,11 @@ impl RegionValues { /// Adds the given element to the value for the given region. Returns true if /// the element is newly added (i.e., was not already present). - pub(super) fn add_element(&mut self, r: N, elem: E) -> bool { + crate fn add_element( + &mut self, + r: N, + elem: impl ToElementIndex, + ) -> bool { let i = self.elements.index(elem); debug!("add(r={:?}, elem={:?})", r, elem); self.matrix.add(r, i) @@ -213,19 +217,19 @@ impl RegionValues { /// Add all elements in `r_from` to `r_to` (because e.g. `r_to: /// r_from`). - pub(super) fn add_region(&mut self, r_to: N, r_from: N) -> bool { + crate fn add_region(&mut self, r_to: N, r_from: N) -> bool { self.matrix.merge(r_from, r_to) } /// True if the region `r` contains the given element. - pub(super) fn contains(&self, r: N, elem: E) -> bool { + crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool { let i = self.elements.index(elem); self.matrix.contains(r, i) } /// True if `sup_region` contains all the CFG points that /// `sub_region` contains. Ignores universal regions. - pub(super) fn contains_points(&self, sup_region: N, sub_region: N) -> bool { + crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool { // This could be done faster by comparing the bitsets. But I // am lazy. self.element_indices_contained_in(sub_region) @@ -236,7 +240,7 @@ impl RegionValues { /// Iterate over the value of the region `r`, yielding up element /// indices. You may prefer `universal_regions_outlived_by` or /// `elements_contained_in`. - pub(super) fn element_indices_contained_in<'a>( + crate fn element_indices_contained_in<'a>( &'a self, r: N, ) -> impl Iterator + 'a { @@ -244,7 +248,7 @@ impl RegionValues { } /// Returns just the universal regions that are contained in a given region's value. - pub(super) fn universal_regions_outlived_by<'a>( + crate fn universal_regions_outlived_by<'a>( &'a self, r: N, ) -> impl Iterator + 'a { @@ -255,7 +259,7 @@ impl RegionValues { } /// Returns all the elements contained in a given region's value. - pub(super) fn elements_contained_in<'a>( + crate fn elements_contained_in<'a>( &'a self, r: N, ) -> impl Iterator + 'a { @@ -264,7 +268,7 @@ impl RegionValues { } /// Returns a "pretty" string value of the region. Meant for debugging. - pub(super) fn region_value_str(&self, r: N) -> String { + crate fn region_value_str(&self, r: N) -> String { let mut result = String::new(); result.push_str("{"); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index a109389aa31..9736ab797b2 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -76,7 +76,7 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( while let Some(location) = stack.pop() { // If region does not contain a point at the location, then add to list and skip // successor locations. - if !regioncx.region_contains_point(borrow_region, location) { + if !regioncx.region_contains(borrow_region, location) { debug!("borrow {:?} gets killed at {:?}", borrow_index, location); borrows_out_of_scope_at_location .entry(location) diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs index b879f9a3398..39050864768 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs @@ -52,9 +52,9 @@ fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell cell_c, |_outlives1, _outlives2, _outlives3, x, y| { // Only works if 'x: 'y: - let p = x.get(); + let p = x.get(); //~ ERROR //~^ WARN not reporting region error due to nll - demand_y(x, y, p) //~ ERROR + demand_y(x, y, p) }, ); } diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index a7a50a3a029..6588cbe8bdf 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -1,28 +1,28 @@ warning: not reporting region error due to nll --> $DIR/propagate-approximated-fail-no-postdom.rs:55:21 | -LL | let p = x.get(); +LL | let p = x.get(); //~ ERROR | ^^^^^^^ error: unsatisfied lifetime constraints - --> $DIR/propagate-approximated-fail-no-postdom.rs:57:13 + --> $DIR/propagate-approximated-fail-no-postdom.rs:55:21 | LL | |_outlives1, _outlives2, _outlives3, x, y| { | ---------- ---------- lifetime `'2` appears in this argument | | | lifetime `'1` appears in this argument -... -LL | demand_y(x, y, p) //~ ERROR - | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` +LL | // Only works if 'x: 'y: +LL | let p = x.get(); //~ ERROR + | ^^^^^^^ argument requires that `'1` must outlive `'2` note: No external requirements --> $DIR/propagate-approximated-fail-no-postdom.rs:53:9 | LL | / |_outlives1, _outlives2, _outlives3, x, y| { LL | | // Only works if 'x: 'y: -LL | | let p = x.get(); +LL | | let p = x.get(); //~ ERROR LL | | //~^ WARN not reporting region error due to nll -LL | | demand_y(x, y, p) //~ ERROR +LL | | demand_y(x, y, p) LL | | }, | |_________^ | diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 96f3d6a6a53..8fd5e898c8d 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -5,7 +5,7 @@ LL | foo(cell, |cell_a, cell_x| { | ^^^ error: unsatisfied lifetime constraints - --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:9 + --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20 | LL | foo(cell, |cell_a, cell_x| { | ------ ------ lifetime `'1` appears in this argument @@ -13,7 +13,7 @@ LL | foo(cell, |cell_a, cell_x| { | lifetime `'2` appears in this argument LL | //~^ WARNING not reporting region error due to nll LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure - | ^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | ^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15 diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index fb98c506c7d..c75b3e6670c 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -5,7 +5,7 @@ LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ error: unsatisfied lifetime constraints - --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9 + --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:24 | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { | --------- - lifetime `'1` appears in this argument @@ -13,7 +13,7 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { | lifetime `'2` appears in this argument LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) - | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | ^^^^^^^ argument requires that `'1` must outlive `'2` note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47 diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 73d39a8502b..2465219ee55 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -5,7 +5,7 @@ LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ error: unsatisfied lifetime constraints - --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9 + --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:24 | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { | ---------- ---------- lifetime `'2` appears in this argument @@ -13,7 +13,7 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y | lifetime `'1` appears in this argument LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) - | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | ^^^^^^^ argument requires that `'1` must outlive `'2` note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47 -- cgit 1.4.1-3-g733a5 From 666c365db338c5f09edc9b0a2623c651a0233f21 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 Jul 2018 01:18:00 -0400 Subject: nit: s/successor/successors/ --- src/librustc_data_structures/graph/scc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index e7a84e47797..64471230f55 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -64,7 +64,7 @@ impl Sccs { self.scc_indices[r] } - /// Returns the successor of the given SCC. + /// Returns the successors of the given SCC. pub fn successors(&self, scc: S) -> &[S] { self.scc_data.successors(scc) } @@ -76,7 +76,7 @@ impl SccData { self.ranges.len() } - /// Returns the successor of the given SCC. + /// Returns the successors of the given SCC. fn successors(&self, scc: S) -> &[S] { // Annoyingly, `range` does not implement `Copy`, so we have // to do `range.start..range.end`: -- cgit 1.4.1-3-g733a5 From 9d2999461fbc07a7059363aacf2b0bcf615d322b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 Jul 2018 01:18:35 -0400 Subject: nit: clarify "keep it around" comment --- src/librustc_data_structures/graph/scc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index 64471230f55..82755ef5ce5 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -122,8 +122,8 @@ struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors + ' /// A set used to strip duplicates. As we accumulate successors /// into the successors_stack, we sometimes get duplicate entries. - /// We use this set to remove those -- we keep it around between - /// successors to amortize memory allocation costs. + /// We use this set to remove those -- we also keep its storage + /// around between successors to amortize memory allocation costs. duplicate_set: FxHashSet, scc_data: SccData, -- cgit 1.4.1-3-g733a5 From 114cdd0816f548f47dbd85628e726663cb681284 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 Jul 2018 01:25:21 -0400 Subject: nit: improve SCC comments --- src/librustc_data_structures/graph/scc/mod.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index 82755ef5ce5..8976e535781 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -177,9 +177,6 @@ where /// D' (i.e., D' < D), we know that N, N', and all nodes in /// between them on the stack are part of an SCC. /// - /// For each node, we track the lowest depth of any successor we - /// have found, along with that - /// /// [wikipedia]: https://bit.ly/2EZIx84 fn construct(graph: &'c G) -> Sccs { let num_nodes = graph.num_nodes(); @@ -213,6 +210,17 @@ where } } + /// Visit a node during the DFS. We first examine its current + /// state -- if it is not yet visited (`NotVisited`), we can push + /// it onto the stack and start walking its successors. + /// + /// If it is already on the DFS stack it will be in the state + /// `BeingVisited`. In that case, we have found a cycle and we + /// return the depth from the stack. + /// + /// Otherwise, we are looking at a node that has already been + /// completely visited. We therefore return `WalkReturn::Complete` + /// with its associated SCC index. fn walk_node(&mut self, depth: usize, node: G::Node) -> WalkReturn { debug!("walk_node(depth = {:?}, node = {:?})", depth, node); match self.find_state(node) { @@ -276,6 +284,7 @@ where _ => false, }); + // Push `node` onto the stack. self.node_states[node] = NodeState::BeingVisited { depth }; self.node_stack.push(node); @@ -294,6 +303,7 @@ where WalkReturn::Cycle { min_depth: successor_min_depth, } => { + // Track the minimum depth we can reach. assert!(successor_min_depth <= depth); if successor_min_depth < min_depth { debug!( @@ -308,6 +318,8 @@ where WalkReturn::Complete { scc_index: successor_scc_index, } => { + // Push the completed SCC indices onto + // the `successors_stack` for later. debug!( "walk_unvisited_node: node = {:?} successor_scc_index = {:?}", node, successor_scc_index @@ -317,9 +329,12 @@ where } } + // Completed walk, remove `node` from the stack. let r = self.node_stack.pop(); debug_assert_eq!(r, Some(node)); + // If `min_depth == depth`, then we are the root of the + // cycle: we can't reach anyone further down the stack. if min_depth == depth { // Note that successor stack may have duplicates, so we // want to remove those: @@ -335,7 +350,7 @@ where WalkReturn::Complete { scc_index } } else { // We are not the head of the cycle. Return back to our - // caller. They will take ownership of the + // caller. They will take ownership of the // `self.successors` data that we pushed. self.node_states[node] = NodeState::InCycleWith { parent: min_cycle_root, -- cgit 1.4.1-3-g733a5 From 0472da3ed643a5957cb1dbe6b790af2528cb5511 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 Jul 2018 01:27:13 -0400 Subject: nit: tweak comment order --- src/librustc_data_structures/graph/scc/test.rs | 44 ++++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/scc/test.rs b/src/librustc_data_structures/graph/scc/test.rs index a273d64a40c..405e1b3a617 100644 --- a/src/librustc_data_structures/graph/scc/test.rs +++ b/src/librustc_data_structures/graph/scc/test.rs @@ -85,9 +85,30 @@ fn test_three_sccs() { #[test] fn test_find_state_2() { // The order in which things will be visited is important to this - // test. It tests part of the `find_state` behavior. + // test. It tests part of the `find_state` behavior. Here is the + // graph: // - // We will start in our DFS by visiting: + // + // /----+ + // 0 <--+ | + // | | | + // v | | + // +-> 1 -> 3 4 + // | | | + // | v | + // +-- 2 <----+ + + let graph = TestGraph::new(0, &[ + (0, 1), + (0, 4), + (1, 2), + (1, 3), + (2, 1), + (3, 0), + (4, 2), + ]); + + // For this graph, we will start in our DFS by visiting: // // 0 -> 1 -> 2 -> 1 // @@ -114,25 +135,6 @@ fn test_find_state_2() { // 2 InCycleWith { 1 } // 3 InCycleWith { 0 } - /* - /----+ - 0 <--+ | - | | | - v | | -+-> 1 -> 3 4 -| | | -| v | -+-- 2 <----+ - */ - let graph = TestGraph::new(0, &[ - (0, 1), - (0, 4), - (1, 2), - (1, 3), - (2, 1), - (3, 0), - (4, 2), - ]); let sccs: Sccs<_, usize> = Sccs::new(&graph); assert_eq!(sccs.num_sccs(), 1); assert_eq!(sccs.scc(0), 0); -- cgit 1.4.1-3-g733a5 From eed2c09a644b161b7a9a8e241e8090f27abc2810 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 Jul 2018 01:28:06 -0400 Subject: nit: fix `all_sccs` comment --- src/librustc_data_structures/graph/scc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index 8976e535781..a989a540102 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -54,7 +54,7 @@ impl Sccs { self.scc_data.len() } - /// Returns the number of SCCs in the graph. + /// Returns an iterator over the SCCs in the graph. pub fn all_sccs(&self) -> impl Iterator { (0 .. self.scc_data.len()).map(S::new) } -- cgit 1.4.1-3-g733a5 From 384d04d31d35ef80324645d06e1afcf3ad48f4ed Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 12 Jul 2018 15:41:24 +0200 Subject: Reduce the number of clone()s needed in obligation_forest Some can be avoided by using remove_entry instead of remove. --- src/librustc_data_structures/obligation_forest/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index df34891ff03..0d6cf260dcd 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -496,9 +496,14 @@ impl ObligationForest { } } NodeState::Done => { - self.waiting_cache.remove(self.nodes[i].obligation.as_predicate()); - // FIXME(HashMap): why can't I get my key back? - self.done_cache.insert(self.nodes[i].obligation.as_predicate().clone()); + // Avoid cloning the key (predicate) in case it exists in the waiting cache + if let Some((predicate, _)) = self.waiting_cache + .remove_entry(self.nodes[i].obligation.as_predicate()) + { + self.done_cache.insert(predicate); + } else { + self.done_cache.insert(self.nodes[i].obligation.as_predicate().clone()); + } node_rewrites[i] = nodes_len; dead_nodes += 1; } -- cgit 1.4.1-3-g733a5 From 7cc527770d1270921647a4324cb30d0d89467de6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 13 Jul 2018 09:57:33 +1000 Subject: Avoid most allocations in `Canonicalizer`. Extra allocations are a significant cost of NLL, and the most common ones come from within `Canonicalizer`. In particular, `canonical_var()` contains this code: indices .entry(kind) .or_insert_with(|| { let cvar1 = variables.push(info); let cvar2 = var_values.push(kind); assert_eq!(cvar1, cvar2); cvar1 }) .clone() `variables` and `var_values` are `Vec`s. `indices` is a `HashMap` used to track what elements have been inserted into `var_values`. If `kind` hasn't been seen before, `indices`, `variables` and `var_values` all get a new element. (The number of elements in each container is always the same.) This results in lots of allocations. In practice, most of the time these containers only end up holding a few elements. This PR changes them to avoid heap allocations in the common case, by changing the `Vec`s to `SmallVec`s and only using `indices` once enough elements are present. (When the number of elements is small, a direct linear search of `var_values` is as good or better than a hashmap lookup.) The changes to `variables` are straightforward and contained within `Canonicalizer`. The changes to `indices` are more complex but also contained within `Canonicalizer`. The changes to `var_values` are more intrusive because they require defining a new type `SmallCanonicalVarValues` -- which is to `CanonicalVarValues` as `SmallVec` is to `Vec -- and passing stack-allocated values of that type in from outside. All this speeds up a number of NLL "check" builds, the best by 2%. --- src/librustc/infer/canonical/canonicalizer.rs | 100 +++++++++++++++-------- src/librustc/infer/canonical/mod.rs | 9 +- src/librustc/infer/canonical/query_result.rs | 29 +++---- src/librustc/infer/canonical/substitute.rs | 2 +- src/librustc/traits/query/dropck_outlives.rs | 4 +- src/librustc/traits/query/evaluate_obligation.rs | 6 +- src/librustc/traits/query/normalize.rs | 6 +- src/librustc/traits/query/type_op/mod.rs | 5 +- src/librustc_data_structures/accumulate_vec.rs | 7 ++ src/librustc_data_structures/small_vec.rs | 4 + src/librustc_traits/chalk_context.rs | 10 +-- src/librustc_typeck/check/mod.rs | 2 +- 12 files changed, 121 insertions(+), 63 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 8b67f04e020..c4de95c60bf 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -16,8 +16,8 @@ //! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html use infer::canonical::{ - Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, CanonicalVarValues, - Canonicalized, + Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized, + SmallCanonicalVarValues, }; use infer::InferCtxt; use std::sync::atomic::Ordering; @@ -26,7 +26,8 @@ use ty::subst::Kind; use ty::{self, CanonicalVar, Lift, Slice, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::small_vec::SmallVec; impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// Canonicalizes a query value `V`. When we canonicalize a query, @@ -47,7 +48,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { pub fn canonicalize_query( &self, value: &V, - ) -> (Canonicalized<'gcx, V>, CanonicalVarValues<'tcx>) + var_values: &mut SmallCanonicalVarValues<'tcx> + ) -> Canonicalized<'gcx, V> where V: TypeFoldable<'tcx> + Lift<'gcx>, { @@ -65,6 +67,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { static_region: true, other_free_regions: true, }, + var_values, ) } @@ -96,10 +99,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { pub fn canonicalize_response( &self, value: &V, - ) -> (Canonicalized<'gcx, V>, CanonicalVarValues<'tcx>) + ) -> Canonicalized<'gcx, V> where V: TypeFoldable<'tcx> + Lift<'gcx>, { + let mut var_values = SmallVec::new(); Canonicalizer::canonicalize( value, Some(self), @@ -108,6 +112,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { static_region: false, other_free_regions: false, }, + &mut var_values ) } @@ -123,7 +128,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { pub fn canonicalize_hr_query_hack( &self, value: &V, - ) -> (Canonicalized<'gcx, V>, CanonicalVarValues<'tcx>) + var_values: &mut SmallCanonicalVarValues<'tcx> + ) -> Canonicalized<'gcx, V> where V: TypeFoldable<'tcx> + Lift<'gcx>, { @@ -141,6 +147,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { static_region: false, other_free_regions: true, }, + var_values ) } } @@ -163,9 +170,11 @@ impl CanonicalizeRegionMode { struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, tcx: TyCtxt<'cx, 'gcx, 'tcx>, - variables: IndexVec, + variables: SmallVec<[CanonicalVarInfo; 8]>, + var_values: &'cx mut SmallCanonicalVarValues<'tcx>, + // Note that indices is only used once `var_values` is big enough to be + // heap-allocated. indices: FxHashMap, CanonicalVar>, - var_values: IndexVec>, canonicalize_region_mode: CanonicalizeRegionMode, needs_canonical_flags: TypeFlags, } @@ -295,7 +304,8 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, tcx: TyCtxt<'cx, 'gcx, 'tcx>, canonicalize_region_mode: CanonicalizeRegionMode, - ) -> (Canonicalized<'gcx, V>, CanonicalVarValues<'tcx>) + var_values: &'cx mut SmallCanonicalVarValues<'tcx> + ) -> Canonicalized<'gcx, V> where V: TypeFoldable<'tcx> + Lift<'gcx>, { @@ -320,10 +330,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { variables: Slice::empty(), value: out_value, }; - let values = CanonicalVarValues { - var_values: IndexVec::default(), - }; - return (canon_value, values); + return canon_value; } let mut canonicalizer = Canonicalizer { @@ -331,9 +338,9 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { tcx, canonicalize_region_mode, needs_canonical_flags, - variables: IndexVec::default(), + variables: SmallVec::new(), + var_values, indices: FxHashMap::default(), - var_values: IndexVec::default(), }; let out_value = value.fold_with(&mut canonicalizer); @@ -348,16 +355,12 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { ) }); - let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables.raw); + let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables); - let canonical_value = Canonical { + Canonical { variables: canonical_variables, value: out_value, - }; - let canonical_var_values = CanonicalVarValues { - var_values: canonicalizer.var_values, - }; - (canonical_value, canonical_var_values) + } } /// Creates a canonical variable replacing `kind` from the input, @@ -366,21 +369,54 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { /// potentially a free region). fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> CanonicalVar { let Canonicalizer { - indices, variables, var_values, + indices, .. } = self; - indices - .entry(kind) - .or_insert_with(|| { - let cvar1 = variables.push(info); - let cvar2 = var_values.push(kind); - assert_eq!(cvar1, cvar2); - cvar1 - }) - .clone() + // This code is hot. `variables` and `var_values` are usually small + // (fewer than 8 elements ~95% of the time). They are SmallVec's to + // avoid allocations in those cases. We also don't use `indices` to + // determine if a kind has been seen before until the limit of 8 has + // been exceeded, to also avoid allocations for `indices`. + if var_values.is_array() { + // `var_values` is stack-allocated. `indices` isn't used yet. Do a + // direct linear search of `var_values`. + if let Some(idx) = var_values.iter().position(|&k| k == kind) { + // `kind` is already present in `var_values`. + CanonicalVar::new(idx) + } else { + // `kind` isn't present in `var_values`. Append it. Likewise + // for `info` and `variables`. + variables.push(info); + var_values.push(kind); + assert_eq!(variables.len(), var_values.len()); + + // If `var_values` has become big enough to be heap-allocated, + // fill up `indices` to facilitate subsequent lookups. + if !var_values.is_array() { + assert!(indices.is_empty()); + *indices = + var_values.iter() + .enumerate() + .map(|(i, &kind)| (kind, CanonicalVar::new(i))) + .collect(); + } + // The cv is the index of the appended element. + CanonicalVar::new(var_values.len() - 1) + } + } else { + // `var_values` is large. Do a hashmap search via `indices`. + *indices + .entry(kind) + .or_insert_with(|| { + variables.push(info); + var_values.push(kind); + assert_eq!(variables.len(), var_values.len()); + CanonicalVar::new(variables.len() - 1) + }) + } } /// Given a type variable `ty_var` of the given kind, first check diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 62424ff9226..958b3391060 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -33,6 +33,7 @@ use infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin}; use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::sync::Lrc; use serialize::UseSpecializedDecodable; use std::ops::Index; @@ -74,6 +75,10 @@ pub struct CanonicalVarValues<'tcx> { pub var_values: IndexVec>, } +/// Like CanonicalVarValues, but for use in places where a SmallVec is +/// appropriate. +pub type SmallCanonicalVarValues<'tcx> = SmallVec<[Kind<'tcx>; 8]>; + /// Information about a canonical variable that is included with the /// canonical value. This is sufficient information for code to create /// a copy of the canonical value in some other inference context, @@ -281,10 +286,6 @@ BraceStructLiftImpl! { } impl<'tcx> CanonicalVarValues<'tcx> { - fn iter<'a>(&'a self) -> impl Iterator> + 'a { - self.var_values.iter().cloned() - } - fn len(&self) -> usize { self.var_values.len() } diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs index b8b13e03afa..02684d962ba 100644 --- a/src/librustc/infer/canonical/query_result.rs +++ b/src/librustc/infer/canonical/query_result.rs @@ -19,7 +19,7 @@ use infer::canonical::substitute::substitute_value; use infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, - Certainty, QueryRegionConstraint, QueryResult}; + Certainty, QueryRegionConstraint, QueryResult, SmallCanonicalVarValues}; use infer::region_constraints::{Constraint, RegionConstraintData}; use infer::InferCtxtBuilder; use infer::{InferCtxt, InferOk, InferResult, RegionObligation}; @@ -103,7 +103,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { T: Debug + Lift<'gcx> + TypeFoldable<'tcx>, { let query_result = self.make_query_result(inference_vars, answer, fulfill_cx)?; - let (canonical_result, _) = self.canonicalize_response(&query_result); + let canonical_result = self.canonicalize_response(&query_result); debug!( "make_canonicalized_query_result: canonical_result = {:#?}", @@ -186,7 +186,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - original_values: &CanonicalVarValues<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, ) -> InferResult<'tcx, R> where @@ -252,7 +252,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - original_values: &CanonicalVarValues<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, output_query_region_constraints: &mut Vec>, ) -> InferResult<'tcx, R> @@ -274,10 +274,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // variable... let mut obligations = vec![]; - for (index, original_value) in original_values.var_values.iter_enumerated() { + for (index, original_value) in original_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. let result_value = query_result - .substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]); + .substitute_projected(self.tcx, &result_subst, + |v| &v.var_values[CanonicalVar::new(index)]); match (original_value.unpack(), result_value.unpack()) { (UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => { // no action needed @@ -341,7 +342,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - original_values: &CanonicalVarValues<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, ) -> InferResult<'tcx, CanonicalVarValues<'tcx>> where @@ -382,7 +383,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { fn query_result_substitution_guess( &self, cause: &ObligationCause<'tcx>, - original_values: &CanonicalVarValues<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, ) -> CanonicalVarValues<'tcx> where @@ -418,14 +419,14 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // e.g., here `result_value` might be `?0` in the example above... if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty { // in which case we would set `canonical_vars[0]` to `Some(?U)`. - opt_values[index] = Some(original_value); + opt_values[index] = Some(*original_value); } } UnpackedKind::Lifetime(result_value) => { // e.g., here `result_value` might be `'?1` in the example above... if let &ty::RegionKind::ReCanonical(index) = result_value { // in which case we would set `canonical_vars[0]` to `Some('static)`. - opt_values[index] = Some(original_value); + opt_values[index] = Some(*original_value); } } } @@ -459,7 +460,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - original_values: &CanonicalVarValues<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, result_subst: &CanonicalVarValues<'tcx>, query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, ) -> InferResult<'tcx, ()> @@ -522,13 +523,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - variables1: &CanonicalVarValues<'tcx>, + variables1: &SmallCanonicalVarValues<'tcx>, variables2: impl Fn(CanonicalVar) -> Kind<'tcx>, ) -> InferResult<'tcx, ()> { self.commit_if_ok(|_| { let mut obligations = vec![]; - for (index, value1) in variables1.var_values.iter_enumerated() { - let value2 = variables2(index); + for (index, value1) in variables1.iter().enumerate() { + let value2 = variables2(CanonicalVar::new(index)); match (value1.unpack(), value2.unpack()) { (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc/infer/canonical/substitute.rs index 5bc1ae689a5..679829f43c5 100644 --- a/src/librustc/infer/canonical/substitute.rs +++ b/src/librustc/infer/canonical/substitute.rs @@ -46,7 +46,7 @@ impl<'tcx, V> Canonical<'tcx, V> { where T: TypeFoldable<'tcx>, { - assert_eq!(self.variables.len(), var_values.var_values.len()); + assert_eq!(self.variables.len(), var_values.len()); let value = projection_fn(&self.value); substitute_value(tcx, var_values, value) } diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 2aaa32aa032..73a9ff4e483 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -10,6 +10,7 @@ use infer::at::At; use infer::InferOk; +use rustc_data_structures::small_vec::SmallVec; use std::iter::FromIterator; use syntax::codemap::Span; use ty::subst::Kind; @@ -50,7 +51,8 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { } let gcx = tcx.global_tcx(); - let (c_ty, orig_values) = self.infcx.canonicalize_query(&self.param_env.and(ty)); + let mut orig_values = SmallVec::new(); + let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); let span = self.cause.span; debug!("c_ty = {:?}", c_ty); match &gcx.dropck_outlives(c_ty) { diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs index c81d1123d42..93fcadceb16 100644 --- a/src/librustc/traits/query/evaluate_obligation.rs +++ b/src/librustc/traits/query/evaluate_obligation.rs @@ -9,6 +9,7 @@ // except according to those terms. use infer::InferCtxt; +use rustc_data_structures::small_vec::SmallVec; use traits::{EvaluationResult, PredicateObligation, SelectionContext, TraitQueryMode, OverflowError}; @@ -38,8 +39,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { - let (c_pred, _) = - self.canonicalize_query(&obligation.param_env.and(obligation.predicate)); + let mut _orig_values = SmallVec::new(); + let c_pred = self.canonicalize_query(&obligation.param_env.and(obligation.predicate), + &mut _orig_values); // Run canonical query. If overflow occurs, rerun from scratch but this time // in standard trait query mode so that overflow is handled appropriately // within `SelectionContext`. diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index a67383fb79a..2203aefa314 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -15,6 +15,7 @@ use infer::{InferCtxt, InferOk}; use infer::at::At; use mir::interpret::{GlobalId, ConstValue}; +use rustc_data_structures::small_vec::SmallVec; use traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use traits::project::Normalized; use ty::{self, Ty, TyCtxt}; @@ -147,8 +148,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx let gcx = self.infcx.tcx.global_tcx(); - let (c_data, orig_values) = - self.infcx.canonicalize_query(&self.param_env.and(*data)); + let mut orig_values = SmallVec::new(); + let c_data = + self.infcx.canonicalize_query(&self.param_env.and(*data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); match gcx.normalize_projection_ty(c_data) { diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs index 3dfa66cd41a..be5e2838963 100644 --- a/src/librustc/traits/query/type_op/mod.rs +++ b/src/librustc/traits/query/type_op/mod.rs @@ -11,6 +11,7 @@ use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint, QueryResult}; use infer::{InferCtxt, InferOk}; +use rustc_data_structures::small_vec::SmallVec; use std::fmt; use std::rc::Rc; use traits::query::Fallible; @@ -103,7 +104,9 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: // `canonicalize_hr_query_hack` here because of things // like the subtype query, which go awry around // `'static` otherwise. - let (canonical_self, canonical_var_values) = infcx.canonicalize_hr_query_hack(&query_key); + let mut canonical_var_values = SmallVec::new(); + let canonical_self = + infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; let canonical_result = Self::shrink_to_tcx_lifetime(&canonical_result); diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index f50b8cadf15..2e8cca3f4f9 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -46,6 +46,13 @@ impl AccumulateVec { AccumulateVec::Array(ArrayVec::new()) } + pub fn is_array(&self) -> bool { + match self { + AccumulateVec::Array(..) => true, + AccumulateVec::Heap(..) => false, + } + } + pub fn one(el: A::Element) -> Self { iter::once(el).collect() } diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index 74738e61b44..83eb54fade1 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -50,6 +50,10 @@ impl SmallVec { SmallVec(AccumulateVec::new()) } + pub fn is_array(&self) -> bool { + self.0.is_array() + } + pub fn with_capacity(cap: usize) -> Self { let mut vec = SmallVec::new(); vec.reserve(cap); diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs index 6062fe03e6a..b0f0b105f3e 100644 --- a/src/librustc_traits/chalk_context.rs +++ b/src/librustc_traits/chalk_context.rs @@ -25,6 +25,7 @@ use rustc::traits::{ use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc::ty::subst::Kind; use rustc::ty::{self, TyCtxt}; +use rustc_data_structures::small_vec::SmallVec; use std::fmt::{self, Debug}; use std::marker::PhantomData; @@ -388,14 +389,15 @@ impl context::UnificationOps, ChalkArenas<'tcx>> &mut self, value: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>, ) -> Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> { - self.infcx.canonicalize_query(value).0 + let mut _orig_values = SmallVec::new(); + self.infcx.canonicalize_query(value, &mut _orig_values) } fn canonicalize_ex_clause( &mut self, value: &ChalkExClause<'tcx>, ) -> Canonical<'gcx, ChalkExClause<'gcx>> { - self.infcx.canonicalize_response(value).0 + self.infcx.canonicalize_response(value) } fn canonicalize_constrained_subst( @@ -403,9 +405,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> subst: CanonicalVarValues<'tcx>, constraints: Vec>, ) -> Canonical<'gcx, ConstrainedSubst<'gcx>> { - self.infcx - .canonicalize_response(&ConstrainedSubst { subst, constraints }) - .0 + self.infcx.canonicalize_response(&ConstrainedSubst { subst, constraints }) } fn u_canonicalize_goal( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 646c4f17568..54386a626eb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -942,7 +942,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { Some(ref ty) => { let o_ty = self.fcx.to_ty(&ty); - let (c_ty, _orig_values) = self.fcx.inh.infcx.canonicalize_response(&o_ty); + let c_ty = self.fcx.inh.infcx.canonicalize_response(&o_ty); debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); -- cgit 1.4.1-3-g733a5 From 8b94d1605be5a73a7e0362d26bdabfeca1250719 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 9 Jul 2018 21:26:20 +0100 Subject: Generate region values directly to reduce memory usage. Also modify `SparseBitMatrix` so that it does not require knowing the dimensions in advance, but instead grows on demand. --- src/librustc_data_structures/bitvec.rs | 56 ++++++++++-- src/librustc_data_structures/indexed_vec.rs | 18 ++++ src/librustc_data_structures/lib.rs | 1 + .../borrow_check/nll/constraint_generation.rs | 40 --------- src/librustc_mir/borrow_check/nll/mod.rs | 9 +- .../borrow_check/nll/region_infer/mod.rs | 27 +++--- .../borrow_check/nll/region_infer/values.rs | 31 ++++--- .../borrow_check/nll/type_check/liveness.rs | 13 ++- .../borrow_check/nll/type_check/mod.rs | 100 ++++++++++++--------- 9 files changed, 174 insertions(+), 121 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index a22dd1fecec..617153d5765 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -281,10 +281,10 @@ where } impl SparseBitMatrix { - /// Create a new `rows x columns` matrix, initially empty. - pub fn new(rows: R, _columns: C) -> SparseBitMatrix { - SparseBitMatrix { - vector: IndexVec::from_elem_n(SparseBitSet::new(), rows.index()), + /// Create a new empty sparse bit matrix with no rows or columns. + pub fn new() -> Self { + Self { + vector: IndexVec::new(), } } @@ -293,6 +293,14 @@ impl SparseBitMatrix { /// /// Returns true if this changed the matrix, and false otherwise. pub fn add(&mut self, row: R, column: C) -> bool { + debug!( + "add(row={:?}, column={:?}, current_len={})", + row, + column, + self.vector.len() + ); + self.vector + .ensure_contains_elem(row, || SparseBitSet::new()); self.vector[row].insert(column) } @@ -301,7 +309,7 @@ impl SparseBitMatrix { /// if the matrix represents (transitive) reachability, can /// `row` reach `column`? pub fn contains(&self, row: R, column: C) -> bool { - self.vector[row].contains(column) + self.vector.get(row).map_or(false, |r| r.contains(column)) } /// Add the bits from row `read` to the bits from row `write`, @@ -315,16 +323,27 @@ impl SparseBitMatrix { let mut changed = false; if read != write { - let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write); + if self.vector.get(read).is_some() { + self.vector + .ensure_contains_elem(write, || SparseBitSet::new()); + let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write); - for read_chunk in bit_set_read.chunks() { - changed = changed | bit_set_write.insert_chunk(read_chunk).any(); + for read_chunk in bit_set_read.chunks() { + changed = changed | bit_set_write.insert_chunk(read_chunk).any(); + } } } changed } + /// Merge a row, `from`, into the `into` row. + pub fn merge_into(&mut self, into: R, from: &SparseBitSet) -> bool { + self.vector + .ensure_contains_elem(into, || SparseBitSet::new()); + self.vector[into].insert_from(from) + } + /// True if `sub` is a subset of `sup` pub fn is_subset(&self, sub: R, sup: R) -> bool { sub == sup || { @@ -336,10 +355,20 @@ impl SparseBitMatrix { } } + /// Number of elements in the matrix. + pub fn len(&self) -> usize { + self.vector.len() + } + /// Iterates through all the columns set to true in a given row of /// the matrix. pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { - self.vector[row].iter() + self.vector.get(row).into_iter().flat_map(|r| r.iter()) + } + + /// Iterates through each row and the accompanying bit set. + pub fn iter_enumerated<'a>(&'a self) -> impl Iterator)> + 'a { + self.vector.iter_enumerated() } } @@ -445,6 +474,15 @@ impl SparseBitSet { } } + /// Insert into bit set from another bit set. + pub fn insert_from(&mut self, from: &SparseBitSet) -> bool { + let mut changed = false; + for read_chunk in from.chunks() { + changed = changed | self.insert_chunk(read_chunk).any(); + } + changed + } + pub fn remove_chunk(&mut self, chunk: SparseChunk) -> SparseChunk { if chunk.bits == 0 { return chunk; diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 26de2191090..e7a75c149cc 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -518,10 +518,28 @@ impl IndexVec { } impl IndexVec { + /// Grows the index vector so that it contains an entry for + /// `elem`; if that is already true, then has no + /// effect. Otherwise, inserts new values as needed by invoking + /// `fill_value`. + #[inline] + pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { + let min_new_len = elem.index() + 1; + if self.len() < min_new_len { + self.raw.resize_with(min_new_len, fill_value); + } + } + #[inline] pub fn resize(&mut self, new_len: usize, value: T) { self.raw.resize(new_len, value) } + + #[inline] + pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { + let min_new_len = elem.index() + 1; + self.raw.resize_with(min_new_len, fill_value); + } } impl IndexVec { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 508dc567fa0..b386f887d77 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -30,6 +30,7 @@ #![feature(optin_builtin_traits)] #![feature(macro_vis_matcher)] #![feature(allow_internal_unstable)] +#![feature(vec_resize_with)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 68484888477..f274f8e9189 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -21,7 +21,6 @@ use rustc::mir::{Local, Statement, Terminator}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts}; -use std::iter; pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( infcx: &InferCtxt<'cx, 'gcx, 'tcx>, @@ -30,7 +29,6 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( location_table: &LocationTable, mir: &Mir<'tcx>, borrow_set: &BorrowSet<'tcx>, - liveness_set_from_typeck: &[(ty::Region<'tcx>, Location)], ) { let mut cg = ConstraintGeneration { borrow_set, @@ -40,8 +38,6 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( all_facts, }; - cg.add_region_liveness_constraints_from_type_check(liveness_set_from_typeck); - for (bb, data) in mir.basic_blocks().iter_enumerated() { cg.visit_basic_block_data(bb, data); } @@ -189,42 +185,6 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx } impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { - /// The MIR type checker generates region liveness constraints - /// that we also have to respect. - fn add_region_liveness_constraints_from_type_check( - &mut self, - liveness_set: &[(ty::Region<'tcx>, Location)], - ) { - debug!( - "add_region_liveness_constraints_from_type_check(liveness_set={} items)", - liveness_set.len(), - ); - - let ConstraintGeneration { - regioncx, - location_table, - all_facts, - .. - } = self; - - for (region, location) in liveness_set { - debug!("generate: {:#?} is live at {:#?}", region, location); - let region_vid = regioncx.to_region_vid(region); - regioncx.add_live_element(region_vid, *location); - } - - if let Some(all_facts) = all_facts { - all_facts - .region_live_at - .extend(liveness_set.into_iter().flat_map(|(region, location)| { - let r = regioncx.to_region_vid(region); - let p1 = location_table.start_index(*location); - let p2 = location_table.mid_index(*location); - iter::once((r, p1)).chain(iter::once((r, p2))) - })); - } - } - /// Some variable with type `live_ty` is "regular live" at /// `location` -- i.e., it may be used later. This means that all /// regions appearing in the type `live_ty` must be live at diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index acd9223e425..5fcf46f6903 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -12,6 +12,7 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::{LocationIndex, LocationTable}; use borrow_check::nll::facts::AllFactsExt; use borrow_check::nll::type_check::MirTypeckRegionConstraints; +use borrow_check::nll::region_infer::values::RegionValueElements; use dataflow::indexes::BorrowIndex; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; @@ -99,6 +100,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( None }; + let elements = &Rc::new(RegionValueElements::new(mir, universal_regions.len())); + // Run the MIR type-checker. let liveness = &LivenessResults::compute(mir); let constraint_sets = type_check::type_check( @@ -113,6 +116,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( &mut all_facts, flow_inits, move_data, + elements, ); if let Some(all_facts) = &mut all_facts { @@ -126,7 +130,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( // base constraints generated by the type-check. let var_origins = infcx.take_region_var_origins(); let MirTypeckRegionConstraints { - liveness_set, + liveness_constraints, outlives_constraints, type_tests, } = constraint_sets; @@ -136,6 +140,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( mir, outlives_constraints, type_tests, + liveness_constraints, + elements, ); // Generate various additional constraints. @@ -146,7 +152,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( location_table, &mir, borrow_set, - &liveness_set, ); invalidation::generate_invalidates( infcx, diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 369f6bd36f8..5159fdc9fba 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -37,7 +37,7 @@ mod annotation; mod dump_mir; mod error_reporting; mod graphviz; -mod values; +pub mod values; use self::values::{RegionValueElements, RegionValues}; use super::ToRegionVid; @@ -66,8 +66,8 @@ pub struct RegionInferenceContext<'tcx> { /// the SCC (see `constraint_sccs`) and for error reporting. constraint_graph: Rc, - /// The SCC computed from `constraints` and - /// `constraint_graph`. Used to compute the values of each region. + /// The SCC computed from `constraints` and the constraint graph. Used to compute the values + /// of each region. constraint_sccs: Rc>, /// The final inferred values of the region variables; we compute @@ -207,15 +207,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn new( var_infos: VarInfos, universal_regions: UniversalRegions<'tcx>, - mir: &Mir<'tcx>, + _mir: &Mir<'tcx>, outlives_constraints: ConstraintSet, type_tests: Vec>, + liveness_constraints: RegionValues, + elements: &Rc, ) -> Self { let universal_regions = Rc::new(universal_regions); - let num_region_variables = var_infos.len(); - let num_universal_regions = universal_regions.len(); - - let elements = &Rc::new(RegionValueElements::new(mir, num_universal_regions)); // Create a RegionDefinition for each inference variable. let definitions: IndexVec<_, _> = var_infos @@ -227,15 +225,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { let constraint_graph = Rc::new(constraints.graph(definitions.len())); let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph)); - let scc_values = RegionValues::new(elements, constraint_sccs.num_sccs()); + let mut scc_values = RegionValues::new(elements); + + for (region, location_set) in liveness_constraints.iter_enumerated() { + let scc = constraint_sccs.scc(region); + scc_values.merge_into(scc, location_set); + } let mut result = Self { definitions, elements: elements.clone(), - liveness_constraints: RegionValues::new(elements, num_region_variables), + liveness_constraints, constraints, - constraint_sccs, constraint_graph, + constraint_sccs, scc_values, type_tests, universal_regions, @@ -414,7 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints }); - // To propagate constriants, we walk the DAG induced by the + // To propagate constraints, we walk the DAG induced by the // SCC. For each SCC, we visit its successors and compute // their values, then we union all those values to get our // own. diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index c5bfb1fc6a5..f041483a8ff 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -10,7 +10,7 @@ use rustc::mir::{BasicBlock, Location, Mir}; use rustc::ty::RegionVid; -use rustc_data_structures::bitvec::SparseBitMatrix; +use rustc_data_structures::bitvec::{SparseBitMatrix, SparseBitSet}; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use std::fmt::Debug; @@ -55,11 +55,6 @@ impl RegionValueElements { } } - /// Total number of element indices that exist. - crate fn num_elements(&self) -> usize { - self.num_points + self.num_universal_regions - } - /// Converts an element of a region value into a `RegionElementIndex`. crate fn index(&self, elem: T) -> RegionElementIndex { elem.to_element_index(self) @@ -188,18 +183,10 @@ impl RegionValues { /// Creates a new set of "region values" that tracks causal information. /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. - crate fn new(elements: &Rc, num_region_variables: usize) -> Self { - assert!( - elements.num_universal_regions <= num_region_variables, - "universal regions are a subset of the region variables" - ); - + crate fn new(elements: &Rc) -> Self { Self { elements: elements.clone(), - matrix: SparseBitMatrix::new( - N::new(num_region_variables), - RegionElementIndex::new(elements.num_elements()), - ), + matrix: SparseBitMatrix::new(), } } @@ -227,6 +214,18 @@ impl RegionValues { self.matrix.contains(r, i) } + /// Iterates through each row and the accompanying bit set. + pub fn iter_enumerated<'a>( + &'a self + ) -> impl Iterator)> + 'a { + self.matrix.iter_enumerated() + } + + /// Merge a row, `from`, originating in another `RegionValues` into the `into` row. + pub fn merge_into(&mut self, into: N, from: &SparseBitSet) -> bool { + self.matrix.merge_into(into, from) + } + /// True if `sup_region` contains all the CFG points that /// `sub_region` contains. Ignores universal regions. crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool { diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs index 91025e3f4af..cd468eabd5f 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs @@ -168,7 +168,18 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo ); cx.tcx().for_each_free_region(&value, |live_region| { - cx.constraints.liveness_set.push((live_region, location)); + if let Some(ref mut borrowck_context) = cx.borrowck_context { + let region_vid = borrowck_context.universal_regions.to_region_vid(live_region); + borrowck_context.constraints.liveness_constraints.add_element(region_vid, location); + + if let Some(all_facts) = borrowck_context.all_facts { + let start_index = borrowck_context.location_table.start_index(location); + all_facts.region_live_at.push((region_vid, start_index)); + + let mid_index = borrowck_context.location_table.mid_index(location); + all_facts.region_live_at.push((region_vid, mid_index)); + } + } }); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 25f2be23177..e188c9d7559 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -16,6 +16,7 @@ use borrow_check::location::LocationTable; use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; +use borrow_check::nll::region_infer::values::{RegionValues, RegionValueElements}; use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::ToRegionVid; use dataflow::move_paths::MoveData; @@ -33,8 +34,9 @@ use rustc::mir::*; use rustc::traits::query::type_op; use rustc::traits::query::{Fallible, NoSolution}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; +use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants, RegionVid}; use std::fmt; +use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; use transform::{MirPass, MirSource}; use util::liveness::LivenessResults; @@ -111,39 +113,55 @@ pub(crate) fn type_check<'gcx, 'tcx>( all_facts: &mut Option, flow_inits: &mut FlowAtLocation>, move_data: &MoveData<'tcx>, + elements: &Rc, ) -> MirTypeckRegionConstraints<'tcx> { let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); - type_check_internal( - infcx, - mir_def_id, - param_env, - mir, - &universal_regions.region_bound_pairs, - Some(implicit_region_bound), - Some(BorrowCheckContext { + let mut constraints = MirTypeckRegionConstraints { + liveness_constraints: RegionValues::new(elements), + outlives_constraints: ConstraintSet::default(), + type_tests: Vec::default(), + }; + + { + let mut borrowck_context = BorrowCheckContext { universal_regions, location_table, borrow_set, all_facts, - }), - &mut |cx| { - liveness::generate(cx, mir, liveness, flow_inits, move_data); + constraints: &mut constraints, + }; + + type_check_internal( + infcx, + mir_def_id, + param_env, + mir, + &universal_regions.region_bound_pairs, + Some(implicit_region_bound), + Some(&mut borrowck_context), + |cx| { + liveness::generate(cx, mir, liveness, flow_inits, move_data); - cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions); - }, - ) + cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions); + }, + ); + } + + constraints } -fn type_check_internal<'gcx, 'tcx>( - infcx: &InferCtxt<'_, 'gcx, 'tcx>, +fn type_check_internal<'a, 'gcx, 'tcx, F>( + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, mir_def_id: DefId, param_env: ty::ParamEnv<'gcx>, - mir: &Mir<'tcx>, - region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)], + mir: &'a Mir<'tcx>, + region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, - borrowck_context: Option>, - extra: &mut dyn FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>), -) -> MirTypeckRegionConstraints<'tcx> { + borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, + mut extra: F, +) + where F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) +{ let mut checker = TypeChecker::new( infcx, mir, @@ -165,8 +183,6 @@ fn type_check_internal<'gcx, 'tcx>( } extra(&mut checker); - - checker.constraints } fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { @@ -603,8 +619,7 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, reported_errors: FxHashSet<(Ty<'tcx>, Span)>, - constraints: MirTypeckRegionConstraints<'tcx>, - borrowck_context: Option>, + borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, } struct BorrowCheckContext<'a, 'tcx: 'a> { @@ -612,11 +627,11 @@ struct BorrowCheckContext<'a, 'tcx: 'a> { location_table: &'a LocationTable, all_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, } /// A collection of region constraints that must be satisfied for the /// program to be considered well-typed. -#[derive(Default)] crate struct MirTypeckRegionConstraints<'tcx> { /// In general, the type-checker is not responsible for enforcing /// liveness constraints; this job falls to the region inferencer, @@ -625,7 +640,7 @@ crate struct MirTypeckRegionConstraints<'tcx> { /// not otherwise appear in the MIR -- in particular, the /// late-bound regions that it instantiates at call-sites -- and /// hence it must report on their liveness constraints. - crate liveness_set: Vec<(ty::Region<'tcx>, Location)>, + crate liveness_constraints: RegionValues, crate outlives_constraints: ConstraintSet, @@ -717,7 +732,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { param_env: ty::ParamEnv<'gcx>, region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, - borrowck_context: Option>, + borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, ) -> Self { TypeChecker { infcx, @@ -729,7 +744,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { implicit_region_bound, borrowck_context, reported_errors: FxHashSet(), - constraints: MirTypeckRegionConstraints::default(), } } @@ -767,7 +781,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { locations, data ); - if let Some(borrowck_context) = &mut self.borrowck_context { + if let Some(ref mut borrowck_context) = self.borrowck_context { constraint_conversion::ConstraintConversion::new( self.infcx.tcx, borrowck_context.universal_regions, @@ -776,8 +790,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.implicit_region_bound, self.param_env, locations, - &mut self.constraints.outlives_constraints, - &mut self.constraints.type_tests, + &mut borrowck_context.constraints.outlives_constraints, + &mut borrowck_context.constraints.type_tests, &mut borrowck_context.all_facts, ).convert_all(&data); } @@ -993,9 +1007,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // output) types in the signature must be live, since // all the inputs that fed into it were live. for &late_bound_region in map.values() { - self.constraints - .liveness_set - .push((late_bound_region, term_location)); + if let Some(ref mut borrowck_context) = self.borrowck_context { + let region_vid = borrowck_context.universal_regions.to_region_vid( + late_bound_region); + borrowck_context.constraints + .liveness_constraints + .add_element(region_vid, term_location); + } } self.check_call_inputs(mir, term, &sig, args, term_location); @@ -1487,9 +1505,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { borrow_set, location_table, all_facts, + constraints, .. - } = match &mut self.borrowck_context { - Some(borrowck_context) => borrowck_context, + } = match self.borrowck_context { + Some(ref mut borrowck_context) => borrowck_context, None => return, }; @@ -1531,7 +1550,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { ty::TyRef(ref_region, _, mutbl) => { - self.constraints + constraints .outlives_constraints .push(OutlivesConstraint { sup: ref_region.to_region_vid(), @@ -1792,8 +1811,7 @@ impl MirPass for TypeckMir { let param_env = tcx.param_env(def_id); tcx.infer_ctxt().enter(|infcx| { - let _ = - type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, &mut |_| ()); + type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, |_| ()); // For verification purposes, we just ignore the resulting // region constraint sets. Not our problem. =) -- cgit 1.4.1-3-g733a5 From 798209e78b90b83a3742f713b70473b6ab799aca Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 18 Jul 2018 15:03:43 +1000 Subject: Speed up `SparseBitMatrix`. Using a `BTreeMap` to represent rows in the bit matrix is really slow. This patch changes things so that each row is represented by a `BitVector`. This is a less sparse representation, but a much faster one. As a result, `SparseBitSet` and `SparseChunk` can be removed. Other minor changes in this patch. - It renames `BitVector::insert()` as `merge()`, which matches the terminology in the other classes in bitvec.rs. - It removes `SparseBitMatrix::is_subset()`, which is unused. - It reinstates `RegionValueElements::num_elements()`, which #52190 had removed. - It removes a low-value `debug!` call in `SparseBitMatrix::add()`. --- src/librustc_data_structures/bitvec.rs | 236 +++------------------ .../borrow_check/nll/region_infer/values.rs | 13 +- 2 files changed, 37 insertions(+), 212 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 617153d5765..ee903e49642 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -9,8 +9,6 @@ // except according to those terms. use indexed_vec::{Idx, IndexVec}; -use std::collections::btree_map::Entry; -use std::collections::BTreeMap; use std::iter::FromIterator; use std::marker::PhantomData; @@ -72,7 +70,7 @@ impl BitVector { } #[inline] - pub fn insert_all(&mut self, all: &BitVector) -> bool { + pub fn merge(&mut self, all: &BitVector) -> bool { assert!(self.data.len() == all.data.len()); let mut changed = false; for (i, j) in self.data.iter_mut().zip(&all.data) { @@ -271,20 +269,26 @@ impl BitMatrix { } } +/// A moderately sparse bit matrix: rows are appended lazily, but columns +/// within appended rows are instantiated fully upon creation. #[derive(Clone, Debug)] pub struct SparseBitMatrix where R: Idx, C: Idx, { - vector: IndexVec>, + columns: usize, + vector: IndexVec, + marker: PhantomData, } impl SparseBitMatrix { /// Create a new empty sparse bit matrix with no rows or columns. - pub fn new() -> Self { + pub fn new(columns: usize) -> Self { Self { + columns, vector: IndexVec::new(), + marker: PhantomData, } } @@ -293,15 +297,10 @@ impl SparseBitMatrix { /// /// Returns true if this changed the matrix, and false otherwise. pub fn add(&mut self, row: R, column: C) -> bool { - debug!( - "add(row={:?}, column={:?}, current_len={})", - row, - column, - self.vector.len() - ); + let columns = self.columns; self.vector - .ensure_contains_elem(row, || SparseBitSet::new()); - self.vector[row].insert(column) + .ensure_contains_elem(row, || BitVector::new(columns)); + self.vector[row].insert(column.index()) } /// Do the bits from `row` contain `column`? Put another way, is @@ -309,7 +308,7 @@ impl SparseBitMatrix { /// if the matrix represents (transitive) reachability, can /// `row` reach `column`? pub fn contains(&self, row: R, column: C) -> bool { - self.vector.get(row).map_or(false, |r| r.contains(column)) + self.vector.get(row).map_or(false, |r| r.contains(column.index())) } /// Add the bits from row `read` to the bits from row `write`, @@ -320,39 +319,23 @@ impl SparseBitMatrix { /// `write` can reach everything that `read` can (and /// potentially more). pub fn merge(&mut self, read: R, write: R) -> bool { - let mut changed = false; - - if read != write { - if self.vector.get(read).is_some() { - self.vector - .ensure_contains_elem(write, || SparseBitSet::new()); - let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write); - - for read_chunk in bit_set_read.chunks() { - changed = changed | bit_set_write.insert_chunk(read_chunk).any(); - } - } + if read == write || self.vector.get(read).is_none() { + return false; } - changed + let columns = self.columns; + self.vector + .ensure_contains_elem(write, || BitVector::new(columns)); + let (bitvec_read, bitvec_write) = self.vector.pick2_mut(read, write); + bitvec_write.merge(bitvec_read) } /// Merge a row, `from`, into the `into` row. - pub fn merge_into(&mut self, into: R, from: &SparseBitSet) -> bool { + pub fn merge_into(&mut self, into: R, from: &BitVector) -> bool { + let columns = self.columns; self.vector - .ensure_contains_elem(into, || SparseBitSet::new()); - self.vector[into].insert_from(from) - } - - /// True if `sub` is a subset of `sup` - pub fn is_subset(&self, sub: R, sup: R) -> bool { - sub == sup || { - let bit_set_sub = &self.vector[sub]; - let bit_set_sup = &self.vector[sup]; - bit_set_sub - .chunks() - .all(|read_chunk| read_chunk.bits_eq(bit_set_sup.contains_chunk(read_chunk))) - } + .ensure_contains_elem(into, || BitVector::new(columns)); + self.vector[into].merge(from) } /// Number of elements in the matrix. @@ -363,178 +346,15 @@ impl SparseBitMatrix { /// Iterates through all the columns set to true in a given row of /// the matrix. pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { - self.vector.get(row).into_iter().flat_map(|r| r.iter()) + self.vector.get(row).into_iter().flat_map(|r| r.iter().map(|n| C::new(n))) } /// Iterates through each row and the accompanying bit set. - pub fn iter_enumerated<'a>(&'a self) -> impl Iterator)> + 'a { + pub fn iter_enumerated<'a>(&'a self) -> impl Iterator + 'a { self.vector.iter_enumerated() } } -#[derive(Clone, Debug)] -pub struct SparseBitSet { - chunk_bits: BTreeMap, - _marker: PhantomData, -} - -#[derive(Copy, Clone)] -pub struct SparseChunk { - key: u32, - bits: Word, - _marker: PhantomData, -} - -impl SparseChunk { - #[inline] - pub fn one(index: I) -> Self { - let index = index.index(); - let key_usize = index / 128; - let key = key_usize as u32; - assert_eq!(key as usize, key_usize); - SparseChunk { - key, - bits: 1 << (index % 128), - _marker: PhantomData, - } - } - - #[inline] - pub fn any(&self) -> bool { - self.bits != 0 - } - - #[inline] - pub fn bits_eq(&self, other: SparseChunk) -> bool { - self.bits == other.bits - } - - pub fn iter(&self) -> impl Iterator { - let base = self.key as usize * 128; - let mut bits = self.bits; - (0..128) - .map(move |i| { - let current_bits = bits; - bits >>= 1; - (i, current_bits) - }) - .take_while(|&(_, bits)| bits != 0) - .filter_map(move |(i, bits)| { - if (bits & 1) != 0 { - Some(I::new(base + i)) - } else { - None - } - }) - } -} - -impl SparseBitSet { - pub fn new() -> Self { - SparseBitSet { - chunk_bits: BTreeMap::new(), - _marker: PhantomData, - } - } - - pub fn capacity(&self) -> usize { - self.chunk_bits.len() * 128 - } - - /// Returns a chunk containing only those bits that are already - /// present. You can test therefore if `self` contains all the - /// bits in chunk already by doing `chunk == - /// self.contains_chunk(chunk)`. - pub fn contains_chunk(&self, chunk: SparseChunk) -> SparseChunk { - SparseChunk { - bits: self.chunk_bits - .get(&chunk.key) - .map_or(0, |bits| bits & chunk.bits), - ..chunk - } - } - - /// Modifies `self` to contain all the bits from `chunk` (in - /// addition to any pre-existing bits); returns a new chunk that - /// contains only those bits that were newly added. You can test - /// if anything was inserted by invoking `any()` on the returned - /// value. - pub fn insert_chunk(&mut self, chunk: SparseChunk) -> SparseChunk { - if chunk.bits == 0 { - return chunk; - } - let bits = self.chunk_bits.entry(chunk.key).or_insert(0); - let old_bits = *bits; - let new_bits = old_bits | chunk.bits; - *bits = new_bits; - let changed = new_bits ^ old_bits; - SparseChunk { - bits: changed, - ..chunk - } - } - - /// Insert into bit set from another bit set. - pub fn insert_from(&mut self, from: &SparseBitSet) -> bool { - let mut changed = false; - for read_chunk in from.chunks() { - changed = changed | self.insert_chunk(read_chunk).any(); - } - changed - } - - pub fn remove_chunk(&mut self, chunk: SparseChunk) -> SparseChunk { - if chunk.bits == 0 { - return chunk; - } - let changed = match self.chunk_bits.entry(chunk.key) { - Entry::Occupied(mut bits) => { - let old_bits = *bits.get(); - let new_bits = old_bits & !chunk.bits; - if new_bits == 0 { - bits.remove(); - } else { - bits.insert(new_bits); - } - new_bits ^ old_bits - } - Entry::Vacant(_) => 0, - }; - SparseChunk { - bits: changed, - ..chunk - } - } - - pub fn clear(&mut self) { - self.chunk_bits.clear(); - } - - pub fn chunks<'a>(&'a self) -> impl Iterator> + 'a { - self.chunk_bits.iter().map(|(&key, &bits)| SparseChunk { - key, - bits, - _marker: PhantomData, - }) - } - - pub fn contains(&self, index: I) -> bool { - self.contains_chunk(SparseChunk::one(index)).any() - } - - pub fn insert(&mut self, index: I) -> bool { - self.insert_chunk(SparseChunk::one(index)).any() - } - - pub fn remove(&mut self, index: I) -> bool { - self.remove_chunk(SparseChunk::one(index)).any() - } - - pub fn iter<'a>(&'a self) -> impl Iterator + 'a { - self.chunks().flat_map(|chunk| chunk.iter()) - } -} - #[inline] fn words(elements: usize) -> usize { (elements + WORD_BITS - 1) / WORD_BITS @@ -584,8 +404,8 @@ fn union_two_vecs() { assert!(!vec1.insert(3)); assert!(vec2.insert(5)); assert!(vec2.insert(64)); - assert!(vec1.insert_all(&vec2)); - assert!(!vec1.insert_all(&vec2)); + assert!(vec1.merge(&vec2)); + assert!(!vec1.merge(&vec2)); assert!(vec1.contains(3)); assert!(!vec1.contains(4)); assert!(vec1.contains(5)); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index f041483a8ff..20b188424f9 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -10,7 +10,7 @@ use rustc::mir::{BasicBlock, Location, Mir}; use rustc::ty::RegionVid; -use rustc_data_structures::bitvec::{SparseBitMatrix, SparseBitSet}; +use rustc_data_structures::bitvec::{BitVector, SparseBitMatrix}; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use std::fmt::Debug; @@ -55,6 +55,11 @@ impl RegionValueElements { } } + /// Total number of element indices that exist. + crate fn num_elements(&self) -> usize { + self.num_points + self.num_universal_regions + } + /// Converts an element of a region value into a `RegionElementIndex`. crate fn index(&self, elem: T) -> RegionElementIndex { elem.to_element_index(self) @@ -186,7 +191,7 @@ impl RegionValues { crate fn new(elements: &Rc) -> Self { Self { elements: elements.clone(), - matrix: SparseBitMatrix::new(), + matrix: SparseBitMatrix::new(elements.num_elements()), } } @@ -217,12 +222,12 @@ impl RegionValues { /// Iterates through each row and the accompanying bit set. pub fn iter_enumerated<'a>( &'a self - ) -> impl Iterator)> + 'a { + ) -> impl Iterator + 'a { self.matrix.iter_enumerated() } /// Merge a row, `from`, originating in another `RegionValues` into the `into` row. - pub fn merge_into(&mut self, into: N, from: &SparseBitSet) -> bool { + pub fn merge_into(&mut self, into: N, from: &BitVector) -> bool { self.matrix.merge_into(into, from) } -- cgit 1.4.1-3-g733a5 From 2eb83ee527fdb4bcd740ea41c43e9d2d52f99c1c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 18 Jul 2018 21:53:54 +0300 Subject: data_structures: Add a reference wrapper for pointer-indexed maps/sets Use `ptr::eq` for comparing pointers --- src/liballoc/collections/btree/node.rs | 2 +- src/librustc/lint/mod.rs | 4 +-- src/librustc/ty/mod.rs | 9 +++---- src/librustc/ty/query/job.rs | 9 ++++--- src/librustc_data_structures/lib.rs | 21 +++++++-------- src/librustc_data_structures/ptr_key.rs | 45 +++++++++++++++++++++++++++++++++ src/librustc_resolve/resolve_imports.rs | 16 ++++++------ 7 files changed, 76 insertions(+), 30 deletions(-) create mode 100644 src/librustc_data_structures/ptr_key.rs (limited to 'src/librustc_data_structures') diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 19bdcbc6ad6..0ae45b31232 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -103,7 +103,7 @@ impl LeafNode { } fn is_shared_root(&self) -> bool { - self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode + ptr::eq(self, &EMPTY_ROOT_NODE as *const _ as *const _) } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e3d35a7c105..dc1c9f7c108 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -39,7 +39,7 @@ use hir::intravisit; use hir; use lint::builtin::BuiltinLintDiagnostics; use session::{Session, DiagnosticMessageId}; -use std::hash; +use std::{hash, ptr}; use syntax::ast; use syntax::codemap::MultiSpan; use syntax::edition::Edition; @@ -354,7 +354,7 @@ pub struct LintId { impl PartialEq for LintId { fn eq(&self, other: &LintId) -> bool { - (self.lint as *const Lint) == (other.lint as *const Lint) + ptr::eq(self.lint, other.lint) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 178f0d3cdcb..bd24b93f029 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -47,7 +47,7 @@ use std::ops::Deref; use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; use std::slice; use std::vec::IntoIter; -use std::mem; +use std::{mem, ptr}; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; @@ -527,8 +527,7 @@ impl<'tcx> PartialOrd for TyS<'tcx> { impl<'tcx> PartialEq for TyS<'tcx> { #[inline] fn eq(&self, other: &TyS<'tcx>) -> bool { - // (self as *const _) == (other as *const _) - (self as *const TyS<'tcx>) == (other as *const TyS<'tcx>) + ptr::eq(self, other) } } impl<'tcx> Eq for TyS<'tcx> {} @@ -678,7 +677,7 @@ impl PartialOrd for Slice where T: PartialOrd { impl PartialEq for Slice { #[inline] fn eq(&self, other: &Slice) -> bool { - (self as *const _) == (other as *const _) + ptr::eq(self, other) } } impl Eq for Slice {} @@ -1730,7 +1729,7 @@ impl Ord for AdtDef { impl PartialEq for AdtDef { // AdtDef are always interned and this is part of TyS equality #[inline] - fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } + fn eq(&self, other: &Self) -> bool { ptr::eq(self, other) } } impl Eq for AdtDef {} diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index a54deeca293..6cc71642c42 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -11,6 +11,7 @@ #![allow(warnings)] use std::mem; +use rustc_data_structures::ptr_key::PtrKey; use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak}; use rustc_data_structures::OnDrop; use syntax_pos::Span; @@ -20,7 +21,7 @@ use ty::query::plumbing::CycleError; use ty::context::TyCtxt; use errors::Diagnostic; use std::process; -use std::fmt; +use std::{fmt, ptr}; use std::collections::HashSet; #[cfg(parallel_queries)] use { @@ -124,7 +125,7 @@ impl<'tcx> QueryJob<'tcx> { while let Some(job) = current_job { cycle.insert(0, job.info.clone()); - if &*job as *const _ == self as *const _ { + if ptr::eq(&*job, self) { // This is the end of the cycle // The span entry we included was for the usage // of the cycle itself, and not part of the cycle @@ -282,7 +283,7 @@ where fn cycle_check<'tcx>(query: Lrc>, span: Span, stack: &mut Vec<(Span, Lrc>)>, - visited: &mut HashSet<*const QueryJob<'tcx>> + visited: &mut HashSet>> ) -> Option>> { if visited.contains(&query.as_ptr()) { return if let Some(p) = stack.iter().position(|q| q.1.as_ptr() == query.as_ptr()) { @@ -321,7 +322,7 @@ fn cycle_check<'tcx>(query: Lrc>, #[cfg(parallel_queries)] fn connected_to_root<'tcx>( query: Lrc>, - visited: &mut HashSet<*const QueryJob<'tcx>> + visited: &mut HashSet>> ) -> bool { // We already visited this or we're deliberately ignoring it if visited.contains(&query.as_ptr()) { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index b386f887d77..ef0d57c7b7c 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -56,29 +56,30 @@ extern crate rustc_cratesio_shim; pub use rustc_serialize::hex::ToHex; -pub mod array_vec; pub mod accumulate_vec; -pub mod small_vec; +pub mod array_vec; pub mod base_n; pub mod bitslice; pub mod bitvec; +pub mod flock; +pub mod fx; +pub mod graph; pub mod indexed_set; pub mod indexed_vec; pub mod obligation_forest; +pub mod owning_ref; +pub mod ptr_key; pub mod sip128; +pub mod small_vec; pub mod snapshot_map; pub use ena::snapshot_vec; +pub mod sorted_map; pub mod stable_hasher; -pub mod transitive_relation; -pub use ena::unify; -pub mod fx; -pub mod tuple_slice; -pub mod graph; -pub mod flock; pub mod sync; -pub mod owning_ref; pub mod tiny_list; -pub mod sorted_map; +pub mod transitive_relation; +pub mod tuple_slice; +pub use ena::unify; pub mod work_queue; pub struct OnDrop(pub F); diff --git a/src/librustc_data_structures/ptr_key.rs b/src/librustc_data_structures/ptr_key.rs new file mode 100644 index 00000000000..6835dab38df --- /dev/null +++ b/src/librustc_data_structures/ptr_key.rs @@ -0,0 +1,45 @@ +// Copyright 2018 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. + +use std::{hash, ptr}; +use std::ops::Deref; + +/// A wrapper around reference that compares and hashes like a pointer. +/// Can be used as a key in sets/maps indexed by pointers to avoid `unsafe`. +#[derive(Debug)] +pub struct PtrKey<'a, T: 'a>(pub &'a T); + +impl<'a, T> Clone for PtrKey<'a, T> { + fn clone(&self) -> Self { *self } +} + +impl<'a, T> Copy for PtrKey<'a, T> {} + +impl<'a, T> PartialEq for PtrKey<'a, T> { + fn eq(&self, rhs: &Self) -> bool { + ptr::eq(self.0, rhs.0) + } +} + +impl<'a, T> Eq for PtrKey<'a, T> {} + +impl<'a, T> hash::Hash for PtrKey<'a, T> { + fn hash(&self, hasher: &mut H) { + (self.0 as *const T).hash(hasher) + } +} + +impl<'a, T> Deref for PtrKey<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0 + } +} diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c242b9c7f2f..97b9a385287 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -17,6 +17,7 @@ use Resolver; use {names_to_string, module_to_string}; use {resolve_error, ResolutionError}; +use rustc_data_structures::ptr_key::PtrKey; use rustc::ty; use rustc::lint::builtin::BuiltinLintDiagnostics; use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE}; @@ -33,7 +34,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; use std::cell::{Cell, RefCell}; -use std::mem; +use std::{mem, ptr}; /// Contains data for specific types of import directives. #[derive(Clone, Debug)] @@ -105,8 +106,8 @@ impl<'a> ImportDirective<'a> { /// Records information about the resolution of a name in a namespace of a module. pub struct NameResolution<'a> { /// Single imports that may define the name in the namespace. - /// Import directives are arena-allocated, so it's ok to use pointers as keys, they are stable. - single_imports: FxHashSet<*const ImportDirective<'a>>, + /// Import directives are arena-allocated, so it's ok to use pointers as keys. + single_imports: FxHashSet>>, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option<&'a NameBinding<'a>>, shadowed_glob: Option<&'a NameBinding<'a>>, @@ -192,7 +193,6 @@ impl<'a> Resolver<'a> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. for single_import in &resolution.single_imports { - let single_import = unsafe { &**single_import }; if !self.is_accessible(single_import.vis.get()) { continue; } @@ -291,7 +291,7 @@ impl<'a> Resolver<'a> { SingleImport { target, type_ns_only, .. } => { self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); - resolution.single_imports.insert(directive); + resolution.single_imports.insert(PtrKey(directive)); }); } // We don't add prelude imports to the globs since they only affect lexical scopes, @@ -398,7 +398,7 @@ impl<'a> Resolver<'a> { _ if old_binding.is_some() => return t, None => return t, Some(binding) => match old_binding { - Some(old_binding) if old_binding as *const _ == binding as *const _ => return t, + Some(old_binding) if ptr::eq(old_binding, binding) => return t, _ => (binding, t), } } @@ -583,7 +583,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Err(Undetermined) => indeterminate = true, Err(Determined) => { this.update_resolution(parent, target, ns, |_, resolution| { - resolution.single_imports.remove(&(directive as *const _)); + resolution.single_imports.remove(&PtrKey(directive)); }); } Ok(binding) if !binding.is_importable() => { @@ -916,7 +916,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let mut reexports = Vec::new(); let mut exported_macro_names = FxHashMap(); - if module as *const _ == self.graph_root as *const _ { + if ptr::eq(module, self.graph_root) { let macro_exports = mem::replace(&mut self.macro_exports, Vec::new()); for export in macro_exports.into_iter().rev() { if let Some(later_span) = exported_macro_names.insert(export.ident.modern(), -- cgit 1.4.1-3-g733a5 From 86d0e9e1c765f434cc31933a970d1c1c1cfebea7 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 24 Jul 2018 15:29:31 +0200 Subject: Simplify a few functions in rustc_data_structures --- src/librustc_data_structures/accumulate_vec.rs | 5 ++--- src/librustc_data_structures/bitslice.rs | 3 +-- src/librustc_data_structures/small_vec.rs | 8 ++------ 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index 2e8cca3f4f9..9423e6b3256 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -224,7 +224,7 @@ impl Encodable for AccumulateVec fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { - try!(s.emit_seq_elt(i, |s| e.encode(s))); + s.emit_seq_elt(i, |s| e.encode(s))?; } Ok(()) }) @@ -236,8 +236,7 @@ impl Decodable for AccumulateVec A::Element: Decodable { fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { - Ok(try!((0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect())) + (0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect() }) } } - diff --git a/src/librustc_data_structures/bitslice.rs b/src/librustc_data_structures/bitslice.rs index 79435aa3987..b8f191c2f57 100644 --- a/src/librustc_data_structures/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -95,8 +95,7 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String { assert!(mask <= 0xFF); let byte = v & mask; - result.push(sep); - result.push_str(&format!("{:02x}", byte)); + result.push_str(&format!("{}{:02x}", sep, byte)); if remain <= 8 { break; } v >>= 8; diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index 83eb54fade1..4a72ab57fcc 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -197,7 +197,7 @@ impl Encodable for SmallVec fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { - try!(s.emit_seq_elt(i, |s| e.encode(s))); + s.emit_seq_elt(i, |s| e.encode(s))?; } Ok(()) }) @@ -209,11 +209,7 @@ impl Decodable for SmallVec A::Element: Decodable { fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { - let mut vec = SmallVec::with_capacity(len); - for i in 0..len { - vec.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); - } - Ok(vec) + (0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect() }) } } -- cgit 1.4.1-3-g733a5 From a54401ebccc5497497b669a1c48fabdf7351d7b2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 22 Jul 2018 17:20:48 +0300 Subject: implement `Step` for `Idx` types This way, we can iterate over a `Range` where `T: Idx` --- src/librustc/lib.rs | 1 + src/librustc_data_structures/indexed_vec.rs | 29 +++++++++++++++++++++++++++++ src/librustc_mir/lib.rs | 1 + 3 files changed, 31 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c72952efc61..d709a4debd1 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -69,6 +69,7 @@ #![feature(trusted_len)] #![feature(vec_remove_item)] #![feature(catch_expr)] +#![feature(step_trait)] #![feature(integer_atomics)] #![feature(test)] #![feature(in_band_lifetimes)] diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index e7a75c149cc..08c518d5ba6 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -89,6 +89,35 @@ macro_rules! newtype_index { } } + impl ::std::iter::Step for $type { + fn steps_between(start: &Self, end: &Self) -> Option { + ::steps_between( + &Idx::index(*start), + &Idx::index(*end), + ) + } + + fn replace_one(&mut self) -> Self { + ::std::mem::replace(self, Self::new(1)) + } + + fn replace_zero(&mut self) -> Self { + ::std::mem::replace(self, Self::new(0)) + } + + fn add_one(&self) -> Self { + Self::new(Idx::index(*self) + 1) + } + + fn sub_one(&self) -> Self { + Self::new(Idx::index(*self) - 1) + } + + fn add_usize(&self, u: usize) -> Option { + Idx::index(*self).checked_add(u).map(Self::new) + } + } + newtype_index!( @handle_debug @derives [$($derives,)*] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index d58affbae75..6483b9b3c68 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -36,6 +36,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(specialization)] #![feature(try_trait)] #![feature(unicode_internals)] +#![feature(step_trait)] #![recursion_limit="256"] -- cgit 1.4.1-3-g733a5 From e098985939a1ac5baef4314aee44efc9dbf1b820 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Fri, 13 Jul 2018 14:12:58 +0900 Subject: Deny bare_trait_objects globally --- src/bootstrap/bin/rustc.rs | 3 ++- src/bootstrap/check.rs | 3 ++- src/bootstrap/doc.rs | 1 + src/bootstrap/test.rs | 9 ++++++--- src/bootstrap/tool.rs | 30 +++++++++++++++++++++++------- src/build_helper/lib.rs | 2 -- src/liballoc/lib.rs | 1 - src/liballoc_jemalloc/lib.rs | 1 - src/liballoc_system/lib.rs | 1 - src/libarena/lib.rs | 1 - src/libcore/lib.rs | 1 - src/libfmt_macros/lib.rs | 2 -- src/libgraphviz/lib.rs | 2 -- src/libpanic_abort/lib.rs | 1 - src/libpanic_unwind/lib.rs | 1 - src/libproc_macro/lib.rs | 1 - src/libprofiler_builtins/lib.rs | 1 - src/librustc/lib.rs | 2 -- src/librustc_allocator/lib.rs | 1 - src/librustc_apfloat/lib.rs | 2 -- src/librustc_asan/lib.rs | 2 -- src/librustc_borrowck/lib.rs | 1 - src/librustc_codegen_llvm/lib.rs | 1 - src/librustc_codegen_utils/lib.rs | 1 - src/librustc_data_structures/lib.rs | 2 -- src/librustc_driver/lib.rs | 2 -- src/librustc_errors/lib.rs | 2 -- src/librustc_incremental/lib.rs | 2 -- src/librustc_lint/lib.rs | 2 -- src/librustc_llvm/lib.rs | 1 - src/librustc_lsan/lib.rs | 2 -- src/librustc_metadata/lib.rs | 2 -- src/librustc_mir/lib.rs | 2 -- src/librustc_msan/lib.rs | 2 -- src/librustc_passes/lib.rs | 2 -- src/librustc_platform_intrinsics/lib.rs | 1 - src/librustc_plugin/lib.rs | 2 -- src/librustc_privacy/lib.rs | 2 -- src/librustc_resolve/lib.rs | 2 -- src/librustc_save_analysis/lib.rs | 1 - src/librustc_target/lib.rs | 2 -- src/librustc_traits/lib.rs | 2 -- src/librustc_tsan/lib.rs | 2 -- src/librustc_typeck/lib.rs | 1 - src/libserialize/lib.rs | 2 -- src/libstd/lib.rs | 1 - src/libsyntax/lib.rs | 2 -- src/libsyntax_ext/lib.rs | 2 -- src/libsyntax_pos/lib.rs | 2 -- src/libterm/lib.rs | 1 - src/libtest/lib.rs | 2 -- src/libunwind/lib.rs | 2 -- 52 files changed, 34 insertions(+), 87 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index f2b2f6f1eeb..d31e5382714 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -296,8 +296,9 @@ fn main() { cmd.arg("--color=always"); } - if env::var_os("RUSTC_DENY_WARNINGS").is_some() { + if env::var_os("RUSTC_DENY_WARNINGS").is_some() && env::var_os("RUSTC_EXT_TOOL").is_none() { cmd.arg("-Dwarnings"); + cmd.arg("-Dbare_trait_objects"); } if verbose > 1 { diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 39c5c832831..dd2a64402b4 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -222,7 +222,8 @@ impl Step for Rustdoc { Mode::ToolRustc, target, "check", - "src/tools/rustdoc"); + "src/tools/rustdoc", + false); let _folder = builder.fold_output(|| format!("stage{}-rustdoc", compiler.stage)); println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f71cb119b77..913b8162a44 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -814,6 +814,7 @@ impl Step for Rustdoc { target, "doc", "src/tools/rustdoc", + false ); cargo.env("RUSTDOCFLAGS", "--document-private-items"); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 639c96bc208..3bcebd08b1e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -286,7 +286,8 @@ impl Step for Rls { Mode::ToolRustc, host, "test", - "src/tools/rls"); + "src/tools/rls", + true); // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); @@ -341,7 +342,8 @@ impl Step for Rustfmt { Mode::ToolRustc, host, "test", - "src/tools/rustfmt"); + "src/tools/rustfmt", + true); // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); @@ -1739,7 +1741,8 @@ impl Step for CrateRustdoc { Mode::ToolRustc, target, test_kind.subcommand(), - "src/tools/rustdoc"); + "src/tools/rustdoc", + false); if test_kind.subcommand() == "test" && !builder.fail_fast { cargo.arg("--no-fail-fast"); } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 0969e5abe07..745733e4d4c 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -115,7 +115,15 @@ impl Step for ToolBuild { _ => panic!("unexpected Mode for tool build") } - let mut cargo = prepare_tool_cargo(builder, compiler, self.mode, target, "build", path); + let mut cargo = prepare_tool_cargo( + builder, + compiler, + self.mode, + target, + "build", + path, + is_ext_tool, + ); cargo.arg("--features").arg(self.extra_features.join(" ")); let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); @@ -238,6 +246,7 @@ pub fn prepare_tool_cargo( target: Interned, command: &'static str, path: &'static str, + is_ext_tool: bool, ) -> Command { let mut cargo = builder.cargo(compiler, mode, target, command); let dir = builder.src.join(path); @@ -247,6 +256,10 @@ pub fn prepare_tool_cargo( // stages and such and it's just easier if they're not dynamically linked. cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + if is_ext_tool { + cargo.env("RUSTC_EXT_TOOL", "1"); + } + if let Some(dir) = builder.openssl_install_dir(target) { cargo.env("OPENSSL_STATIC", "1"); cargo.env("OPENSSL_DIR", dir); @@ -449,12 +462,15 @@ impl Step for Rustdoc { target: builder.config.build, }); - let mut cargo = prepare_tool_cargo(builder, - build_compiler, - Mode::ToolRustc, - target, - "build", - "src/tools/rustdoc"); + let mut cargo = prepare_tool_cargo( + builder, + build_compiler, + Mode::ToolRustc, + target, + "build", + "src/tools/rustdoc", + false, + ); // Most tools don't get debuginfo, but rustdoc should. cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string()) diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 00e5dee256e..1cbb8e49bfa 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - use std::fs::File; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 63cf01a0fac..ef619527e06 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -72,7 +72,6 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] #![needs_allocator] -#![deny(bare_trait_objects)] #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 413b212281b..b3b20715511 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![allow(unused_attributes)] -#![deny(bare_trait_objects)] #![unstable(feature = "alloc_jemalloc", reason = "implementation detail of std, does not provide any public API", issue = "0")] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index c6c0abefbab..64348e05de7 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![allow(unused_attributes)] -#![deny(bare_trait_objects)] #![unstable(feature = "alloc_system", reason = "this library is unlikely to be stabilized in its current \ form or name", diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 6f692923c85..0f4a5d16e17 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -30,7 +30,6 @@ #![cfg_attr(test, feature(test))] #![allow(deprecated)] -#![deny(bare_trait_objects)] extern crate alloc; extern crate rustc_data_structures; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ae0469bfa04..72074e1dbce 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -70,7 +70,6 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] #![no_core] -#![deny(bare_trait_objects)] #![deny(missing_docs)] #![deny(missing_debug_implementations)] diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 9952e5f64d6..62e0ffb8b74 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -14,8 +14,6 @@ //! Parsing does not happen at runtime: structures of `std::fmt::rt` are //! generated instead. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 9e71ed4063e..158d0101515 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -283,8 +283,6 @@ //! //! * [DOT language](http://www.graphviz.org/doc/info/lang.html) -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 02ab28507d7..392bf17968f 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -21,7 +21,6 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![panic_runtime] #![allow(unused_features)] -#![deny(bare_trait_objects)] #![feature(core_intrinsics)] #![feature(libc)] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index f8cd29fc086..5c320bb369e 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -22,7 +22,6 @@ //! More documentation about each implementation can be found in the respective //! module. -#![deny(bare_trait_objects)] #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 61da9db76f6..bf6e4a3aaa4 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -22,7 +22,6 @@ //! See [the book](../book/first-edition/procedural-macros.html) for more. #![stable(feature = "proc_macro_lib", since = "1.15.0")] -#![deny(bare_trait_objects)] #![deny(missing_docs)] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", diff --git a/src/libprofiler_builtins/lib.rs b/src/libprofiler_builtins/lib.rs index 3d91505cd77..6d0d6d115b7 100644 --- a/src/libprofiler_builtins/lib.rs +++ b/src/libprofiler_builtins/lib.rs @@ -15,5 +15,4 @@ reason = "internal implementation detail of rustc right now", issue = "0")] #![allow(unused_features)] -#![deny(bare_trait_objects)] #![feature(staged_api)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c72952efc61..8050522d066 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -36,8 +36,6 @@ //! //! This API is completely unstable and subject to change. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 1227936ce96..b217d3665a2 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] #![feature(rustc_private)] #[macro_use] extern crate log; diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index c7cd958016d..08438805a70 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -40,8 +40,6 @@ //! //! This API is completely unstable and subject to change. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index 7bd1e98f85d..0c78fd74a23 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![sanitizer_runtime] #![feature(alloc_system)] #![feature(sanitizer_runtime)] diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index d583a32c431..a5a20af0e4e 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -13,7 +13,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(non_camel_case_types)] -#![deny(bare_trait_objects)] #![feature(from_ref)] #![feature(quote)] diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 8aa7902021f..90f96c9687b 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -23,7 +23,6 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![deny(bare_trait_objects)] #![feature(libc)] #![feature(quote)] #![feature(range_contains)] diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index e9031007a4e..f59cf5832fc 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -20,7 +20,6 @@ #![feature(box_syntax)] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![deny(bare_trait_objects)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ef0d57c7b7c..a9e582e510e 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -16,8 +16,6 @@ //! //! This API is completely unstable and subject to change. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 2100ceea228..44386d9c3ee 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -14,8 +14,6 @@ //! //! This API is completely unstable and subject to change. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index c0f07645f49..67d2aa4d770 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 2ef88041d33..3839c133a6e 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -10,8 +10,6 @@ //! Support for serializing the dep-graph and reloading it. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 798c289ac2f..78a8c494f48 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -19,8 +19,6 @@ //! //! This API is completely unstable and subject to change. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index c60016cde0d..741758cb954 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -12,7 +12,6 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(dead_code)] -#![deny(bare_trait_objects)] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs index 7bd1e98f85d..0c78fd74a23 100644 --- a/src/librustc_lsan/lib.rs +++ b/src/librustc_lsan/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![sanitizer_runtime] #![feature(alloc_system)] #![feature(sanitizer_runtime)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index d535c1ef903..5cba0387d17 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index d58affbae75..92c0a2b475c 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,8 +14,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ -#![deny(bare_trait_objects)] - #![feature(slice_patterns)] #![feature(slice_sort_by_cached_key)] #![feature(from_ref)] diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs index 7bd1e98f85d..0c78fd74a23 100644 --- a/src/librustc_msan/lib.rs +++ b/src/librustc_msan/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![sanitizer_runtime] #![feature(alloc_system)] #![feature(sanitizer_runtime)] diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 15d7c0fdaa3..41f1e782965 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -14,8 +14,6 @@ //! //! This API is completely unstable and subject to change. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 92e83fd70fa..b57debdd994 100644 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -9,7 +9,6 @@ // except according to those terms. #![allow(bad_style)] -#![deny(bare_trait_objects)] pub struct Intrinsic { pub inputs: &'static [&'static Type], diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index b2c492f204f..348aa6a7cef 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -60,8 +60,6 @@ //! See the [`plugin` feature](../unstable-book/language-features/plugin.html) of //! the Unstable Book for more examples. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 7b13c98b31d..405952065da 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 765016fdc4a..8130c4e8326 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index c84f194f023..a250d4a3598 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -13,7 +13,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![deny(bare_trait_objects)] #![recursion_limit="256"] diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index e611d26da56..8f491157439 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -21,8 +21,6 @@ //! one that doesn't; the one that doesn't might get decent parallel //! build speedups. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 2a4cacb5623..d17cf35f181 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -11,8 +11,6 @@ //! New recursive solver modeled on Chalk's recursive solver. Most of //! the guts are broken up into modules; see the comments in those modules. -#![deny(bare_trait_objects)] - #![feature(crate_in_paths)] #![feature(crate_visibility_modifier)] #![feature(extern_prelude)] diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs index 7bd1e98f85d..0c78fd74a23 100644 --- a/src/librustc_tsan/lib.rs +++ b/src/librustc_tsan/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![sanitizer_runtime] #![feature(alloc_system)] #![feature(sanitizer_runtime)] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e343fb1a57b..6bf1ec8f697 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -70,7 +70,6 @@ This API is completely unstable and subject to change. html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(non_camel_case_types)] -#![deny(bare_trait_objects)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 7c1bb69434d..a5f4b32b329 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -14,8 +14,6 @@ Core encoding and decoding interfaces. */ -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0396ba362bd..3c01de2e997 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -221,7 +221,6 @@ // Don't link to std. We are std. #![no_std] -#![deny(bare_trait_objects)] #![deny(missing_docs)] #![deny(missing_debug_implementations)] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d241ae1d442..60de94821bb 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -14,8 +14,6 @@ //! //! This API is completely unstable and subject to change. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index ff76e788b3c..f0d33835cd0 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -10,8 +10,6 @@ //! Syntax extensions in the Rust compiler. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index cc09a944e4c..61af70af47d 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -14,8 +14,6 @@ //! //! This API is completely unstable and subject to change. -#![deny(bare_trait_objects)] - #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index 6b115770237..cf92ce27ee5 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -45,7 +45,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] -#![deny(bare_trait_objects)] #![deny(missing_docs)] #![cfg_attr(windows, feature(libc))] diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 6b547dff912..76206e2c10d 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -27,8 +27,6 @@ // this crate, which relies on this attribute (rather than the value of `--crate-name` passed by // cargo) to detect this crate. -#![deny(bare_trait_objects)] - #![crate_name = "test"] #![unstable(feature = "test", issue = "27812")] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index ea5eee3cc7d..2b3c19c067e 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bare_trait_objects)] - #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] -- cgit 1.4.1-3-g733a5 From 145155dc96757002c7b2e9de8489416e2fdbbd57 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 22 Jul 2018 19:23:39 +0300 Subject: parameterize `BitVector` and `BitMatrix` by their index types --- src/librustc/mir/traversal.rs | 13 ++-- .../debuginfo/create_scope_map.rs | 6 +- src/librustc_codegen_llvm/mir/analyze.rs | 6 +- src/librustc_codegen_llvm/mir/mod.rs | 8 +- src/librustc_data_structures/bitvec.rs | 89 ++++++++++++---------- .../graph/implementation/mod.rs | 2 +- src/librustc_data_structures/indexed_vec.rs | 10 ++- .../transitive_relation.rs | 8 +- .../borrow_check/nll/region_infer/values.rs | 4 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 2 +- src/librustc_mir/transform/generator.rs | 8 +- src/librustc_mir/transform/qualify_consts.rs | 6 +- .../transform/remove_noop_landing_pads.rs | 18 +++-- src/librustc_mir/transform/simplify.rs | 31 ++++---- 16 files changed, 119 insertions(+), 96 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 92888ed99e4..87ba3420eec 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -9,7 +9,6 @@ // except according to those terms. use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::indexed_vec::Idx; use super::*; @@ -33,7 +32,7 @@ use super::*; #[derive(Clone)] pub struct Preorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, - visited: BitVector, + visited: BitVector, worklist: Vec, } @@ -58,7 +57,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { while let Some(idx) = self.worklist.pop() { - if !self.visited.insert(idx.index()) { + if !self.visited.insert(idx) { continue; } @@ -107,7 +106,7 @@ impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {} /// A Postorder traversal of this graph is `D B C A` or `D C B A` pub struct Postorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, - visited: BitVector, + visited: BitVector, visit_stack: Vec<(BasicBlock, Successors<'a>)> } @@ -123,7 +122,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { let data = &po.mir[root]; if let Some(ref term) = data.terminator { - po.visited.insert(root.index()); + po.visited.insert(root); po.visit_stack.push((root, term.successors())); po.traverse_successor(); } @@ -190,8 +189,8 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { break; }; - if self.visited.insert(bb.index()) { - if let Some(ref term) = self.mir[bb].terminator { + if self.visited.insert(bb) { + if let Some(term) = &self.mir[bb].terminator { self.visit_stack.push((bb, term.successors())); } } diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index 9ced0f5f4ec..fcde7f9bbc3 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -65,7 +65,7 @@ pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebu let mut has_variables = BitVector::new(mir.source_scopes.len()); for var in mir.vars_iter() { let decl = &mir.local_decls[var]; - has_variables.insert(decl.visibility_scope.index()); + has_variables.insert(decl.visibility_scope); } // Instantiate all scopes. @@ -79,7 +79,7 @@ pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebu fn make_mir_scope(cx: &CodegenCx, mir: &Mir, - has_variables: &BitVector, + has_variables: &BitVector, debug_context: &FunctionDebugContextData, scope: SourceScope, scopes: &mut IndexVec) { @@ -102,7 +102,7 @@ fn make_mir_scope(cx: &CodegenCx, return; }; - if !has_variables.contains(scope.index()) { + if !has_variables.contains(scope) { // Do not create a DIScope if there are no variables // defined in this MIR Scope, to avoid debuginfo bloat. diff --git a/src/librustc_codegen_llvm/mir/analyze.rs b/src/librustc_codegen_llvm/mir/analyze.rs index efd829c283f..e105baba8aa 100644 --- a/src/librustc_codegen_llvm/mir/analyze.rs +++ b/src/librustc_codegen_llvm/mir/analyze.rs @@ -22,7 +22,7 @@ use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; use super::FunctionCx; -pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { +pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { let mir = fx.mir; let mut analyzer = LocalAnalyzer::new(fx); @@ -54,7 +54,7 @@ pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> { fx: &'mir FunctionCx<'a, 'tcx>, dominators: Dominators, - non_ssa_locals: BitVector, + non_ssa_locals: BitVector, // The location of the first visited direct assignment to each // local, or an invalid location (out of bounds `block` index). first_assignment: IndexVec @@ -90,7 +90,7 @@ impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> { fn not_ssa(&mut self, local: mir::Local) { debug!("marking {:?} as non-SSA", local); - self.non_ssa_locals.insert(local.index()); + self.non_ssa_locals.insert(local); } fn assign(&mut self, local: mir::Local, location: Location) { diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs index 608539dd3fa..312939408c6 100644 --- a/src/librustc_codegen_llvm/mir/mod.rs +++ b/src/librustc_codegen_llvm/mir/mod.rs @@ -268,7 +268,7 @@ pub fn codegen_mir<'a, 'tcx: 'a>( let debug_scope = fx.scopes[decl.visibility_scope]; let dbg = debug_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo; - if !memory_locals.contains(local.index()) && !dbg { + if !memory_locals.contains(local) && !dbg { debug!("alloc: {:?} ({}) -> operand", local, name); return LocalRef::new_operand(bx.cx, layout); } @@ -291,7 +291,7 @@ pub fn codegen_mir<'a, 'tcx: 'a>( debug!("alloc: {:?} (return place) -> place", local); let llretptr = llvm::get_param(llfn, 0); LocalRef::Place(PlaceRef::new_sized(llretptr, layout, layout.align)) - } else if memory_locals.contains(local.index()) { + } else if memory_locals.contains(local) { debug!("alloc: {:?} -> place", local); LocalRef::Place(PlaceRef::alloca(&bx, layout, &format!("{:?}", local))) } else { @@ -415,7 +415,7 @@ fn create_funclets<'a, 'tcx>( fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, fx: &FunctionCx<'a, 'tcx>, scopes: &IndexVec, - memory_locals: &BitVector) + memory_locals: &BitVector) -> Vec> { let mir = fx.mir; let tcx = bx.tcx(); @@ -487,7 +487,7 @@ fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, llarg_idx += 1; } - if arg_scope.is_none() && !memory_locals.contains(local.index()) { + if arg_scope.is_none() && !memory_locals.contains(local) { // We don't have to cast or keep the argument in the alloca. // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead // of putting everything in allocas just so we can use llvm.dbg.declare. diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index ee903e49642..dec10416bcb 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -17,16 +17,18 @@ const WORD_BITS: usize = 128; /// A very simple BitVector type. #[derive(Clone, Debug, PartialEq)] -pub struct BitVector { +pub struct BitVector { data: Vec, + marker: PhantomData, } -impl BitVector { +impl BitVector { #[inline] - pub fn new(num_bits: usize) -> BitVector { + pub fn new(num_bits: usize) -> BitVector { let num_words = words(num_bits); BitVector { data: vec![0; num_words], + marker: PhantomData, } } @@ -42,14 +44,14 @@ impl BitVector { } #[inline] - pub fn contains(&self, bit: usize) -> bool { + pub fn contains(&self, bit: C) -> bool { let (word, mask) = word_mask(bit); (self.data[word] & mask) != 0 } /// Returns true if the bit has changed. #[inline] - pub fn insert(&mut self, bit: usize) -> bool { + pub fn insert(&mut self, bit: C) -> bool { let (word, mask) = word_mask(bit); let data = &mut self.data[word]; let value = *data; @@ -60,7 +62,7 @@ impl BitVector { /// Returns true if the bit has changed. #[inline] - pub fn remove(&mut self, bit: usize) -> bool { + pub fn remove(&mut self, bit: C) -> bool { let (word, mask) = word_mask(bit); let data = &mut self.data[word]; let value = *data; @@ -70,7 +72,7 @@ impl BitVector { } #[inline] - pub fn merge(&mut self, all: &BitVector) -> bool { + pub fn merge(&mut self, all: &BitVector) -> bool { assert!(self.data.len() == all.data.len()); let mut changed = false; for (i, j) in self.data.iter_mut().zip(&all.data) { @@ -84,7 +86,7 @@ impl BitVector { } #[inline] - pub fn grow(&mut self, num_bits: usize) { + pub fn grow(&mut self, num_bits: C) { let num_words = words(num_bits); if self.data.len() < num_words { self.data.resize(num_words, 0) @@ -93,24 +95,26 @@ impl BitVector { /// Iterates over indexes of set bits in a sorted order #[inline] - pub fn iter<'a>(&'a self) -> BitVectorIter<'a> { + pub fn iter<'a>(&'a self) -> BitVectorIter<'a, C> { BitVectorIter { iter: self.data.iter(), current: 0, idx: 0, + marker: PhantomData, } } } -pub struct BitVectorIter<'a> { +pub struct BitVectorIter<'a, C: Idx> { iter: ::std::slice::Iter<'a, Word>, current: Word, idx: usize, + marker: PhantomData } -impl<'a> Iterator for BitVectorIter<'a> { - type Item = usize; - fn next(&mut self) -> Option { +impl<'a, C: Idx> Iterator for BitVectorIter<'a, C> { + type Item = C; + fn next(&mut self) -> Option { while self.current == 0 { self.current = if let Some(&i) = self.iter.next() { if i == 0 { @@ -128,7 +132,7 @@ impl<'a> Iterator for BitVectorIter<'a> { self.current >>= offset; self.current >>= 1; // shift otherwise overflows for 0b1000_0000_…_0000 self.idx += offset + 1; - return Some(self.idx - 1); + return Some(C::new(self.idx - 1)); } fn size_hint(&self) -> (usize, Option) { @@ -137,8 +141,8 @@ impl<'a> Iterator for BitVectorIter<'a> { } } -impl FromIterator for BitVector { - fn from_iter(iter: I) -> BitVector +impl FromIterator for BitVector { + fn from_iter(iter: I) -> BitVector where I: IntoIterator, { @@ -150,10 +154,10 @@ impl FromIterator for BitVector { let mut bv = BitVector::new(len); for (idx, val) in iter.enumerate() { if idx > len { - bv.grow(idx); + bv.grow(C::new(idx)); } if val { - bv.insert(idx); + bv.insert(C::new(idx)); } } @@ -165,25 +169,28 @@ impl FromIterator for BitVector { /// one gigantic bitvector. In other words, it is as if you have /// `rows` bitvectors, each of length `columns`. #[derive(Clone, Debug)] -pub struct BitMatrix { +pub struct BitMatrix { columns: usize, vector: Vec, + phantom: PhantomData<(R, C)>, } -impl BitMatrix { +impl BitMatrix { /// Create a new `rows x columns` matrix, initially empty. - pub fn new(rows: usize, columns: usize) -> BitMatrix { + pub fn new(rows: usize, columns: usize) -> BitMatrix { // For every element, we need one bit for every other // element. Round up to an even number of words. let words_per_row = words(columns); BitMatrix { columns, vector: vec![0; rows * words_per_row], + phantom: PhantomData, } } /// The range of bits for a given row. - fn range(&self, row: usize) -> (usize, usize) { + fn range(&self, row: R) -> (usize, usize) { + let row = row.index(); let words_per_row = words(self.columns); let start = row * words_per_row; (start, start + words_per_row) @@ -193,7 +200,7 @@ impl BitMatrix { /// `column` to the bitset for `row`. /// /// Returns true if this changed the matrix, and false otherwise. - pub fn add(&mut self, row: usize, column: usize) -> bool { + pub fn add(&mut self, row: R, column: R) -> bool { let (start, _) = self.range(row); let (word, mask) = word_mask(column); let vector = &mut self.vector[..]; @@ -207,7 +214,7 @@ impl BitMatrix { /// the matrix cell at `(row, column)` true? Put yet another way, /// if the matrix represents (transitive) reachability, can /// `row` reach `column`? - pub fn contains(&self, row: usize, column: usize) -> bool { + pub fn contains(&self, row: R, column: R) -> bool { let (start, _) = self.range(row); let (word, mask) = word_mask(column); (self.vector[start + word] & mask) != 0 @@ -217,7 +224,7 @@ impl BitMatrix { /// is an O(n) operation where `n` is the number of elements /// (somewhat independent from the actual size of the /// intersection, in particular). - pub fn intersection(&self, a: usize, b: usize) -> Vec { + pub fn intersection(&self, a: R, b: R) -> Vec { let (a_start, a_end) = self.range(a); let (b_start, b_end) = self.range(b); let mut result = Vec::with_capacity(self.columns); @@ -228,7 +235,7 @@ impl BitMatrix { break; } if v & 0x1 != 0 { - result.push(base * WORD_BITS + bit); + result.push(C::new(base * WORD_BITS + bit)); } v >>= 1; } @@ -243,7 +250,7 @@ impl BitMatrix { /// you have an edge `write -> read`, because in that case /// `write` can reach everything that `read` can (and /// potentially more). - pub fn merge(&mut self, read: usize, write: usize) -> bool { + pub fn merge(&mut self, read: R, write: R) -> bool { let (read_start, read_end) = self.range(read); let (write_start, write_end) = self.range(write); let vector = &mut self.vector[..]; @@ -259,12 +266,13 @@ impl BitMatrix { /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter<'a>(&'a self, row: usize) -> BitVectorIter<'a> { + pub fn iter<'a>(&'a self, row: R) -> BitVectorIter<'a, C> { let (start, end) = self.range(row); BitVectorIter { iter: self.vector[start..end].iter(), current: 0, idx: 0, + marker: PhantomData, } } } @@ -278,8 +286,7 @@ where C: Idx, { columns: usize, - vector: IndexVec, - marker: PhantomData, + vector: IndexVec>, } impl SparseBitMatrix { @@ -288,7 +295,6 @@ impl SparseBitMatrix { Self { columns, vector: IndexVec::new(), - marker: PhantomData, } } @@ -300,7 +306,7 @@ impl SparseBitMatrix { let columns = self.columns; self.vector .ensure_contains_elem(row, || BitVector::new(columns)); - self.vector[row].insert(column.index()) + self.vector[row].insert(column) } /// Do the bits from `row` contain `column`? Put another way, is @@ -308,7 +314,7 @@ impl SparseBitMatrix { /// if the matrix represents (transitive) reachability, can /// `row` reach `column`? pub fn contains(&self, row: R, column: C) -> bool { - self.vector.get(row).map_or(false, |r| r.contains(column.index())) + self.vector.get(row).map_or(false, |r| r.contains(column)) } /// Add the bits from row `read` to the bits from row `write`, @@ -331,7 +337,7 @@ impl SparseBitMatrix { } /// Merge a row, `from`, into the `into` row. - pub fn merge_into(&mut self, into: R, from: &BitVector) -> bool { + pub fn merge_into(&mut self, into: R, from: &BitVector) -> bool { let columns = self.columns; self.vector .ensure_contains_elem(into, || BitVector::new(columns)); @@ -346,22 +352,27 @@ impl SparseBitMatrix { /// Iterates through all the columns set to true in a given row of /// the matrix. pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { - self.vector.get(row).into_iter().flat_map(|r| r.iter().map(|n| C::new(n))) + self.vector.get(row).into_iter().flat_map(|r| r.iter()) } /// Iterates through each row and the accompanying bit set. - pub fn iter_enumerated<'a>(&'a self) -> impl Iterator + 'a { + pub fn iter_enumerated<'a>(&'a self) -> impl Iterator)> + 'a { self.vector.iter_enumerated() } + + pub fn row(&self, row: R) -> Option<&BitVector> { + self.vector.get(row) + } } #[inline] -fn words(elements: usize) -> usize { - (elements + WORD_BITS - 1) / WORD_BITS +fn words(elements: C) -> usize { + (elements.index() + WORD_BITS - 1) / WORD_BITS } #[inline] -fn word_mask(index: usize) -> (usize, Word) { +fn word_mask(index: C) -> (usize, Word) { + let index = index.index(); let word = index / WORD_BITS; let mask = 1 << (index % WORD_BITS); (word, mask) diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs index e2b393071ff..dbfc09116bb 100644 --- a/src/librustc_data_structures/graph/implementation/mod.rs +++ b/src/librustc_data_structures/graph/implementation/mod.rs @@ -348,7 +348,7 @@ where { graph: &'g Graph, stack: Vec, - visited: BitVector, + visited: BitVector, direction: Direction, } diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 08c518d5ba6..c358f2f852e 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -25,7 +25,13 @@ use rustc_serialize as serialize; /// (purpose: avoid mixing indexes for different bitvector domains.) pub trait Idx: Copy + 'static + Ord + Debug + Hash { fn new(idx: usize) -> Self; + fn index(self) -> usize; + + fn increment_by(&mut self, amount: usize) { + let v = self.index() + amount; + *self = Self::new(v); + } } impl Idx for usize { @@ -504,8 +510,8 @@ impl IndexVec { } #[inline] - pub fn swap(&mut self, a: usize, b: usize) { - self.raw.swap(a, b) + pub fn swap(&mut self, a: I, b: I) { + self.raw.swap(a.index(), b.index()) } #[inline] diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 6d63bc4436f..a8124fb7c5b 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -39,7 +39,7 @@ pub struct TransitiveRelation { // are added with new elements. Perhaps better would be to ask the // user for a batch of edges to minimize this effect, but I // already wrote the code this way. :P -nmatsakis - closure: Lock>, + closure: Lock>>, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)] @@ -354,7 +354,7 @@ impl TransitiveRelation { } fn with_closure(&self, op: OP) -> R - where OP: FnOnce(&BitMatrix) -> R + where OP: FnOnce(&BitMatrix) -> R { let mut closure_cell = self.closure.borrow_mut(); let mut closure = closure_cell.take(); @@ -366,7 +366,7 @@ impl TransitiveRelation { result } - fn compute_closure(&self) -> BitMatrix { + fn compute_closure(&self) -> BitMatrix { let mut matrix = BitMatrix::new(self.elements.len(), self.elements.len()); let mut changed = true; @@ -396,7 +396,7 @@ impl TransitiveRelation { /// - Input: `[a, b, x]`. Output: `[a, x]`. /// - Input: `[b, a, x]`. Output: `[b, a, x]`. /// - Input: `[a, x, b, y]`. Output: `[a, x]`. -fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { +fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { let mut i = 0; while i < candidates.len() { let candidate_i = candidates[i]; diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 20b188424f9..4db5267cbd4 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -222,12 +222,12 @@ impl RegionValues { /// Iterates through each row and the accompanying bit set. pub fn iter_enumerated<'a>( &'a self - ) -> impl Iterator + 'a { + ) -> impl Iterator)> + 'a { self.matrix.iter_enumerated() } /// Merge a row, `from`, originating in another `RegionValues` into the `into` row. - pub fn merge_into(&mut self, into: N, from: &BitVector) -> bool { + pub fn merge_into(&mut self, into: N, from: &BitVector) -> bool { self.matrix.merge_into(into, from) } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index f1591535fa1..5de316a6640 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -487,7 +487,7 @@ enum TestKind<'tcx> { // test the branches of enum Switch { adt_def: &'tcx ty::AdtDef, - variants: BitVector, + variants: BitVector, }, // test the branches of enum diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index e2b460f69fd..3ff209c872f 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn add_variants_to_switch<'pat>(&mut self, test_place: &Place<'tcx>, candidate: &Candidate<'pat, 'tcx>, - variants: &mut BitVector) + variants: &mut BitVector) -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 2f983e25acd..5f05783b15c 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -231,7 +231,7 @@ pub struct InliningMap<'tcx> { // Contains one bit per mono item in the `targets` field. That bit // is true if that mono item needs to be inlined into every CGU. - inlines: BitVector, + inlines: BitVector, } impl<'tcx> InliningMap<'tcx> { diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 97467e00385..6a9258fe2c9 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -292,8 +292,10 @@ fn make_generator_state_argument_indirect<'a, 'tcx>( DerefArgVisitor.visit_mir(mir); } -fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>, - mir: &mut Mir<'tcx>) -> Local { +fn replace_result_variable<'tcx>( + ret_ty: Ty<'tcx>, + mir: &mut Mir<'tcx>, +) -> Local { let source_info = source_info(mir); let new_ret = LocalDecl { mutability: Mutability::Mut, @@ -306,7 +308,7 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>, }; let new_ret_local = Local::new(mir.local_decls.len()); mir.local_decls.push(new_ret); - mir.local_decls.swap(0, new_ret_local.index()); + mir.local_decls.swap(RETURN_PLACE, new_ret_local); RenameLocalVisitor { from: RETURN_PLACE, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 4e1129ea7e9..8a12a604ef2 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -116,7 +116,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { param_env: ty::ParamEnv<'tcx>, local_qualif: IndexVec>, qualif: Qualif, - const_fn_arg_vars: BitVector, + const_fn_arg_vars: BitVector, temp_promotion_state: IndexVec, promotion_candidates: Vec } @@ -344,7 +344,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { // Make sure there are no extra unassigned variables. self.qualif = Qualif::NOT_CONST; for index in mir.vars_iter() { - if !self.const_fn_arg_vars.contains(index.index()) { + if !self.const_fn_arg_vars.contains(index) { debug!("unassigned variable {:?}", index); self.assign(&Place::Local(index), Location { block: bb, @@ -1021,7 +1021,7 @@ This does not pose a problem by itself because they can't be accessed directly." // Check the allowed const fn argument forms. if let (Mode::ConstFn, &Place::Local(index)) = (self.mode, dest) { if self.mir.local_kind(index) == LocalKind::Var && - self.const_fn_arg_vars.insert(index.index()) && + self.const_fn_arg_vars.insert(index) && !self.tcx.sess.features_untracked().const_let { // Direct use of an argument is permitted. diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 680b60b9728..a7ef93eaec6 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -11,7 +11,6 @@ use rustc::ty::TyCtxt; use rustc::mir::*; use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::indexed_vec::Idx; use transform::{MirPass, MirSource}; use util::patch::MirPatch; @@ -42,9 +41,12 @@ impl MirPass for RemoveNoopLandingPads { } impl RemoveNoopLandingPads { - fn is_nop_landing_pad(&self, bb: BasicBlock, mir: &Mir, nop_landing_pads: &BitVector) - -> bool - { + fn is_nop_landing_pad( + &self, + bb: BasicBlock, + mir: &Mir, + nop_landing_pads: &BitVector, + ) -> bool { for stmt in &mir[bb].statements { match stmt.kind { StatementKind::ReadForMatch(_) | @@ -79,8 +81,8 @@ impl RemoveNoopLandingPads { TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => { - terminator.successors().all(|succ| { - nop_landing_pads.contains(succ.index()) + terminator.successors().all(|&succ| { + nop_landing_pads.contains(succ) }) }, TerminatorKind::GeneratorDrop | @@ -117,7 +119,7 @@ impl RemoveNoopLandingPads { for bb in postorder { debug!(" processing {:?}", bb); for target in mir[bb].terminator_mut().successors_mut() { - if *target != resume_block && nop_landing_pads.contains(target.index()) { + if *target != resume_block && nop_landing_pads.contains(*target) { debug!(" folding noop jump to {:?} to resume block", target); *target = resume_block; jumps_folded += 1; @@ -138,7 +140,7 @@ impl RemoveNoopLandingPads { let is_nop_landing_pad = self.is_nop_landing_pad(bb, mir, &nop_landing_pads); if is_nop_landing_pad { - nop_landing_pads.insert(bb.index()); + nop_landing_pads.insert(bb); } debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad); } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 7e23a5cb1a8..6b8d5a14893 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -288,15 +288,15 @@ impl MirPass for SimplifyLocals { let mut marker = DeclMarker { locals: BitVector::new(mir.local_decls.len()) }; marker.visit_mir(mir); // Return pointer and arguments are always live - marker.locals.insert(RETURN_PLACE.index()); + marker.locals.insert(RETURN_PLACE); for arg in mir.args_iter() { - marker.locals.insert(arg.index()); + marker.locals.insert(arg); } // We may need to keep dead user variables live for debuginfo. if tcx.sess.opts.debuginfo == FullDebugInfo { for local in mir.vars_iter() { - marker.locals.insert(local.index()); + marker.locals.insert(local); } } @@ -308,35 +308,38 @@ impl MirPass for SimplifyLocals { } /// Construct the mapping while swapping out unused stuff out from the `vec`. -fn make_local_map<'tcx, I: Idx, V>(vec: &mut IndexVec, mask: BitVector) -> Vec { - let mut map: Vec = ::std::iter::repeat(!0).take(vec.len()).collect(); - let mut used = 0; +fn make_local_map<'tcx, V>( + vec: &mut IndexVec, + mask: BitVector, +) -> IndexVec> { + let mut map: IndexVec> = IndexVec::from_elem(None, &*vec); + let mut used = Local::new(0); for alive_index in mask.iter() { - map[alive_index] = used; + map[alive_index] = Some(used); if alive_index != used { vec.swap(alive_index, used); } - used += 1; + used.increment_by(1); } - vec.truncate(used); + vec.truncate(used.index()); map } struct DeclMarker { - pub locals: BitVector, + pub locals: BitVector, } impl<'tcx> Visitor<'tcx> for DeclMarker { fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) { // ignore these altogether, they get removed along with their otherwise unused decls. if ctx != PlaceContext::StorageLive && ctx != PlaceContext::StorageDead { - self.locals.insert(local.index()); + self.locals.insert(*local); } } } struct LocalUpdater { - map: Vec, + map: IndexVec>, } impl<'tcx> MutVisitor<'tcx> for LocalUpdater { @@ -345,7 +348,7 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { data.statements.retain(|stmt| { match stmt.kind { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { - self.map[l.index()] != !0 + self.map[l].is_some() } _ => true } @@ -353,6 +356,6 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { self.super_basic_block_data(block, data); } fn visit_local(&mut self, l: &mut Local, _: PlaceContext<'tcx>, _: Location) { - *l = Local::new(self.map[l.index()]); + *l = self.map[*l].unwrap(); } } -- cgit 1.4.1-3-g733a5 From 3f0fb4f7d849a12bce2996c03214601255bfe82e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 22 Jul 2018 19:46:48 +0300 Subject: split into two matrices --- src/librustc_data_structures/bitvec.rs | 61 ++++ .../borrow_check/nll/region_infer/mod.rs | 18 +- .../borrow_check/nll/region_infer/values.rs | 312 ++++++++++++--------- src/librustc_mir/lib.rs | 1 + 4 files changed, 245 insertions(+), 147 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index dec10416bcb..bc7b8f8df46 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -43,12 +43,27 @@ impl BitVector { self.data.iter().map(|e| e.count_ones() as usize).sum() } + /// True if `self` contains the bit `bit`. #[inline] pub fn contains(&self, bit: C) -> bool { let (word, mask) = word_mask(bit); (self.data[word] & mask) != 0 } + /// True if `self` contains all the bits in `other`. + /// + /// The two vectors must have the same length. + #[inline] + pub fn contains_all(&self, other: &BitVector) -> bool { + assert_eq!(self.data.len(), other.data.len()); + self.data.iter().zip(&other.data).all(|(a, b)| (a & b) == *b) + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.data.iter().all(|a| *a == 0) + } + /// Returns true if the bit has changed. #[inline] pub fn insert(&mut self, bit: C) -> bool { @@ -349,6 +364,10 @@ impl SparseBitMatrix { self.vector.len() } + pub fn rows(&self) -> impl Iterator { + self.vector.indices() + } + /// Iterates through all the columns set to true in a given row of /// the matrix. pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { @@ -522,3 +541,45 @@ fn matrix_iter() { } assert!(iter.next().is_none()); } + +#[test] +fn sparse_matrix_iter() { + let mut matrix = SparseBitMatrix::new(64, 100); + matrix.add(3, 22); + matrix.add(3, 75); + matrix.add(2, 99); + matrix.add(4, 0); + matrix.merge(3, 5); + + let expected = [99]; + let mut iter = expected.iter(); + for i in matrix.iter(2) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [22, 75]; + let mut iter = expected.iter(); + for i in matrix.iter(3) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [0]; + let mut iter = expected.iter(); + for i in matrix.iter(4) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [22, 75]; + let mut iter = expected.iter(); + for i in matrix.iter(5) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); +} diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index a74f4f5539f..3ba95895bfd 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -48,9 +48,6 @@ pub struct RegionInferenceContext<'tcx> { /// from as well as its final inferred value. definitions: IndexVec>, - /// Maps from points/universal-regions to a `RegionElementIndex`. - elements: Rc, - /// The liveness constraints added to each region. For most /// regions, these start out empty and steadily grow, though for /// each universally quantified region R they start out containing @@ -219,14 +216,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut scc_values = RegionValues::new(elements); - for (region, location_set) in liveness_constraints.iter_enumerated() { + for region in liveness_constraints.regions_with_points() { let scc = constraint_sccs.scc(region); - scc_values.merge_into(scc, location_set); + scc_values.merge_row(scc, region, &liveness_constraints); } let mut result = Self { definitions, - elements: elements.clone(), liveness_constraints, constraints, constraint_graph, @@ -273,7 +269,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // For each universally quantified region X: - let elements = self.elements.clone(); let universal_regions = self.universal_regions.clone(); for variable in universal_regions.universal_regions() { // These should be free-region variables. @@ -283,9 +278,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); // Add all nodes in the CFG to liveness constraints - for point_index in elements.all_point_indices() { - self.add_live_element(variable, point_index); - } + let variable_scc = self.constraint_sccs.scc(variable); + self.liveness_constraints.add_all_points(variable); + self.scc_values.add_all_points(variable_scc); // Add `end(X)` into the set for X. self.add_live_element(variable, variable); @@ -782,7 +777,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // now). Therefore, the sup-region outlives the sub-region if, // for each universal region R1 in the sub-region, there // exists some region R2 in the sup-region that outlives R1. - let universal_outlives = self.scc_values + let universal_outlives = self + .scc_values .universal_regions_outlived_by(sub_region_scc) .all(|r1| { self.scc_values diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 4db5267cbd4..8092b773eae 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -10,11 +10,12 @@ use rustc::mir::{BasicBlock, Location, Mir}; use rustc::ty::RegionVid; -use rustc_data_structures::bitvec::{BitVector, SparseBitMatrix}; +use rustc_data_structures::bitvec::SparseBitMatrix; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use std::fmt::Debug; use std::rc::Rc; +use std::ops::Range; /// Maps between the various kinds of elements of a region value to /// the internal indices that w use. @@ -50,90 +51,65 @@ impl RegionValueElements { Self { statements_before_block, - num_universal_regions, num_points, + num_universal_regions, } } - /// Total number of element indices that exist. - crate fn num_elements(&self) -> usize { - self.num_points + self.num_universal_regions - } - - /// Converts an element of a region value into a `RegionElementIndex`. - crate fn index(&self, elem: T) -> RegionElementIndex { - elem.to_element_index(self) + fn point_from_location(&self, location: Location) -> PointIndex { + let Location { + block, + statement_index, + } = location; + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index + statement_index) } - /// Iterates over the `RegionElementIndex` for all points in the CFG. - crate fn all_point_indices<'a>(&'a self) -> impl Iterator + 'a { - (0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions)) + /// Range coverting all point indices. + fn all_points(&self) -> Range { + PointIndex::new(0)..PointIndex::new(self.num_points) } - /// Converts a particular `RegionElementIndex` to the `RegionElement` it represents. - crate fn to_element(&self, i: RegionElementIndex) -> RegionElement { - debug!("to_element(i={:?})", i); - - if let Some(r) = self.to_universal_region(i) { - RegionElement::UniversalRegion(r) - } else { - let point_index = i.index() - self.num_universal_regions; - - // Find the basic block. We have a vector with the - // starting index of the statement in each block. Imagine - // we have statement #22, and we have a vector like: - // - // [0, 10, 20] - // - // In that case, this represents point_index 2 of - // basic block BB2. We know this because BB0 accounts for - // 0..10, BB1 accounts for 11..20, and BB2 accounts for - // 20... - // - // To compute this, we could do a binary search, but - // because I am lazy we instead iterate through to find - // the last point where the "first index" (0, 10, or 20) - // was less than the statement index (22). In our case, this will - // be (BB2, 20). - // - // Nit: we could do a binary search here but I'm too lazy. - let (block, &first_index) = self - .statements_before_block - .iter_enumerated() - .filter(|(_, first_index)| **first_index <= point_index) - .last() - .unwrap(); - - RegionElement::Location(Location { - block, - statement_index: point_index - first_index, - }) - } - } - - /// Converts a particular `RegionElementIndex` to a universal - /// region, if that is what it represents. Returns `None` - /// otherwise. - crate fn to_universal_region(&self, i: RegionElementIndex) -> Option { - if i.index() < self.num_universal_regions { - Some(RegionVid::new(i.index())) - } else { - None + /// Converts a particular `RegionElementIndex` to a location, if + /// that is what it represents. Returns `None` otherwise. + crate fn to_location(&self, i: PointIndex) -> Location { + let point_index = i.index(); + + // Find the basic block. We have a vector with the + // starting index of the statement in each block. Imagine + // we have statement #22, and we have a vector like: + // + // [0, 10, 20] + // + // In that case, this represents point_index 2 of + // basic block BB2. We know this because BB0 accounts for + // 0..10, BB1 accounts for 11..20, and BB2 accounts for + // 20... + // + // To compute this, we could do a binary search, but + // because I am lazy we instead iterate through to find + // the last point where the "first index" (0, 10, or 20) + // was less than the statement index (22). In our case, this will + // be (BB2, 20). + // + // Nit: we could do a binary search here but I'm too lazy. + let (block, &first_index) = self + .statements_before_block + .iter_enumerated() + .filter(|(_, first_index)| **first_index <= point_index) + .last() + .unwrap(); + + Location { + block, + statement_index: point_index - first_index, } } } -/// A newtype for the integers that represent one of the possible -/// elements in a region. These are the rows in the `SparseBitMatrix` that -/// is used to store the values of all regions. They have the following -/// convention: -/// -/// - The first N indices represent free regions (where N = universal_regions.len()). -/// - The remainder represent the points in the CFG (see `point_indices` map). -/// -/// You can convert a `RegionElementIndex` into a `RegionElement` -/// using the `to_region_elem` method. -newtype_index!(RegionElementIndex { DEBUG_FORMAT = "RegionElementIndex({})" }); +/// A single integer representing a `Location` in the MIR control-flow +/// graph. Constructed efficiently from `RegionValueElements`. +newtype_index!(PointIndex { DEBUG_FORMAT = "PointIndex({})" }); /// An individual element in a region value -- the value of a /// particular region variable consists of a set of these elements. @@ -142,36 +118,9 @@ crate enum RegionElement { /// A point in the control-flow graph. Location(Location), - /// An in-scope, universally quantified region (e.g., a lifetime parameter). - UniversalRegion(RegionVid), -} - -crate trait ToElementIndex: Debug + Copy { - fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex; -} - -impl ToElementIndex for Location { - fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex { - let Location { - block, - statement_index, - } = self; - let start_index = elements.statements_before_block[block]; - RegionElementIndex::new(elements.num_universal_regions + start_index + statement_index) - } -} - -impl ToElementIndex for RegionVid { - fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex { - assert!(self.index() < elements.num_universal_regions); - RegionElementIndex::new(self.index()) - } -} - -impl ToElementIndex for RegionElementIndex { - fn to_element_index(self, _elements: &RegionValueElements) -> RegionElementIndex { - self - } + /// A universally quantified region from the root universe (e.g., + /// a lifetime parameter). + RootUniversalRegion(RegionVid), } /// Stores the values for a set of regions. These are stored in a @@ -181,7 +130,8 @@ impl ToElementIndex for RegionElementIndex { #[derive(Clone)] crate struct RegionValues { elements: Rc, - matrix: SparseBitMatrix, + points: SparseBitMatrix, + free_regions: SparseBitMatrix, } impl RegionValues { @@ -191,7 +141,8 @@ impl RegionValues { crate fn new(elements: &Rc) -> Self { Self { elements: elements.clone(), - matrix: SparseBitMatrix::new(elements.num_elements()), + points: SparseBitMatrix::new(elements.num_points), + free_regions: SparseBitMatrix::new(elements.num_universal_regions), } } @@ -202,53 +153,83 @@ impl RegionValues { r: N, elem: impl ToElementIndex, ) -> bool { - let i = self.elements.index(elem); debug!("add(r={:?}, elem={:?})", r, elem); - self.matrix.add(r, i) + elem.add_to_row(self, r) + } + + /// Adds all the control-flow points to the values for `r`. + crate fn add_all_points(&mut self, r: N) { + // FIXME OMG so inefficient. We'll fix later. + for p in self.elements.all_points() { + self.points.add(r, p); + } } /// Add all elements in `r_from` to `r_to` (because e.g. `r_to: /// r_from`). crate fn add_region(&mut self, r_to: N, r_from: N) -> bool { - self.matrix.merge(r_from, r_to) + self.points.merge(r_from, r_to) | self.free_regions.merge(r_from, r_to) + // FIXME universes? } /// True if the region `r` contains the given element. - crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool { - let i = self.elements.index(elem); - self.matrix.contains(r, i) + crate fn contains( + &self, + r: N, + elem: impl ToElementIndex, + ) -> bool { + elem.contained_in_row(self, r) } - /// Iterates through each row and the accompanying bit set. - pub fn iter_enumerated<'a>( - &'a self - ) -> impl Iterator)> + 'a { - self.matrix.iter_enumerated() + /// Iterate through each region that has a value in this set. + crate fn regions_with_points<'a>(&'a self) -> impl Iterator { + self.points.rows() } - /// Merge a row, `from`, originating in another `RegionValues` into the `into` row. - pub fn merge_into(&mut self, into: N, from: &BitVector) -> bool { - self.matrix.merge_into(into, from) + /// `self[to] |= values[from]`, essentially: that is, take all the + /// elements for the region `from` from `values` and add them to + /// the region `to` in `self`. + crate fn merge_row(&mut self, to: N, from: M, values: &RegionValues) { + if let Some(set) = values.points.row(from) { + self.points.merge_into(to, set); + } + + if let Some(set) = values.free_regions.row(from) { + self.free_regions.merge_into(to, set); + } } /// True if `sup_region` contains all the CFG points that /// `sub_region` contains. Ignores universal regions. - crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool { + crate fn contains_points( + &self, + sup_region: N, + sub_region: N, + ) -> bool { // This could be done faster by comparing the bitsets. But I // am lazy. - self.element_indices_contained_in(sub_region) - .skip_while(|&i| self.elements.to_universal_region(i).is_some()) - .all(|e| self.contains(sup_region, e)) + if let Some(sub_row) = self.points.row(sub_region) { + if let Some(sup_row) = self.points.row(sup_region) { + sup_row.contains_all(sub_row) + } else { + // sup row is empty, so sub row must be empty + sub_row.is_empty() + } + } else { + // sub row is empty, always true + true + } } - /// Iterate over the value of the region `r`, yielding up element - /// indices. You may prefer `universal_regions_outlived_by` or - /// `elements_contained_in`. - crate fn element_indices_contained_in<'a>( + /// Returns the locations contained within a given region `r`. + crate fn locations_outlived_by<'a>( &'a self, r: N, - ) -> impl Iterator + 'a { - self.matrix.iter(r).map(move |i| i) + ) -> impl Iterator + 'a { + self.points + .row(r) + .into_iter() + .flat_map(move |set| set.iter().map(move |p| self.elements.to_location(p))) } /// Returns just the universal regions that are contained in a given region's value. @@ -256,10 +237,10 @@ impl RegionValues { &'a self, r: N, ) -> impl Iterator + 'a { - self.element_indices_contained_in(r) - .map(move |i| self.elements.to_universal_region(i)) - .take_while(move |v| v.is_some()) // universal regions are a prefix - .map(move |v| v.unwrap()) + self.free_regions + .row(r) + .into_iter() + .flat_map(|set| set.iter()) } /// Returns all the elements contained in a given region's value. @@ -267,8 +248,15 @@ impl RegionValues { &'a self, r: N, ) -> impl Iterator + 'a { - self.element_indices_contained_in(r) - .map(move |r| self.elements.to_element(r)) + let points_iter = self + .locations_outlived_by(r) + .map(RegionElement::Location); + + let free_regions_iter = self + .universal_regions_outlived_by(r) + .map(RegionElement::RootUniversalRegion); + + points_iter.chain(free_regions_iter) } /// Returns a "pretty" string value of the region. Meant for debugging. @@ -306,7 +294,7 @@ impl RegionValues { open_location = Some((l, l)); } - RegionElement::UniversalRegion(fr) => { + RegionElement::RootUniversalRegion(fr) => { if let Some((location1, location2)) = open_location { push_sep(&mut result); Self::push_location_range(&mut result, location1, location2); @@ -341,3 +329,55 @@ impl RegionValues { } } } + +crate trait ToElementIndex: Debug + Copy { + fn add_to_row( + self, + values: &mut RegionValues, + row: N, + ) -> bool; + + fn contained_in_row( + self, + values: &RegionValues, + row: N, + ) -> bool; +} + +impl ToElementIndex for Location { + fn add_to_row( + self, + values: &mut RegionValues, + row: N, + ) -> bool { + let index = values.elements.point_from_location(self); + values.points.add(row, index) + } + + fn contained_in_row( + self, + values: &RegionValues, + row: N, + ) -> bool { + let index = values.elements.point_from_location(self); + values.points.contains(row, index) + } +} + +impl ToElementIndex for RegionVid { + fn add_to_row( + self, + values: &mut RegionValues, + row: N, + ) -> bool { + values.free_regions.add(row, self) + } + + fn contained_in_row( + self, + values: &RegionValues, + row: N, + ) -> bool { + values.free_regions.contains(row, self) + } +} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 6483b9b3c68..382248c2d15 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -27,6 +27,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(core_intrinsics)] #![feature(decl_macro)] #![feature(fs_read_write)] +#![feature(in_band_lifetimes)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] #![feature(range_contains)] -- cgit 1.4.1-3-g733a5 From 71fef95e765f812f2eada304f1a6be00a814c0e9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Jul 2018 18:13:35 +0300 Subject: SparseBitMatrix: add `ensure_row` helper fn --- src/librustc_data_structures/bitvec.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index bc7b8f8df46..f564f46dd2b 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -313,14 +313,18 @@ impl SparseBitMatrix { } } + fn ensure_row(&mut self, row: R) { + let columns = self.columns; + self.vector + .ensure_contains_elem(row, || BitVector::new(columns)); + } + /// Sets the cell at `(row, column)` to true. Put another way, insert /// `column` to the bitset for `row`. /// /// Returns true if this changed the matrix, and false otherwise. pub fn add(&mut self, row: R, column: C) -> bool { - let columns = self.columns; - self.vector - .ensure_contains_elem(row, || BitVector::new(columns)); + self.ensure_row(row); self.vector[row].insert(column) } @@ -344,18 +348,14 @@ impl SparseBitMatrix { return false; } - let columns = self.columns; - self.vector - .ensure_contains_elem(write, || BitVector::new(columns)); + self.ensure_row(write); let (bitvec_read, bitvec_write) = self.vector.pick2_mut(read, write); bitvec_write.merge(bitvec_read) } /// Merge a row, `from`, into the `into` row. pub fn merge_into(&mut self, into: R, from: &BitVector) -> bool { - let columns = self.columns; - self.vector - .ensure_contains_elem(into, || BitVector::new(columns)); + self.ensure_row(into); self.vector[into].merge(from) } -- cgit 1.4.1-3-g733a5 From 7c74518f504737b6a35a892156cf42e578073eac Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Jul 2018 18:13:54 +0300 Subject: SparseBitMatrix: add `insert_all` and `add_all` methods --- src/librustc_data_structures/bitvec.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index f564f46dd2b..245f5d61099 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -75,6 +75,13 @@ impl BitVector { new_value != value } + /// Sets all bits to true. + pub fn insert_all(&mut self) { + for data in &mut self.data { + *data = u128::max_value(); + } + } + /// Returns true if the bit has changed. #[inline] pub fn remove(&mut self, bit: C) -> bool { @@ -359,6 +366,12 @@ impl SparseBitMatrix { self.vector[into].merge(from) } + /// Add all bits to the given row. + pub fn add_all(&mut self, row: R) { + self.ensure_row(row); + self.vector[row].insert_all(); + } + /// Number of elements in the matrix. pub fn len(&self) -> usize { self.vector.len() -- cgit 1.4.1-3-g733a5 From 5c603e8752874aab0231eecfce5776605f23e05f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 16:32:13 +0300 Subject: convert tests of `BitVector` to use `BitVector` --- src/librustc_data_structures/bitvec.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 245f5d61099..30a0286bc21 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -412,7 +412,7 @@ fn word_mask(index: C) -> (usize, Word) { #[test] fn bitvec_iter_works() { - let mut bitvec = BitVector::new(100); + let mut bitvec: BitVector = BitVector::new(100); bitvec.insert(1); bitvec.insert(10); bitvec.insert(19); @@ -430,7 +430,7 @@ fn bitvec_iter_works() { #[test] fn bitvec_iter_works_2() { - let mut bitvec = BitVector::new(319); + let mut bitvec: BitVector = BitVector::new(319); bitvec.insert(0); bitvec.insert(127); bitvec.insert(191); @@ -441,8 +441,8 @@ fn bitvec_iter_works_2() { #[test] fn union_two_vecs() { - let mut vec1 = BitVector::new(65); - let mut vec2 = BitVector::new(65); + let mut vec1: BitVector = BitVector::new(65); + let mut vec2: BitVector = BitVector::new(65); assert!(vec1.insert(3)); assert!(!vec1.insert(3)); assert!(vec2.insert(5)); @@ -458,7 +458,7 @@ fn union_two_vecs() { #[test] fn grow() { - let mut vec1 = BitVector::new(65); + let mut vec1: BitVector = BitVector::new(65); for index in 0..65 { assert!(vec1.insert(index)); assert!(!vec1.insert(index)); -- cgit 1.4.1-3-g733a5 From d376a6bc5d0180758ea2952aed2d374aaa8b093c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 16:33:15 +0300 Subject: add type parameters to `BitMatrix` and `SparseBitMatrix` unit tests --- src/librustc_data_structures/bitvec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 30a0286bc21..9004af35aef 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -484,7 +484,7 @@ fn grow() { #[test] fn matrix_intersection() { - let mut vec1 = BitMatrix::new(200, 200); + let mut vec1: BitMatrix = BitMatrix::new(200, 200); // (*) Elements reachable from both 2 and 65. @@ -515,7 +515,7 @@ fn matrix_intersection() { #[test] fn matrix_iter() { - let mut matrix = BitMatrix::new(64, 100); + let mut matrix: BitMatrix = BitMatrix::new(64, 100); matrix.add(3, 22); matrix.add(3, 75); matrix.add(2, 99); @@ -557,7 +557,7 @@ fn matrix_iter() { #[test] fn sparse_matrix_iter() { - let mut matrix = SparseBitMatrix::new(64, 100); + let mut matrix: SparseBitMatrix = SparseBitMatrix::new(64, 100); matrix.add(3, 22); matrix.add(3, 75); matrix.add(2, 99); -- cgit 1.4.1-3-g733a5 From ce576ac259e98138f6e2f19e40a632c279c6a516 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 16:33:52 +0300 Subject: fix `sparse_matrix_iter` unit test --- src/librustc_data_structures/bitvec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 9004af35aef..04d6cb5e2a6 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -557,7 +557,7 @@ fn matrix_iter() { #[test] fn sparse_matrix_iter() { - let mut matrix: SparseBitMatrix = SparseBitMatrix::new(64, 100); + let mut matrix: SparseBitMatrix = SparseBitMatrix::new(100); matrix.add(3, 22); matrix.add(3, 75); matrix.add(2, 99); -- cgit 1.4.1-3-g733a5 From 503455bcc7dd3acd31964504237735f5ef238520 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 29 Jul 2018 17:40:36 +0100 Subject: Remove unused `mut`s --- src/libfmt_macros/lib.rs | 2 +- src/librustc/hir/lowering.rs | 2 +- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_data_structures/sorted_map.rs | 2 +- src/librustc_lint/unused.rs | 2 +- src/librustc_mir/borrow_check/nll/constraints/graph.rs | 4 ++-- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/monomorphize/partitioning.rs | 2 +- src/librustc_mir/transform/promote_consts.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 3aa09a91e07..373db1f1664 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -168,7 +168,7 @@ impl<'a> Iterator for Parser<'a> { if self.consume('{') { Some(String(self.string(pos + 1))) } else { - let mut arg = self.argument(); + let arg = self.argument(); if let Some(arg_pos) = self.must_consume('}').map(|end| { (pos + raw + 1, end + raw + 2) }) { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 7e2c5d03d6b..63755bcea5e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2814,7 +2814,7 @@ impl<'a> LoweringContext<'a> { let mut defs = self.expect_full_def_from_use(id); // we want to return *something* from this function, so hang onto the first item // for later - let mut ret_def = defs.next().unwrap_or(Def::Err); + let ret_def = defs.next().unwrap_or(Def::Err); for (def, &new_node_id) in defs.zip([id1, id2].iter()) { let vis = vis.clone(); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b99c630edfc..c04785aac20 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1054,7 +1054,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // found arguments is empty (assume the user just wants to ignore args in this case). // For example, if `expected_args_length` is 2, suggest `|_, _|`. if found_args.is_empty() && is_closure { - let mut underscores = "_".repeat(expected_args.len()) + let underscores = "_".repeat(expected_args.len()) .split("") .filter(|s| !s.is_empty()) .collect::>() diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 15b5edaa3d5..bb54e183604 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -354,7 +354,7 @@ impl PrintContext { }; if has_default { if let Some(substs) = tcx.lift(&substs) { - let mut types = substs.types().rev().skip(child_types); + let types = substs.types().rev().skip(child_types); for ((def_id, has_default), actual) in type_params.zip(types) { if !has_default { break; diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index 92b0bffd752..730b13a0584 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -56,7 +56,7 @@ impl SortedMap { pub fn insert(&mut self, key: K, mut value: V) -> Option { match self.lookup_index_for(&key) { Ok(index) => { - let mut slot = unsafe { + let slot = unsafe { self.data.get_unchecked_mut(index) }; mem::swap(&mut slot.1, &mut value); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 3d64fa572d1..da291f56ee4 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { fn check_must_use(cx: &LateContext, def_id: DefId, sp: Span, describe_path: &str) -> bool { for attr in cx.tcx.get_attrs(def_id).iter() { if attr.check_name("must_use") { - let mut msg = format!("unused {}`{}` which must be used", + let msg = format!("unused {}`{}` which must be used", describe_path, cx.tcx.item_path_str(def_id)); let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg); // check for #[must_use = "..."] diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/nll/constraints/graph.rs index 45ed37a90ef..5f05ae8ade5 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/graph.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/graph.rs @@ -28,8 +28,8 @@ impl ConstraintGraph { let mut next_constraints = IndexVec::from_elem(None, &set.constraints); for (idx, constraint) in set.constraints.iter_enumerated().rev() { - let mut head = &mut first_constraints[constraint.sup]; - let mut next = &mut next_constraints[idx]; + let head = &mut first_constraints[constraint.sup]; + let next = &mut next_constraints[idx]; debug_assert!(next.is_none()); *next = *head; *head = Some(idx); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index afa0d28dd77..f8bfb5b48ba 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -259,7 +259,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } TestKind::Eq { value, mut ty } => { - let mut val = Operand::Copy(place.clone()); + let val = Operand::Copy(place.clone()); let mut expect = self.literal_operand(test.span, ty, value); // Use PartialEq::eq instead of BinOp::Eq // (the binop can only handle primitives) diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index f83ea6fa13b..bd0b2c6c278 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -353,7 +353,7 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Visibility::Hidden } }; - let (linkage, mut visibility) = match mono_item.explicit_linkage(tcx) { + let (linkage, visibility) = match mono_item.explicit_linkage(tcx) { Some(explicit_linkage) => (explicit_linkage, Visibility::Default), None => { match mono_item { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 1d1ef1a151a..b3ae65f5325 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -390,7 +390,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, LocalDecl::new_return_place(tcx.types.never, mir.span) ).collect(); - let mut promoter = Promoter { + let promoter = Promoter { promoted: Mir::new( IndexVec::new(), // FIXME: maybe try to filter this to avoid blowing up diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 50eb89be690..acdb7c4d4ed 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -865,7 +865,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() { - let mut import = this.import_map.entry(directive.id).or_default(); + let import = this.import_map.entry(directive.id).or_default(); import[ns] = Some(PathResolution::new(binding.def())); }); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index a250d4a3598..761521c8807 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -423,7 +423,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut qualname = String::from("<"); qualname.push_str(&self.tcx.hir.node_to_pretty_string(ty.id)); - let mut trait_id = self.tcx.trait_id_of_impl(impl_id); + let trait_id = self.tcx.trait_id_of_impl(impl_id); let mut decl_id = None; let mut docs = String::new(); let mut attrs = vec![]; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c050e30fea0..f658d574264 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1172,7 +1172,7 @@ fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option // Try looking for methods and associated items let mut split = path_str.rsplitn(2, "::"); - let mut item_name = if let Some(first) = split.next() { + let item_name = if let Some(first) = split.next() { first } else { return Err(()) -- cgit 1.4.1-3-g733a5 From 9169934e27c955787e94186364dcc6fcb7455e4d Mon Sep 17 00:00:00 2001 From: ljedrz Date: Mon, 30 Jul 2018 14:54:33 +0200 Subject: Use Vec::extend in SmallVec::extend when applicable --- src/librustc_data_structures/small_vec.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index 83eb54fade1..bfa580eb186 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -169,10 +169,18 @@ impl FromIterator for SmallVec { impl Extend for SmallVec { fn extend>(&mut self, iter: I) { - let iter = iter.into_iter(); - self.reserve(iter.size_hint().0); - for el in iter { - self.push(el); + if self.is_array() { + let iter = iter.into_iter(); + self.reserve(iter.size_hint().0); + + for el in iter { + self.push(el); + } + } else { + match self.0 { + AccumulateVec::Heap(ref mut vec) => vec.extend(iter), + _ => unreachable!() + } } } } -- cgit 1.4.1-3-g733a5 From ca5264826430cb5dab7a3c61394e8e795bbbd851 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 31 Jul 2018 14:11:04 +0200 Subject: Benchmarks for SmallVec --- src/librustc_data_structures/small_vec.rs | 116 ++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index bfa580eb186..2398a6f9925 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -225,3 +225,119 @@ impl Decodable for SmallVec }) } } + +#[cfg(test)] +mod tests { + extern crate test; + use self::test::Bencher; + + use super::*; + + #[bench] + fn fill_small_vec_1_10_with_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 1]> = SmallVec::with_capacity(10); + + sv.extend(0..10); + }) + } + + #[bench] + fn fill_small_vec_1_10_wo_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 1]> = SmallVec::new(); + + sv.extend(0..10); + }) + } + + #[bench] + fn fill_small_vec_8_10_with_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 8]> = SmallVec::with_capacity(10); + + sv.extend(0..10); + }) + } + + #[bench] + fn fill_small_vec_8_10_wo_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 8]> = SmallVec::new(); + + sv.extend(0..10); + }) + } + + #[bench] + fn fill_small_vec_32_10_with_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 32]> = SmallVec::with_capacity(10); + + sv.extend(0..10); + }) + } + + #[bench] + fn fill_small_vec_32_10_wo_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 32]> = SmallVec::new(); + + sv.extend(0..10); + }) + } + + #[bench] + fn fill_small_vec_1_50_with_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 1]> = SmallVec::with_capacity(50); + + sv.extend(0..50); + }) + } + + #[bench] + fn fill_small_vec_1_50_wo_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 1]> = SmallVec::new(); + + sv.extend(0..50); + }) + } + + #[bench] + fn fill_small_vec_8_50_with_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 8]> = SmallVec::with_capacity(50); + + sv.extend(0..50); + }) + } + + #[bench] + fn fill_small_vec_8_50_wo_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 8]> = SmallVec::new(); + + sv.extend(0..50); + }) + } + + #[bench] + fn fill_small_vec_32_50_with_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 32]> = SmallVec::with_capacity(50); + + sv.extend(0..50); + }) + } + + #[bench] + fn fill_small_vec_32_50_wo_cap(b: &mut Bencher) { + b.iter(|| { + let mut sv: SmallVec<[usize; 32]> = SmallVec::new(); + + sv.extend(0..50); + }) + } +} -- cgit 1.4.1-3-g733a5 From e462c06a280e4198b404323d7754e1308817b22e Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 1 Aug 2018 13:00:37 +0200 Subject: Another SmallVec.extend optimization This improves SmallVec.extend even more over #52859 Before (as of #52859): ``` test small_vec::tests::fill_small_vec_1_10_with_cap ... bench: 31 ns/iter (+/- 5) test small_vec::tests::fill_small_vec_1_10_wo_cap ... bench: 70 ns/iter (+/- 4) test small_vec::tests::fill_small_vec_1_50_with_cap ... bench: 36 ns/iter (+/- 3) test small_vec::tests::fill_small_vec_1_50_wo_cap ... bench: 256 ns/iter (+/- 17) test small_vec::tests::fill_small_vec_32_10_with_cap ... bench: 31 ns/iter (+/- 5) test small_vec::tests::fill_small_vec_32_10_wo_cap ... bench: 26 ns/iter (+/- 1) test small_vec::tests::fill_small_vec_32_50_with_cap ... bench: 49 ns/iter (+/- 4) test small_vec::tests::fill_small_vec_32_50_wo_cap ... bench: 219 ns/iter (+/- 11) test small_vec::tests::fill_small_vec_8_10_with_cap ... bench: 32 ns/iter (+/- 2) test small_vec::tests::fill_small_vec_8_10_wo_cap ... bench: 61 ns/iter (+/- 12) test small_vec::tests::fill_small_vec_8_50_with_cap ... bench: 37 ns/iter (+/- 3) test small_vec::tests::fill_small_vec_8_50_wo_cap ... bench: 210 ns/iter (+/- 10) ``` After: ``` test small_vec::tests::fill_small_vec_1_10_wo_cap ... bench: 31 ns/iter (+/- 3) test small_vec::tests::fill_small_vec_1_50_with_cap ... bench: 39 ns/iter (+/- 4) test small_vec::tests::fill_small_vec_1_50_wo_cap ... bench: 35 ns/iter (+/- 4) test small_vec::tests::fill_small_vec_32_10_with_cap ... bench: 37 ns/iter (+/- 3) test small_vec::tests::fill_small_vec_32_10_wo_cap ... bench: 32 ns/iter (+/- 2) test small_vec::tests::fill_small_vec_32_50_with_cap ... bench: 52 ns/iter (+/- 4) test small_vec::tests::fill_small_vec_32_50_wo_cap ... bench: 46 ns/iter (+/- 0) test small_vec::tests::fill_small_vec_8_10_with_cap ... bench: 35 ns/iter (+/- 4) test small_vec::tests::fill_small_vec_8_10_wo_cap ... bench: 31 ns/iter (+/- 0) test small_vec::tests::fill_small_vec_8_50_with_cap ... bench: 40 ns/iter (+/- 15) test small_vec::tests::fill_small_vec_8_50_wo_cap ... bench: 36 ns/iter (+/- 2) ``` --- src/librustc_data_structures/small_vec.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index b5f52d54ae4..76b01beb4ba 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -169,18 +169,11 @@ impl FromIterator for SmallVec { impl Extend for SmallVec { fn extend>(&mut self, iter: I) { - if self.is_array() { - let iter = iter.into_iter(); - self.reserve(iter.size_hint().0); - - for el in iter { - self.push(el); - } - } else { - match self.0 { - AccumulateVec::Heap(ref mut vec) => vec.extend(iter), - _ => unreachable!() - } + let iter = iter.into_iter(); + self.reserve(iter.size_hint().0); + match self.0 { + AccumulateVec::Heap(ref mut vec) => vec.extend(iter), + _ => iter.for_each(|el| self.push(el)) } } } -- cgit 1.4.1-3-g733a5 From 9bc4fbb10a1517c2ac5a4c9b0ae3ac6559c90a0d Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 30 Jul 2018 08:58:14 -0600 Subject: Split out growth functionality into BitVector type --- src/librustc/mir/traversal.rs | 10 +- src/librustc/traits/select.rs | 4 +- .../debuginfo/create_scope_map.rs | 6 +- src/librustc_codegen_llvm/mir/analyze.rs | 8 +- src/librustc_codegen_llvm/mir/mod.rs | 6 +- src/librustc_data_structures/bitvec.rs | 128 ++++++++++++--------- .../graph/implementation/mod.rs | 8 +- src/librustc_mir/build/matches/mod.rs | 4 +- src/librustc_mir/build/matches/test.rs | 6 +- src/librustc_mir/monomorphize/collector.rs | 2 +- src/librustc_mir/transform/inline.rs | 4 +- src/librustc_mir/transform/qualify_consts.rs | 8 +- .../transform/remove_noop_landing_pads.rs | 6 +- src/librustc_mir/transform/simplify.rs | 10 +- src/libsyntax/lib.rs | 4 +- 15 files changed, 116 insertions(+), 98 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 86fd825850f..c178a9063c9 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use super::*; @@ -32,7 +32,7 @@ use super::*; #[derive(Clone)] pub struct Preorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, - visited: BitVector, + visited: BitArray, worklist: Vec, } @@ -42,7 +42,7 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> { Preorder { mir, - visited: BitVector::new(mir.basic_blocks().len()), + visited: BitArray::new(mir.basic_blocks().len()), worklist, } } @@ -104,7 +104,7 @@ impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {} /// A Postorder traversal of this graph is `D B C A` or `D C B A` pub struct Postorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, - visited: BitVector, + visited: BitArray, visit_stack: Vec<(BasicBlock, Successors<'a>)> } @@ -112,7 +112,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> { let mut po = Postorder { mir, - visited: BitVector::new(mir.basic_blocks().len()), + visited: BitArray::new(mir.basic_blocks().len()), visit_stack: Vec::new() }; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 40171345f55..35184ca6a25 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -45,7 +45,7 @@ use middle::lang_items; use mir::interpret::{GlobalId}; use rustc_data_structures::sync::Lock; -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use std::iter; use std::cmp; use std::fmt; @@ -3056,7 +3056,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } else { return Err(Unimplemented); }; - let mut ty_params = BitVector::new(substs_a.types().count()); + let mut ty_params = BitArray::new(substs_a.types().count()); let mut found = false; for ty in field.walk() { if let ty::TyParam(p) = ty.sty { diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index 5273032f2d7..a76f1d50fa7 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -21,7 +21,7 @@ use libc::c_uint; use syntax_pos::Pos; -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use syntax_pos::BytePos; @@ -64,7 +64,7 @@ pub fn create_mir_scopes( }; // Find all the scopes with variables defined in them. - let mut has_variables = BitVector::new(mir.source_scopes.len()); + let mut has_variables = BitArray::new(mir.source_scopes.len()); for var in mir.vars_iter() { let decl = &mir.local_decls[var]; has_variables.insert(decl.visibility_scope); @@ -81,7 +81,7 @@ pub fn create_mir_scopes( fn make_mir_scope(cx: &CodegenCx<'ll, '_>, mir: &Mir, - has_variables: &BitVector, + has_variables: &BitArray, debug_context: &FunctionDebugContextData<'ll>, scope: SourceScope, scopes: &mut IndexVec>) { diff --git a/src/librustc_codegen_llvm/mir/analyze.rs b/src/librustc_codegen_llvm/mir/analyze.rs index 2c205803524..993138aee1c 100644 --- a/src/librustc_codegen_llvm/mir/analyze.rs +++ b/src/librustc_codegen_llvm/mir/analyze.rs @@ -11,7 +11,7 @@ //! An analysis to determine which locals require allocas and //! which do not. -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::{self, Location, TerminatorKind}; @@ -22,7 +22,7 @@ use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; use super::FunctionCx; -pub fn non_ssa_locals(fx: &FunctionCx<'a, 'll, 'tcx>) -> BitVector { +pub fn non_ssa_locals(fx: &FunctionCx<'a, 'll, 'tcx>) -> BitArray { let mir = fx.mir; let mut analyzer = LocalAnalyzer::new(fx); @@ -54,7 +54,7 @@ pub fn non_ssa_locals(fx: &FunctionCx<'a, 'll, 'tcx>) -> BitVector { struct LocalAnalyzer<'mir, 'a: 'mir, 'll: 'a, 'tcx: 'll> { fx: &'mir FunctionCx<'a, 'll, 'tcx>, dominators: Dominators, - non_ssa_locals: BitVector, + non_ssa_locals: BitArray, // The location of the first visited direct assignment to each // local, or an invalid location (out of bounds `block` index). first_assignment: IndexVec @@ -67,7 +67,7 @@ impl LocalAnalyzer<'mir, 'a, 'll, 'tcx> { let mut analyzer = LocalAnalyzer { fx, dominators: fx.mir.dominators(), - non_ssa_locals: BitVector::new(fx.mir.local_decls.len()), + non_ssa_locals: BitArray::new(fx.mir.local_decls.len()), first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls) }; diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs index 8cdd0398eff..a099cb5c64b 100644 --- a/src/librustc_codegen_llvm/mir/mod.rs +++ b/src/librustc_codegen_llvm/mir/mod.rs @@ -31,7 +31,7 @@ use syntax::symbol::keywords; use std::iter; -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; pub use self::constant::codegen_static_initializer; @@ -323,7 +323,7 @@ pub fn codegen_mir( debuginfo::start_emitting_source_locations(&fx.debug_context); let rpo = traversal::reverse_postorder(&mir); - let mut visited = BitVector::new(mir.basic_blocks().len()); + let mut visited = BitArray::new(mir.basic_blocks().len()); // Codegen the body of each block using reverse postorder for (bb, _) in rpo { @@ -417,7 +417,7 @@ fn arg_local_refs( bx: &Builder<'a, 'll, 'tcx>, fx: &FunctionCx<'a, 'll, 'tcx>, scopes: &IndexVec>, - memory_locals: &BitVector, + memory_locals: &BitArray, ) -> Vec> { let mir = fx.mir; let tcx = bx.tcx(); diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 04d6cb5e2a6..6e8a45d0342 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -9,24 +9,74 @@ // except according to those terms. use indexed_vec::{Idx, IndexVec}; -use std::iter::FromIterator; use std::marker::PhantomData; type Word = u128; const WORD_BITS: usize = 128; -/// A very simple BitVector type. +/// A very simple BitArray type. +/// +/// It does not support resizing after creation; use `BitVector` for that. #[derive(Clone, Debug, PartialEq)] -pub struct BitVector { +pub struct BitArray { data: Vec, marker: PhantomData, } +#[derive(Clone, Debug, PartialEq)] +pub struct BitVector { + data: BitArray, +} + impl BitVector { + pub fn grow(&mut self, num_bits: C) { + self.data.grow(num_bits) + } + + pub fn new() -> BitVector { + BitVector { + data: BitArray::new(0), + } + } + + pub fn with_capacity(bits: usize) -> BitVector { + BitVector { + data: BitArray::new(bits), + } + } + + /// Returns true if the bit has changed. + #[inline] + pub fn insert(&mut self, bit: C) -> bool { + self.grow(bit); + self.data.insert(bit) + } + #[inline] - pub fn new(num_bits: usize) -> BitVector { + pub fn contains(&self, bit: C) -> bool { + let (word, mask) = word_mask(bit); + if let Some(word) = self.data.data.get(word) { + (word & mask) != 0 + } else { + false + } + } +} + +impl BitArray { + // Do not make this method public, instead switch your use case to BitVector. + #[inline] + fn grow(&mut self, num_bits: C) { let num_words = words(num_bits); - BitVector { + if self.data.len() <= num_words { + self.data.resize(num_words + 1, 0) + } + } + + #[inline] + pub fn new(num_bits: usize) -> BitArray { + let num_words = words(num_bits); + BitArray { data: vec![0; num_words], marker: PhantomData, } @@ -54,7 +104,7 @@ impl BitVector { /// /// The two vectors must have the same length. #[inline] - pub fn contains_all(&self, other: &BitVector) -> bool { + pub fn contains_all(&self, other: &BitArray) -> bool { assert_eq!(self.data.len(), other.data.len()); self.data.iter().zip(&other.data).all(|(a, b)| (a & b) == *b) } @@ -94,7 +144,7 @@ impl BitVector { } #[inline] - pub fn merge(&mut self, all: &BitVector) -> bool { + pub fn merge(&mut self, all: &BitArray) -> bool { assert!(self.data.len() == all.data.len()); let mut changed = false; for (i, j) in self.data.iter_mut().zip(&all.data) { @@ -107,18 +157,10 @@ impl BitVector { changed } - #[inline] - pub fn grow(&mut self, num_bits: C) { - let num_words = words(num_bits); - if self.data.len() < num_words { - self.data.resize(num_words, 0) - } - } - /// Iterates over indexes of set bits in a sorted order #[inline] - pub fn iter<'a>(&'a self) -> BitVectorIter<'a, C> { - BitVectorIter { + pub fn iter<'a>(&'a self) -> BitIter<'a, C> { + BitIter { iter: self.data.iter(), current: 0, idx: 0, @@ -127,14 +169,14 @@ impl BitVector { } } -pub struct BitVectorIter<'a, C: Idx> { +pub struct BitIter<'a, C: Idx> { iter: ::std::slice::Iter<'a, Word>, current: Word, idx: usize, marker: PhantomData } -impl<'a, C: Idx> Iterator for BitVectorIter<'a, C> { +impl<'a, C: Idx> Iterator for BitIter<'a, C> { type Item = C; fn next(&mut self) -> Option { while self.current == 0 { @@ -163,30 +205,6 @@ impl<'a, C: Idx> Iterator for BitVectorIter<'a, C> { } } -impl FromIterator for BitVector { - fn from_iter(iter: I) -> BitVector - where - I: IntoIterator, - { - let iter = iter.into_iter(); - let (len, _) = iter.size_hint(); - // Make the minimum length for the bitvector WORD_BITS bits since that's - // the smallest non-zero size anyway. - let len = if len < WORD_BITS { WORD_BITS } else { len }; - let mut bv = BitVector::new(len); - for (idx, val) in iter.enumerate() { - if idx > len { - bv.grow(C::new(idx)); - } - if val { - bv.insert(C::new(idx)); - } - } - - bv - } -} - /// A "bit matrix" is basically a matrix of booleans represented as /// one gigantic bitvector. In other words, it is as if you have /// `rows` bitvectors, each of length `columns`. @@ -288,9 +306,9 @@ impl BitMatrix { /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter<'a>(&'a self, row: R) -> BitVectorIter<'a, C> { + pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> { let (start, end) = self.range(row); - BitVectorIter { + BitIter { iter: self.vector[start..end].iter(), current: 0, idx: 0, @@ -308,7 +326,7 @@ where C: Idx, { columns: usize, - vector: IndexVec>, + vector: IndexVec>, } impl SparseBitMatrix { @@ -323,7 +341,7 @@ impl SparseBitMatrix { fn ensure_row(&mut self, row: R) { let columns = self.columns; self.vector - .ensure_contains_elem(row, || BitVector::new(columns)); + .ensure_contains_elem(row, || BitArray::new(columns)); } /// Sets the cell at `(row, column)` to true. Put another way, insert @@ -361,7 +379,7 @@ impl SparseBitMatrix { } /// Merge a row, `from`, into the `into` row. - pub fn merge_into(&mut self, into: R, from: &BitVector) -> bool { + pub fn merge_into(&mut self, into: R, from: &BitArray) -> bool { self.ensure_row(into); self.vector[into].merge(from) } @@ -388,11 +406,11 @@ impl SparseBitMatrix { } /// Iterates through each row and the accompanying bit set. - pub fn iter_enumerated<'a>(&'a self) -> impl Iterator)> + 'a { + pub fn iter_enumerated<'a>(&'a self) -> impl Iterator)> + 'a { self.vector.iter_enumerated() } - pub fn row(&self, row: R) -> Option<&BitVector> { + pub fn row(&self, row: R) -> Option<&BitArray> { self.vector.get(row) } } @@ -412,7 +430,7 @@ fn word_mask(index: C) -> (usize, Word) { #[test] fn bitvec_iter_works() { - let mut bitvec: BitVector = BitVector::new(100); + let mut bitvec: BitArray = BitArray::new(100); bitvec.insert(1); bitvec.insert(10); bitvec.insert(19); @@ -430,7 +448,7 @@ fn bitvec_iter_works() { #[test] fn bitvec_iter_works_2() { - let mut bitvec: BitVector = BitVector::new(319); + let mut bitvec: BitArray = BitArray::new(319); bitvec.insert(0); bitvec.insert(127); bitvec.insert(191); @@ -441,8 +459,8 @@ fn bitvec_iter_works_2() { #[test] fn union_two_vecs() { - let mut vec1: BitVector = BitVector::new(65); - let mut vec2: BitVector = BitVector::new(65); + let mut vec1: BitArray = BitArray::new(65); + let mut vec2: BitArray = BitArray::new(65); assert!(vec1.insert(3)); assert!(!vec1.insert(3)); assert!(vec2.insert(5)); @@ -458,7 +476,7 @@ fn union_two_vecs() { #[test] fn grow() { - let mut vec1: BitVector = BitVector::new(65); + let mut vec1: BitVector = BitVector::with_capacity(65); for index in 0..65 { assert!(vec1.insert(index)); assert!(!vec1.insert(index)); diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs index dbfc09116bb..cf9403db658 100644 --- a/src/librustc_data_structures/graph/implementation/mod.rs +++ b/src/librustc_data_structures/graph/implementation/mod.rs @@ -30,7 +30,7 @@ //! the field `next_edge`). Each of those fields is an array that should //! be indexed by the direction (see the type `Direction`). -use bitvec::BitVector; +use bitvec::BitArray; use std::fmt::Debug; use std::usize; use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; @@ -266,7 +266,7 @@ impl Graph { direction: Direction, entry_node: NodeIndex, ) -> Vec { - let mut visited = BitVector::new(self.len_nodes()); + let mut visited = BitArray::new(self.len_nodes()); let mut stack = vec![]; let mut result = Vec::with_capacity(self.len_nodes()); let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { @@ -348,7 +348,7 @@ where { graph: &'g Graph, stack: Vec, - visited: BitVector, + visited: BitArray, direction: Direction, } @@ -358,7 +358,7 @@ impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { start_node: NodeIndex, direction: Direction, ) -> Self { - let mut visited = BitVector::new(graph.len_nodes()); + let mut visited = BitArray::new(graph.len_nodes()); visited.insert(start_node.node_id()); DepthFirstTraversal { graph, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 6a447d81dc3..6b6ec749bcb 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -18,7 +18,7 @@ use build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard}; use build::scope::{CachedBlock, DropKind}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use rustc::ty::{self, Ty}; use rustc::mir::*; use rustc::hir; @@ -496,7 +496,7 @@ enum TestKind<'tcx> { // test the branches of enum Switch { adt_def: &'tcx ty::AdtDef, - variants: BitVector, + variants: BitArray, }, // test the branches of enum diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index f8bfb5b48ba..7106e02284d 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -19,7 +19,7 @@ use build::Builder; use build::matches::{Candidate, MatchPair, Test, TestKind}; use hair::*; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use rustc::ty::{self, Ty}; use rustc::ty::util::IntTypeExt; use rustc::mir::*; @@ -38,7 +38,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: match_pair.pattern.span, kind: TestKind::Switch { adt_def: adt_def.clone(), - variants: BitVector::new(adt_def.variants.len()), + variants: BitArray::new(adt_def.variants.len()), }, } } @@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn add_variants_to_switch<'pat>(&mut self, test_place: &Place<'tcx>, candidate: &Candidate<'pat, 'tcx>, - variants: &mut BitVector) + variants: &mut BitArray) -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 5f05783b15c..6283ee9cfe6 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -240,7 +240,7 @@ impl<'tcx> InliningMap<'tcx> { InliningMap { index: FxHashMap(), targets: Vec::new(), - inlines: BitVector::new(1024), + inlines: BitVector::with_capacity(1024), } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 46fab544aaf..85115427eda 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -14,7 +14,7 @@ use rustc::hir; use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::DefId; -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::*; @@ -271,7 +271,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Traverse the MIR manually so we can account for the effects of // inlining on the CFG. let mut work_list = vec![START_BLOCK]; - let mut visited = BitVector::new(callee_mir.basic_blocks().len()); + let mut visited = BitArray::new(callee_mir.basic_blocks().len()); while let Some(bb) = work_list.pop() { if !visited.insert(bb.index()) { continue; } let blk = &callee_mir.basic_blocks()[bb]; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8a12a604ef2..208679d2aa0 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -14,7 +14,7 @@ //! The Qualif flags below can be used to also provide better //! diagnostics as to why a constant rvalue wasn't promoted. -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::fx::FxHashSet; @@ -116,7 +116,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { param_env: ty::ParamEnv<'tcx>, local_qualif: IndexVec>, qualif: Qualif, - const_fn_arg_vars: BitVector, + const_fn_arg_vars: BitArray, temp_promotion_state: IndexVec, promotion_candidates: Vec } @@ -150,7 +150,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { param_env, local_qualif, qualif: Qualif::empty(), - const_fn_arg_vars: BitVector::new(mir.local_decls.len()), + const_fn_arg_vars: BitArray::new(mir.local_decls.len()), temp_promotion_state: temps, promotion_candidates: vec![] } @@ -284,7 +284,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { let mir = self.mir; - let mut seen_blocks = BitVector::new(mir.basic_blocks().len()); + let mut seen_blocks = BitArray::new(mir.basic_blocks().len()); let mut bb = START_BLOCK; loop { seen_blocks.insert(bb.index()); diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index a7ef93eaec6..04a7a81eb12 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -10,7 +10,7 @@ use rustc::ty::TyCtxt; use rustc::mir::*; -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use transform::{MirPass, MirSource}; use util::patch::MirPatch; @@ -45,7 +45,7 @@ impl RemoveNoopLandingPads { &self, bb: BasicBlock, mir: &Mir, - nop_landing_pads: &BitVector, + nop_landing_pads: &BitArray, ) -> bool { for stmt in &mir[bb].statements { match stmt.kind { @@ -111,7 +111,7 @@ impl RemoveNoopLandingPads { let mut jumps_folded = 0; let mut landing_pads_removed = 0; - let mut nop_landing_pads = BitVector::new(mir.basic_blocks().len()); + let mut nop_landing_pads = BitArray::new(mir.basic_blocks().len()); // This is a post-order traversal, so that if A post-dominates B // then A will be visited before B. diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 6b8d5a14893..6e8471c6729 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -37,7 +37,7 @@ //! naively generate still contains the `_a = ()` write in the unreachable block "after" the //! return. -use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::bitvec::BitArray; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::ty::TyCtxt; use rustc::mir::*; @@ -249,7 +249,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { } pub fn remove_dead_blocks(mir: &mut Mir) { - let mut seen = BitVector::new(mir.basic_blocks().len()); + let mut seen = BitArray::new(mir.basic_blocks().len()); for (bb, _) in traversal::preorder(mir) { seen.insert(bb.index()); } @@ -285,7 +285,7 @@ impl MirPass for SimplifyLocals { tcx: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { - let mut marker = DeclMarker { locals: BitVector::new(mir.local_decls.len()) }; + let mut marker = DeclMarker { locals: BitArray::new(mir.local_decls.len()) }; marker.visit_mir(mir); // Return pointer and arguments are always live marker.locals.insert(RETURN_PLACE); @@ -310,7 +310,7 @@ impl MirPass for SimplifyLocals { /// Construct the mapping while swapping out unused stuff out from the `vec`. fn make_local_map<'tcx, V>( vec: &mut IndexVec, - mask: BitVector, + mask: BitArray, ) -> IndexVec> { let mut map: IndexVec> = IndexVec::from_elem(None, &*vec); let mut used = Local::new(0); @@ -326,7 +326,7 @@ fn make_local_map<'tcx, V>( } struct DeclMarker { - pub locals: BitVector, + pub locals: BitArray, } impl<'tcx> Visitor<'tcx> for DeclMarker { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 16507ec5a5d..0c105865e0c 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -87,8 +87,8 @@ impl Globals { Globals { // We have no idea how many attributes their will be, so just // initiate the vectors with 0 bits. We'll grow them as necessary. - used_attrs: Lock::new(BitVector::new(0)), - known_attrs: Lock::new(BitVector::new(0)), + used_attrs: Lock::new(BitVector::new()), + known_attrs: Lock::new(BitVector::new()), syntax_pos_globals: syntax_pos::Globals::new(), } } -- cgit 1.4.1-3-g733a5 From 4471537ea046da8d8465e2234fa501c29b201d0c Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 2 Aug 2018 22:58:53 +0200 Subject: make TinyList more readable and optimize remove(_) also add benchmarks Before: ``` test tiny_list::test::bench_insert_empty ... bench: 1 ns/iter (+/- 0) test tiny_list::test::bench_insert_one ... bench: 16 ns/iter (+/- 0) test tiny_list::test::bench_remove_empty ... bench: 2 ns/iter (+/- 0) test tiny_list::test::bench_remove_one ... bench: 6 ns/iter (+/- 0) test tiny_list::test::bench_remove_unknown ... bench: 4 ns/iter (+/- 0) ``` After: ``` test tiny_list::test::bench_insert_empty ... bench: 1 ns/iter (+/- 0) test tiny_list::test::bench_insert_one ... bench: 16 ns/iter (+/- 0) test tiny_list::test::bench_remove_empty ... bench: 0 ns/iter (+/- 0) test tiny_list::test::bench_remove_one ... bench: 3 ns/iter (+/- 0) test tiny_list::test::bench_remove_unknown ... bench: 2 ns/iter (+/- 0) ``` --- src/librustc_data_structures/tiny_list.rs | 81 +++++++++++++++++++------------ 1 file changed, 49 insertions(+), 32 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index 5b1b2aadec5..c12fc22baf0 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -50,44 +50,22 @@ impl TinyList { #[inline] pub fn insert(&mut self, data: T) { - let current_head = mem::replace(&mut self.head, None); - - if let Some(current_head) = current_head { - let current_head = Box::new(current_head); - self.head = Some(Element { - data, - next: Some(current_head) - }); - } else { - self.head = Some(Element { - data, - next: None, - }) - } + self.head = Some(Element { + data, + next: mem::replace(&mut self.head, None).map(Box::new), + }); } #[inline] pub fn remove(&mut self, data: &T) -> bool { - let remove_head = if let Some(ref mut head) = self.head { - if head.data == *data { - Some(mem::replace(&mut head.next, None)) - } else { - None + self.head = match self.head { + Some(ref mut head) if head.data == *data => { + mem::replace(&mut head.next, None).map(|x| *x) } - } else { - return false + Some(ref mut head) => return head.remove_next(data), + None => return false, }; - - if let Some(remove_head) = remove_head { - if let Some(next) = remove_head { - self.head = Some(*next); - } else { - self.head = None; - } - return true - } - - self.head.as_mut().unwrap().remove_next(data) + true } #[inline] @@ -156,6 +134,8 @@ impl Element { #[cfg(test)] mod test { use super::*; + extern crate test; + use self::test::Bencher; #[test] fn test_contains_and_insert() { @@ -248,4 +228,41 @@ mod test { assert_eq!(list.len(), 0); } + + #[bench] + fn bench_insert_empty(b: &mut Bencher) { + b.iter(|| { + let mut list = TinyList::new(); + list.insert(1); + }) + } + + #[bench] + fn bench_insert_one(b: &mut Bencher) { + b.iter(|| { + let mut list = TinyList::new_single(0); + list.insert(1); + }) + } + + #[bench] + fn bench_remove_empty(b: &mut Bencher) { + b.iter(|| { + TinyList::new().remove(&1) + }); + } + + #[bench] + fn bench_remove_unknown(b: &mut Bencher) { + b.iter(|| { + TinyList::new_single(0).remove(&1) + }); + } + + #[bench] + fn bench_remove_one(b: &mut Bencher) { + b.iter(|| { + TinyList::new_single(1).remove(&1) + }); + } } -- cgit 1.4.1-3-g733a5 From b68b3965a241e47c232613f403fbace64fd8b876 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Fri, 3 Aug 2018 10:19:22 +0200 Subject: Don't collect() when size_hint is useless --- src/librustc/infer/outlives/obligations.rs | 12 +++++++----- src/librustc_data_structures/small_vec.rs | 7 ++++++- src/libsyntax/ast.rs | 6 +++++- 3 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index c74783f5e4d..3598d66060b 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -151,12 +151,14 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { debug!("process_registered_region_obligations()"); // pull out the region obligations with the given `body_id` (leaving the rest) - let my_region_obligations = { + let mut my_region_obligations = Vec::with_capacity(self.region_obligations.borrow().len()); + { let mut r_o = self.region_obligations.borrow_mut(); - let my_r_o = r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id) - .map(|(_, obligation)| obligation).collect::>(); - my_r_o - }; + my_region_obligations.extend( + r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id) + .map(|(_, obligation)| obligation) + ); + } let outlives = &mut TypeOutlives::new( self, diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index 76b01beb4ba..e958fd7da61 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -210,7 +210,12 @@ impl Decodable for SmallVec A::Element: Decodable { fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { - (0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect() + let mut vec = SmallVec::with_capacity(len); + // FIXME(#48994) - could just be collected into a Result + for i in 0..len { + vec.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); + } + Ok(vec) }) } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 28c1e4324de..6925ed2afb8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -501,7 +501,11 @@ impl Pat { PatKind::Slice(pats, None, _) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?, PatKind::Tuple(pats, None) => { - let tys = pats.iter().map(|pat| pat.to_ty()).collect::>>()?; + let mut tys = Vec::with_capacity(pats.len()); + // FIXME(#48994) - could just be collected into an Option + for pat in pats { + tys.push(pat.to_ty()?); + } TyKind::Tup(tys) } _ => return None, -- cgit 1.4.1-3-g733a5 From c81b95f305e76c4173121aabb08af15e2d22aaed Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 23 Jul 2018 14:53:39 +0100 Subject: Remove unnecessary feature attributes that sneaked in --- src/librustc/lib.rs | 3 --- src/librustc_borrowck/lib.rs | 1 - src/librustc_codegen_llvm/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/librustc_incremental/lib.rs | 1 - src/librustc_metadata/lib.rs | 1 - src/librustc_mir/lib.rs | 3 --- src/librustc_target/lib.rs | 2 -- src/librustc_typeck/lib.rs | 1 - src/librustdoc/lib.rs | 2 -- 10 files changed, 16 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8ff5d33c91d..a5913467b80 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -45,8 +45,6 @@ #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(drain_filter)] -#![feature(from_ref)] -#![feature(fs_read_write)] #![feature(iterator_find_map)] #![cfg_attr(windows, feature(libc))] #![feature(macro_vis_matcher)] @@ -72,7 +70,6 @@ #![feature(test)] #![feature(in_band_lifetimes)] #![feature(macro_at_most_once_rep)] -#![feature(inclusive_range_methods)] #![feature(crate_in_paths)] #![recursion_limit="512"] diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index a5a20af0e4e..c7e7465a353 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -14,7 +14,6 @@ #![allow(non_camel_case_types)] -#![feature(from_ref)] #![feature(quote)] #![recursion_limit="256"] diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index c01ef37d1b8..9599ccfe979 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -23,7 +23,6 @@ #![feature(crate_visibility_modifier)] #![feature(custom_attribute)] #![feature(extern_types)] -#![feature(fs_read_write)] #![feature(in_band_lifetimes)] #![allow(unused_attributes)] #![feature(libc)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index a9e582e510e..dd90cf7ae19 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -20,7 +20,6 @@ html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(collections_range)] #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 3839c133a6e..73886e5e281 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -14,7 +14,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(fs_read_write)] #![feature(specialization)] #![recursion_limit="256"] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 798b631989b..98946ad6081 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -13,7 +13,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_patterns)] -#![feature(fs_read_write)] #![feature(libc)] #![feature(macro_at_most_once_rep)] #![feature(proc_macro_internals)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 3f32d307409..d60b453e0d8 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -18,7 +18,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(in_band_lifetimes)] #![feature(slice_patterns)] #![feature(slice_sort_by_cached_key)] -#![feature(from_ref)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(catch_expr)] @@ -26,13 +25,11 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] -#![feature(fs_read_write)] #![feature(in_band_lifetimes)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] -#![feature(crate_visibility_modifier)] #![feature(never_type)] #![feature(specialization)] #![feature(try_trait)] diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index a50a5a2d1cb..af2697f62f7 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -23,8 +23,6 @@ #![feature(box_syntax)] #![feature(const_fn)] -#![feature(fs_read_write)] -#![feature(inclusive_range)] #![feature(slice_patterns)] #[macro_use] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9fd5db16fb1..ecc167d5a19 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -74,7 +74,6 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] -#![feature(from_ref)] #![feature(exhaustive_patterns)] #![feature(iterator_find_map)] #![feature(quote)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index dda97cfdb2c..228a1b9b0cd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -17,13 +17,11 @@ #![feature(rustc_private)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(fs_read_write)] #![feature(iterator_find_map)] #![feature(set_stdio)] #![feature(slice_sort_by_cached_key)] #![feature(test)] #![feature(vec_remove_item)] -#![feature(entry_and_modify)] #![feature(ptr_offset_from)] #![feature(crate_visibility_modifier)] -- cgit 1.4.1-3-g733a5 From c556cff96f05530ee63d49eeb55acb3210de0060 Mon Sep 17 00:00:00 2001 From: memoryruins Date: Thu, 9 Aug 2018 09:21:23 -0400 Subject: [nll] librustc_data_structures: enable feature(nll) for bootstrap --- src/librustc_data_structures/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index dd90cf7ae19..67f1c119ea8 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,6 +26,7 @@ #![feature(specialization)] #![feature(optin_builtin_traits)] #![feature(macro_vis_matcher)] +#![cfg_attr(not(stage0), feature(nll))] #![feature(allow_internal_unstable)] #![feature(vec_resize_with)] -- cgit 1.4.1-3-g733a5 From bf103700c6e2aa51e0531ab807b554c17ce9ba7d Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 3 Aug 2018 12:22:22 -0600 Subject: Move SVH structure to data structures --- src/librustc/hir/map/collector.rs | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/hir/mod.rs | 1 - src/librustc/hir/svh.rs | 72 ----------------------------- src/librustc/middle/cstore.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/query/mod.rs | 2 +- src/librustc_codegen_utils/link.rs | 2 +- src/librustc_data_structures/lib.rs | 2 + src/librustc_data_structures/svh.rs | 84 ++++++++++++++++++++++++++++++++++ src/librustc_incremental/persist/fs.rs | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 3 +- src/librustc_metadata/locator.rs | 2 +- src/librustc_metadata/schema.rs | 5 +- 15 files changed, 100 insertions(+), 85 deletions(-) delete mode 100644 src/librustc/hir/svh.rs create mode 100644 src/librustc_data_structures/svh.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 0150ba659c9..3934475bea9 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -12,7 +12,7 @@ use super::*; use dep_graph::{DepGraph, DepKind, DepNodeIndex}; use hir::def_id::{LOCAL_CRATE, CrateNum}; use hir::intravisit::{Visitor, NestedVisitorMap}; -use hir::svh::Svh; +use rustc_data_structures::svh::Svh; use ich::Fingerprint; use middle::cstore::CrateStore; use session::CrateDisambiguator; diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b05bcadf826..81897322b6f 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -22,6 +22,7 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; use middle::cstore::CrateStore; use rustc_target::spec::abi::Abi; +use rustc_data_structures::svh::Svh; use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID}; use syntax::codemap::Spanned; use syntax::ext::base::MacroKind; @@ -29,7 +30,6 @@ use syntax_pos::{Span, DUMMY_SP}; use hir::*; use hir::print::Nested; -use hir::svh::Svh; use util::nodemap::FxHashMap; use std::io; diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 0003790e6d5..521499e4766 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -70,7 +70,6 @@ pub mod lowering; pub mod map; pub mod pat_util; pub mod print; -pub mod svh; /// A HirId uniquely identifies a node in the HIR of the current crate. It is /// composed of the `owner`, which is the DefIndex of the directly enclosing diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs deleted file mode 100644 index a6cfcb710ed..00000000000 --- a/src/librustc/hir/svh.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Calculation and management of a Strict Version Hash for crates -//! -//! The SVH is used for incremental compilation to track when HIR -//! nodes have changed between compilations, and also to detect -//! mismatches where we have two versions of the same crate that were -//! compiled from distinct sources. - -use std::fmt; -use std::hash::{Hash, Hasher}; -use serialize::{Encodable, Decodable, Encoder, Decoder}; - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Svh { - hash: u64, -} - -impl Svh { - /// Create a new `Svh` given the hash. If you actually want to - /// compute the SVH from some HIR, you want the `calculate_svh` - /// function found in `librustc_incremental`. - pub fn new(hash: u64) -> Svh { - Svh { hash: hash } - } - - pub fn as_u64(&self) -> u64 { - self.hash - } - - pub fn to_string(&self) -> String { - format!("{:016x}", self.hash) - } -} - -impl Hash for Svh { - fn hash(&self, state: &mut H) where H: Hasher { - self.hash.to_le().hash(state); - } -} - -impl fmt::Display for Svh { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad(&self.to_string()) - } -} - -impl Encodable for Svh { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_u64(self.as_u64().to_le()) - } -} - -impl Decodable for Svh { - fn decode(d: &mut D) -> Result { - d.read_u64() - .map(u64::from_le) - .map(Svh::new) - } -} - -impl_stable_hash_for!(struct Svh { - hash -}); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 0e84104245d..b91a9644b21 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -25,7 +25,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::definitions::{DefKey, DefPathTable}; -use hir::svh::Svh; +use rustc_data_structures::svh::Svh; use ty::{self, TyCtxt}; use session::{Session, CrateDisambiguator}; use session::search_paths::PathKind; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4fda3bdca3d..6c5713d233a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -18,7 +18,7 @@ use hir::{map as hir_map, FreevarMap, TraitMap}; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use hir::map::DefPathData; -use hir::svh::Svh; +use rustc_data_structures::svh::Svh; use ich::Fingerprint; use ich::StableHashingContext; use infer::canonical::Canonical; diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 35080123d3e..ef22ebef9d7 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -13,7 +13,7 @@ use errors::DiagnosticBuilder; use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::def::{Def, Export}; use hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; -use hir::svh::Svh; +use rustc_data_structures::svh::Svh; use infer::canonical::{self, Canonical}; use lint; use middle::borrowck::BorrowCheckResult; diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs index 73cffdf7d49..a0d88ccae0f 100644 --- a/src/librustc_codegen_utils/link.rs +++ b/src/librustc_codegen_utils/link.rs @@ -11,7 +11,7 @@ use rustc::session::config::{self, OutputFilenames, Input, OutputType}; use rustc::session::Session; use rustc::middle::cstore::LinkMeta; -use rustc::hir::svh::Svh; +use rustc_data_structures::svh::Svh; use std::path::{Path, PathBuf}; use syntax::{ast, attr}; use syntax_pos::Span; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index dd90cf7ae19..b8c21afc386 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -46,6 +46,7 @@ extern crate stable_deref_trait; extern crate rustc_rayon as rayon; extern crate rustc_rayon_core as rayon_core; extern crate rustc_hash; +extern crate serialize; // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] @@ -53,6 +54,7 @@ extern crate rustc_cratesio_shim; pub use rustc_serialize::hex::ToHex; +pub mod svh; pub mod accumulate_vec; pub mod array_vec; pub mod base_n; diff --git a/src/librustc_data_structures/svh.rs b/src/librustc_data_structures/svh.rs new file mode 100644 index 00000000000..94f132562b5 --- /dev/null +++ b/src/librustc_data_structures/svh.rs @@ -0,0 +1,84 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Calculation and management of a Strict Version Hash for crates +//! +//! The SVH is used for incremental compilation to track when HIR +//! nodes have changed between compilations, and also to detect +//! mismatches where we have two versions of the same crate that were +//! compiled from distinct sources. + +use std::fmt; +use std::hash::{Hash, Hasher}; +use serialize::{Encodable, Decodable, Encoder, Decoder}; + +use stable_hasher; + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Svh { + hash: u64, +} + +impl Svh { + /// Create a new `Svh` given the hash. If you actually want to + /// compute the SVH from some HIR, you want the `calculate_svh` + /// function found in `librustc_incremental`. + pub fn new(hash: u64) -> Svh { + Svh { hash: hash } + } + + pub fn as_u64(&self) -> u64 { + self.hash + } + + pub fn to_string(&self) -> String { + format!("{:016x}", self.hash) + } +} + +impl Hash for Svh { + fn hash(&self, state: &mut H) where H: Hasher { + self.hash.to_le().hash(state); + } +} + +impl fmt::Display for Svh { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(&self.to_string()) + } +} + +impl Encodable for Svh { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_u64(self.as_u64().to_le()) + } +} + +impl Decodable for Svh { + fn decode(d: &mut D) -> Result { + d.read_u64() + .map(u64::from_le) + .map(Svh::new) + } +} + +impl stable_hasher::HashStable for Svh { + #[inline] + fn hash_stable( + &self, + ctx: &mut T, + hasher: &mut stable_hasher::StableHasher + ) { + let Svh { + hash + } = *self; + hash.hash_stable(ctx, hasher); + } +} diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 795825f180c..65bc7f3f856 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -114,11 +114,11 @@ //! unsupported file system and emit a warning in that case. This is not yet //! implemented. -use rustc::hir::svh::Svh; use rustc::session::{Session, CrateDisambiguator}; use rustc::util::fs as fs_util; use rustc_data_structures::{flock, base_n}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_data_structures::svh::Svh; use std::fs as std_fs; use std::io; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 62c06aac1df..d3b70933e2c 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -16,7 +16,7 @@ use schema::CrateRoot; use rustc_data_structures::sync::{Lrc, RwLock, Lock}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX}; -use rustc::hir::svh::Svh; +use rustc_data_structures::svh::Svh; use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::DepKind; use rustc::mir::interpret::AllocDecodingState; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 060dddd5343..4926da3b880 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -30,6 +30,7 @@ use rustc::hir::map::{DefKey, DefPath, DefPathHash}; use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::definitions::DefPathTable; use rustc::util::nodemap::DefIdMap; +use rustc_data_structures::svh::Svh; use std::any::Any; use rustc_data_structures::sync::Lrc; @@ -515,7 +516,7 @@ impl CrateStore for cstore::CStore { self.get_crate_data(cnum).root.disambiguator } - fn crate_hash_untracked(&self, cnum: CrateNum) -> hir::svh::Svh + fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh { self.get_crate_data(cnum).root.hash } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index f68bcdd62c6..52777e5f6b9 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -226,7 +226,7 @@ use cstore::{MetadataRef, MetadataBlob}; use creader::Library; use schema::{METADATA_HEADER, rustc_version}; -use rustc::hir::svh::Svh; +use rustc_data_structures::svh::Svh; use rustc::middle::cstore::MetadataLoader; use rustc::session::{config, Session}; use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 894c7cbf683..781652e1985 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -20,6 +20,7 @@ use rustc::mir; use rustc::session::CrateDisambiguator; use rustc::ty::{self, Ty, ReprOptions}; use rustc_target::spec::{PanicStrategy, TargetTriple}; +use rustc_data_structures::svh::Svh; use rustc_serialize as serialize; use syntax::{ast, attr}; @@ -187,7 +188,7 @@ pub struct CrateRoot { pub name: Symbol, pub triple: TargetTriple, pub extra_filename: String, - pub hash: hir::svh::Svh, + pub hash: Svh, pub disambiguator: CrateDisambiguator, pub panic_strategy: PanicStrategy, pub edition: Edition, @@ -223,7 +224,7 @@ pub struct CrateRoot { #[derive(RustcEncodable, RustcDecodable)] pub struct CrateDep { pub name: ast::Name, - pub hash: hir::svh::Svh, + pub hash: Svh, pub kind: DepKind, pub extra_filename: String, } -- cgit 1.4.1-3-g733a5 From ac4439c5b6494963bfbee36e34668f844e703015 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 3 Aug 2018 16:41:30 -0600 Subject: Reuse Hash impls for session data structures --- src/librustc/ich/fingerprint.rs | 9 +------ src/librustc/session/config.rs | 36 +++------------------------ src/librustc/session/mod.rs | 2 +- src/librustc_data_structures/stable_hasher.rs | 11 +++++--- 4 files changed, 13 insertions(+), 45 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index a6e35d78dcb..f00c5a649d2 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -92,14 +92,7 @@ impl stable_hasher::StableHasherResult for Fingerprint { } } -impl stable_hasher::HashStable for Fingerprint { - #[inline] - fn hash_stable(&self, - _: &mut CTX, - hasher: &mut stable_hasher::StableHasher) { - ::std::hash::Hash::hash(self, hasher); - } -} +impl_stable_hash_via_hash!(Fingerprint); impl serialize::UseSpecializedEncodable for Fingerprint { } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index dddf921aec6..ef1052d562e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -16,10 +16,8 @@ use std::str::FromStr; use session::{early_error, early_warn, Session}; use session::search_paths::SearchPaths; -use ich::StableHashingContext; use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel}; use rustc_target::spec::{Target, TargetTriple}; -use rustc_data_structures::stable_hasher::ToStableHashKey; use lint; use middle::cstore; @@ -126,25 +124,7 @@ pub enum OutputType { DepInfo, } - -impl_stable_hash_for!(enum self::OutputType { - Bitcode, - Assembly, - LlvmAssembly, - Mir, - Metadata, - Object, - Exe, - DepInfo -}); - -impl<'a, 'tcx> ToStableHashKey> for OutputType { - type KeyType = OutputType; - #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> Self::KeyType { - *self - } -} +impl_stable_hash_via_hash!(OutputType); impl OutputType { fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool { @@ -233,9 +213,7 @@ impl Default for ErrorOutputType { #[derive(Clone, Hash)] pub struct OutputTypes(BTreeMap>); -impl_stable_hash_for!(tuple_struct self::OutputTypes { - map -}); +impl_stable_hash_via_hash!(OutputTypes); impl OutputTypes { pub fn new(entries: &[(OutputType, Option)]) -> OutputTypes { @@ -512,7 +490,7 @@ impl Input { } } -#[derive(Clone)] +#[derive(Clone, Hash)] pub struct OutputFilenames { pub out_directory: PathBuf, pub out_filestem: String, @@ -521,13 +499,7 @@ pub struct OutputFilenames { pub outputs: OutputTypes, } -impl_stable_hash_for!(struct self::OutputFilenames { - out_directory, - out_filestem, - single_output_file, - extra, - outputs -}); +impl_stable_hash_via_hash!(OutputFilenames); pub const RUST_CGU_EXT: &str = "rcgu"; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 9a3ce50fcbd..6bbb4d9c668 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1235,7 +1235,7 @@ impl From for CrateDisambiguator { } } -impl_stable_hash_for!(tuple_struct CrateDisambiguator { fingerprint }); +impl_stable_hash_via_hash!(CrateDisambiguator); /// Holds data on the current incremental compilation session, if there is one. #[derive(Debug)] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index a8f689e5c81..9f1c7dac119 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -183,13 +183,16 @@ pub trait ToStableHashKey { // Implement HashStable by just calling `Hash::hash()`. This works fine for // self-contained values that don't depend on the hashing context `CTX`. +#[macro_export] macro_rules! impl_stable_hash_via_hash { ($t:ty) => ( - impl HashStable for $t { + impl $crate::stable_hasher::HashStable for $t { #[inline] - fn hash_stable(&self, - _: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable( + &self, + _: &mut CTX, + hasher: &mut $crate::stable_hasher::StableHasher + ) { ::std::hash::Hash::hash(self, hasher); } } -- cgit 1.4.1-3-g733a5 From bd6fe1e7007c110d3afa46a2c0df14eb07df372e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 3 Aug 2018 18:34:23 -0600 Subject: Move Fingerprint to data structures --- src/librustc/ich/fingerprint.rs | 111 ------------------------ src/librustc/ich/mod.rs | 3 +- src/librustc/lib.rs | 1 + src/librustc/session/mod.rs | 2 +- src/librustc_codegen_llvm/back/symbol_export.rs | 2 +- src/librustc_codegen_llvm/debuginfo/metadata.rs | 3 +- src/librustc_data_structures/fingerprint.rs | 111 ++++++++++++++++++++++++ src/librustc_data_structures/lib.rs | 3 +- src/librustc_driver/driver.rs | 2 +- src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/encoder.rs | 2 +- 11 files changed, 122 insertions(+), 120 deletions(-) delete mode 100644 src/librustc/ich/fingerprint.rs create mode 100644 src/librustc_data_structures/fingerprint.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs deleted file mode 100644 index f00c5a649d2..00000000000 --- a/src/librustc/ich/fingerprint.rs +++ /dev/null @@ -1,111 +0,0 @@ -// 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. - -use std::mem; -use rustc_data_structures::stable_hasher; -use serialize; -use serialize::opaque::{EncodeResult, Encoder, Decoder}; - -#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)] -pub struct Fingerprint(u64, u64); - -impl Fingerprint { - - pub const ZERO: Fingerprint = Fingerprint(0, 0); - - #[inline] - pub fn from_smaller_hash(hash: u64) -> Fingerprint { - Fingerprint(hash, hash) - } - - #[inline] - pub fn to_smaller_hash(&self) -> u64 { - self.0 - } - - #[inline] - pub fn as_value(&self) -> (u64, u64) { - (self.0, self.1) - } - - #[inline] - pub fn combine(self, other: Fingerprint) -> Fingerprint { - // See https://stackoverflow.com/a/27952689 on why this function is - // implemented this way. - Fingerprint( - self.0.wrapping_mul(3).wrapping_add(other.0), - self.1.wrapping_mul(3).wrapping_add(other.1) - ) - } - - // Combines two hashes in an order independent way. Make sure this is what - // you want. - #[inline] - pub fn combine_commutative(self, other: Fingerprint) -> Fingerprint { - let a = (self.1 as u128) << 64 | self.0 as u128; - let b = (other.1 as u128) << 64 | other.0 as u128; - - let c = a.wrapping_add(b); - - Fingerprint((c >> 64) as u64, c as u64) - } - - pub fn to_hex(&self) -> String { - format!("{:x}{:x}", self.0, self.1) - } - - pub fn encode_opaque(&self, encoder: &mut Encoder) -> EncodeResult { - let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) }; - - encoder.emit_raw_bytes(&bytes); - Ok(()) - } - - pub fn decode_opaque<'a>(decoder: &mut Decoder<'a>) -> Result { - let mut bytes = [0; 16]; - - decoder.read_raw_bytes(&mut bytes)?; - - let [l, r]: [u64; 2] = unsafe { mem::transmute(bytes) }; - - Ok(Fingerprint(u64::from_le(l), u64::from_le(r))) - } -} - -impl ::std::fmt::Display for Fingerprint { - fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(formatter, "{:x}-{:x}", self.0, self.1) - } -} - -impl stable_hasher::StableHasherResult for Fingerprint { - fn finish(hasher: stable_hasher::StableHasher) -> Self { - let (_0, _1) = hasher.finalize(); - Fingerprint(_0, _1) - } -} - -impl_stable_hash_via_hash!(Fingerprint); - -impl serialize::UseSpecializedEncodable for Fingerprint { } - -impl serialize::UseSpecializedDecodable for Fingerprint { } - -impl serialize::SpecializedEncoder for serialize::opaque::Encoder { - fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { - f.encode_opaque(self) - } -} - -impl<'a> serialize::SpecializedDecoder for serialize::opaque::Decoder<'a> { - fn specialized_decode(&mut self) -> Result { - Fingerprint::decode_opaque(self) - } -} diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index d58eb64c366..dbb9ecaddfd 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -10,11 +10,10 @@ //! ICH - Incremental Compilation Hash -pub use self::fingerprint::Fingerprint; +crate use rustc_data_structures::fingerprint::Fingerprint; pub use self::caching_codemap_view::CachingCodemapView; pub use self::hcx::{StableHashingContextProvider, StableHashingContext, NodeIdHashingMode, hash_stable_trait_impls, compute_ignored_attr_names}; -mod fingerprint; mod caching_codemap_view; mod hcx; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 62f244acc9a..6b00a10eaa3 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -72,6 +72,7 @@ #![feature(in_band_lifetimes)] #![feature(macro_at_most_once_rep)] #![feature(crate_in_paths)] +#![feature(crate_visibility_modifier)] #![recursion_limit="512"] diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 6bbb4d9c668..ece58978c5d 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -12,7 +12,7 @@ pub use self::code_stats::{DataTypeKind, SizeKind, FieldInfo, VariantInfo}; use self::code_stats::CodeStats; use hir::def_id::CrateNum; -use ich::Fingerprint; +use rustc_data_structures::fingerprint::Fingerprint; use ich; use lint; diff --git a/src/librustc_codegen_llvm/back/symbol_export.rs b/src/librustc_codegen_llvm/back/symbol_export.rs index 02434b7be0b..c78d061a39b 100644 --- a/src/librustc_codegen_llvm/back/symbol_export.rs +++ b/src/librustc_codegen_llvm/back/symbol_export.rs @@ -15,7 +15,7 @@ use monomorphize::Instance; use rustc::hir; use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; -use rustc::ich::Fingerprint; +use rustc_data_structures::fingerprint::Fingerprint; use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; use rustc::session::config; use rustc::ty::{TyCtxt, SymbolName}; diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 3ae30e85796..8ee2404e10c 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -28,7 +28,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def::CtorKind; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; -use rustc::ich::{Fingerprint, NodeIdHashingMode}; +use rustc::ich::NodeIdHashingMode; +use rustc_data_structures::fingerprint::Fingerprint; use rustc::ty::Instance; use common::CodegenCx; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; diff --git a/src/librustc_data_structures/fingerprint.rs b/src/librustc_data_structures/fingerprint.rs new file mode 100644 index 00000000000..aa9ddda2b93 --- /dev/null +++ b/src/librustc_data_structures/fingerprint.rs @@ -0,0 +1,111 @@ +// 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. + +use std::mem; +use stable_hasher; +use serialize; +use serialize::opaque::{EncodeResult, Encoder, Decoder}; + +#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)] +pub struct Fingerprint(u64, u64); + +impl Fingerprint { + + pub const ZERO: Fingerprint = Fingerprint(0, 0); + + #[inline] + pub fn from_smaller_hash(hash: u64) -> Fingerprint { + Fingerprint(hash, hash) + } + + #[inline] + pub fn to_smaller_hash(&self) -> u64 { + self.0 + } + + #[inline] + pub fn as_value(&self) -> (u64, u64) { + (self.0, self.1) + } + + #[inline] + pub fn combine(self, other: Fingerprint) -> Fingerprint { + // See https://stackoverflow.com/a/27952689 on why this function is + // implemented this way. + Fingerprint( + self.0.wrapping_mul(3).wrapping_add(other.0), + self.1.wrapping_mul(3).wrapping_add(other.1) + ) + } + + // Combines two hashes in an order independent way. Make sure this is what + // you want. + #[inline] + pub fn combine_commutative(self, other: Fingerprint) -> Fingerprint { + let a = (self.1 as u128) << 64 | self.0 as u128; + let b = (other.1 as u128) << 64 | other.0 as u128; + + let c = a.wrapping_add(b); + + Fingerprint((c >> 64) as u64, c as u64) + } + + pub fn to_hex(&self) -> String { + format!("{:x}{:x}", self.0, self.1) + } + + pub fn encode_opaque(&self, encoder: &mut Encoder) -> EncodeResult { + let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) }; + + encoder.emit_raw_bytes(&bytes); + Ok(()) + } + + pub fn decode_opaque<'a>(decoder: &mut Decoder<'a>) -> Result { + let mut bytes = [0; 16]; + + decoder.read_raw_bytes(&mut bytes)?; + + let [l, r]: [u64; 2] = unsafe { mem::transmute(bytes) }; + + Ok(Fingerprint(u64::from_le(l), u64::from_le(r))) + } +} + +impl ::std::fmt::Display for Fingerprint { + fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(formatter, "{:x}-{:x}", self.0, self.1) + } +} + +impl stable_hasher::StableHasherResult for Fingerprint { + fn finish(hasher: stable_hasher::StableHasher) -> Self { + let (_0, _1) = hasher.finalize(); + Fingerprint(_0, _1) + } +} + +impl_stable_hash_via_hash!(Fingerprint); + +impl serialize::UseSpecializedEncodable for Fingerprint { } + +impl serialize::UseSpecializedDecodable for Fingerprint { } + +impl serialize::SpecializedEncoder for serialize::opaque::Encoder { + fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { + f.encode_opaque(self) + } +} + +impl<'a> serialize::SpecializedDecoder for serialize::opaque::Decoder<'a> { + fn specialized_decode(&mut self) -> Result { + Fingerprint::decode_opaque(self) + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index b8c21afc386..3aa15f472a2 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -73,13 +73,14 @@ pub mod small_vec; pub mod snapshot_map; pub use ena::snapshot_vec; pub mod sorted_map; -pub mod stable_hasher; +#[macro_use] pub mod stable_hasher; pub mod sync; pub mod tiny_list; pub mod transitive_relation; pub mod tuple_slice; pub use ena::unify; pub mod work_queue; +pub mod fingerprint; pub struct OnDrop(pub F); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 805a5ecd991..b6e03b66510 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -11,7 +11,7 @@ use rustc::dep_graph::DepGraph; use rustc::hir::{self, map as hir_map}; use rustc::hir::lowering::lower_crate; -use rustc::ich::Fingerprint; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::StableHasher; use rustc_mir as mir; use rustc::session::{CompileResult, CrateDisambiguator, Session}; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5121b682d36..33d4cf26c03 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -22,7 +22,7 @@ use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId}; -use rustc::ich::Fingerprint; +use rustc_data_structures::fingerprint::Fingerprint; use rustc::middle::lang_items; use rustc::mir::{self, interpret}; use rustc::mir::interpret::AllocDecodingSession; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 96d6c5b75f4..7c445cb715e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -18,7 +18,7 @@ use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, use rustc::hir::def::CtorKind; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, LOCAL_CRATE}; use rustc::hir::map::definitions::DefPathTable; -use rustc::ich::Fingerprint; +use rustc_data_structures::fingerprint::Fingerprint; use rustc::middle::dependency_format::Linkage; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel, metadata_symbol_name}; -- cgit 1.4.1-3-g733a5 From ffdac5d592194e7026d3e5fc03bce896c3086cd7 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 9 Aug 2018 16:57:55 +0200 Subject: Make SnapshotMap::{commit, rollback_to} take references --- src/librustc/infer/mod.rs | 2 +- src/librustc/traits/project.rs | 6 +++--- src/librustc_data_structures/snapshot_map/mod.rs | 10 +++++----- src/librustc_data_structures/snapshot_map/test.rs | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 0b84c6a0aa7..eed6215150f 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -709,7 +709,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.projection_cache .borrow_mut() - .commit(projection_cache_snapshot); + .commit(&projection_cache_snapshot); self.type_variables .borrow_mut() .commit(type_snapshot); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 1ce60d8f055..5a95b27e93c 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1668,15 +1668,15 @@ impl<'tcx> ProjectionCache<'tcx> { } pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.rollback_to(snapshot.snapshot); + self.map.rollback_to(&snapshot.snapshot); } pub fn rollback_skolemized(&mut self, snapshot: &ProjectionCacheSnapshot) { self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_skol()); } - pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.commit(snapshot.snapshot); + pub fn commit(&mut self, snapshot: &ProjectionCacheSnapshot) { + self.map.commit(&snapshot.snapshot); } /// Try to start normalize `key`; returns an error if diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index 6ee8c3579f5..5030bf98dff 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -92,7 +92,7 @@ impl SnapshotMap pub fn snapshot(&mut self) -> Snapshot { self.undo_log.push(UndoLog::OpenSnapshot); let len = self.undo_log.len() - 1; - Snapshot { len: len } + Snapshot { len } } fn assert_open_snapshot(&self, snapshot: &Snapshot) { @@ -103,8 +103,8 @@ impl SnapshotMap }); } - pub fn commit(&mut self, snapshot: Snapshot) { - self.assert_open_snapshot(&snapshot); + pub fn commit(&mut self, snapshot: &Snapshot) { + self.assert_open_snapshot(snapshot); if snapshot.len == 0 { // The root snapshot. self.undo_log.truncate(0); @@ -135,8 +135,8 @@ impl SnapshotMap } } - pub fn rollback_to(&mut self, snapshot: Snapshot) { - self.assert_open_snapshot(&snapshot); + pub fn rollback_to(&mut self, snapshot: &Snapshot) { + self.assert_open_snapshot(snapshot); while self.undo_log.len() > snapshot.len + 1 { let entry = self.undo_log.pop().unwrap(); self.reverse(entry); diff --git a/src/librustc_data_structures/snapshot_map/test.rs b/src/librustc_data_structures/snapshot_map/test.rs index 4114082839b..b163e0fe420 100644 --- a/src/librustc_data_structures/snapshot_map/test.rs +++ b/src/librustc_data_structures/snapshot_map/test.rs @@ -20,7 +20,7 @@ fn basic() { map.insert(44, "fourty-four"); assert_eq!(map[&44], "fourty-four"); assert_eq!(map.get(&33), None); - map.rollback_to(snapshot); + map.rollback_to(&snapshot); assert_eq!(map[&22], "twenty-two"); assert_eq!(map.get(&33), None); assert_eq!(map.get(&44), None); @@ -33,7 +33,7 @@ fn out_of_order() { map.insert(22, "twenty-two"); let snapshot1 = map.snapshot(); let _snapshot2 = map.snapshot(); - map.rollback_to(snapshot1); + map.rollback_to(&snapshot1); } #[test] @@ -43,8 +43,8 @@ fn nested_commit_then_rollback() { let snapshot1 = map.snapshot(); let snapshot2 = map.snapshot(); map.insert(22, "thirty-three"); - map.commit(snapshot2); + map.commit(&snapshot2); assert_eq!(map[&22], "thirty-three"); - map.rollback_to(snapshot1); + map.rollback_to(&snapshot1); assert_eq!(map[&22], "twenty-two"); } -- cgit 1.4.1-3-g733a5 From 160187937d679d78bfc36aa39c3cb36cc5024012 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 9 Aug 2018 16:59:10 +0200 Subject: Change transmute()s in IdxSet::{from_slice, from_slice_mut} to casts --- src/librustc_data_structures/indexed_set.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 2e95a45479c..46d6c65101a 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -59,10 +59,6 @@ impl rustc_serialize::Decodable for IdxSetBuf { // pnkfelix wants to have this be `IdxSet([Word]) and then pass // around `&mut IdxSet` or `&IdxSet`. -// -// WARNING: Mapping a `&IdxSetBuf` to `&IdxSet` (at least today) -// requires a transmute relying on representation guarantees that may -// not hold in the future. /// Represents a set (or packed family of sets), of some element type /// E, where each E is identified by some unique index type `T`. @@ -134,11 +130,11 @@ impl IdxSetBuf { impl IdxSet { unsafe fn from_slice(s: &[Word]) -> &Self { - mem::transmute(s) // (see above WARNING) + &*(s as *const [Word] as *const Self) } unsafe fn from_slice_mut(s: &mut [Word]) -> &mut Self { - mem::transmute(s) // (see above WARNING) + &mut *(s as *mut [Word] as *mut Self) } } -- cgit 1.4.1-3-g733a5 From 94c38568048b579c5a29768a8d4bacb8c9d687e1 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 9 Aug 2018 17:00:14 +0200 Subject: A few cleanups for rustc_data_structures --- src/librustc_data_structures/base_n.rs | 5 +++-- src/librustc_data_structures/bitslice.rs | 5 +++-- src/librustc_data_structures/bitvec.rs | 5 +++-- src/librustc_data_structures/flock.rs | 4 ++-- src/librustc_data_structures/graph/dominators/mod.rs | 3 ++- src/librustc_data_structures/graph/implementation/mod.rs | 8 ++++---- src/librustc_data_structures/indexed_set.rs | 1 + src/librustc_data_structures/obligation_forest/mod.rs | 2 +- src/librustc_data_structures/tiny_list.rs | 3 ++- src/librustc_data_structures/transitive_relation.rs | 15 ++++++--------- 10 files changed, 27 insertions(+), 24 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/base_n.rs b/src/librustc_data_structures/base_n.rs index d333b6393b9..d3b47daa5b4 100644 --- a/src/librustc_data_structures/base_n.rs +++ b/src/librustc_data_structures/base_n.rs @@ -17,7 +17,7 @@ pub const MAX_BASE: usize = 64; pub const ALPHANUMERIC_ONLY: usize = 62; pub const CASE_INSENSITIVE: usize = 36; -const BASE_64: &'static [u8; MAX_BASE as usize] = +const BASE_64: &[u8; MAX_BASE as usize] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$"; #[inline] @@ -37,7 +37,8 @@ pub fn push_str(mut n: u128, base: usize, output: &mut String) { break; } } - &mut s[0..index].reverse(); + s[0..index].reverse(); + output.push_str(str::from_utf8(&s[0..index]).unwrap()); } diff --git a/src/librustc_data_structures/bitslice.rs b/src/librustc_data_structures/bitslice.rs index b8f191c2f57..a63033c4365 100644 --- a/src/librustc_data_structures/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -75,7 +75,7 @@ fn bit_lookup(bit: usize) -> BitLookup { let word = bit / word_bits; let bit_in_word = bit % word_bits; let bit_mask = 1 << bit_in_word; - BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask } + BitLookup { word, bit_in_word, bit_mask } } pub fn bits_to_string(words: &[Word], bits: usize) -> String { @@ -105,7 +105,8 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String { sep = '|'; } result.push(']'); - return result + + result } #[inline] diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 6e8a45d0342..49ab3e58812 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -196,7 +196,8 @@ impl<'a, C: Idx> Iterator for BitIter<'a, C> { self.current >>= offset; self.current >>= 1; // shift otherwise overflows for 0b1000_0000_…_0000 self.idx += offset + 1; - return Some(C::new(self.idx - 1)); + + Some(C::new(self.idx - 1)) } fn size_hint(&self) -> (usize, Option) { @@ -299,7 +300,7 @@ impl BitMatrix { let v1 = vector[write_index]; let v2 = v1 | vector[read_index]; vector[write_index] = v2; - changed = changed | (v1 != v2); + changed |= v1 != v2; } changed } diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index ff1ebb11b72..3f248dadb66 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -254,8 +254,8 @@ mod imp { type ULONG_PTR = usize; type LPOVERLAPPED = *mut OVERLAPPED; - const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002; - const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001; + const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x0000_0002; + const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x0000_0001; const FILE_SHARE_DELETE: DWORD = 0x4; const FILE_SHARE_READ: DWORD = 0x1; diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs index d134fad2855..e54147cbe7c 100644 --- a/src/librustc_data_structures/graph/dominators/mod.rs +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -107,7 +107,8 @@ fn intersect( node2 = immediate_dominators[node2].unwrap(); } } - return node1; + + node1 } #[derive(Clone, Debug)] diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs index cf9403db658..baac7565868 100644 --- a/src/librustc_data_structures/graph/implementation/mod.rs +++ b/src/librustc_data_structures/graph/implementation/mod.rs @@ -90,7 +90,7 @@ pub const INCOMING: Direction = Direction { repr: 1 }; impl NodeIndex { /// Returns unique id (unique with respect to the graph holding associated node). - pub fn node_id(&self) -> usize { + pub fn node_id(self) -> usize { self.0 } } @@ -187,7 +187,7 @@ impl Graph { self.nodes[source.0].first_edge[OUTGOING.repr] = idx; self.nodes[target.0].first_edge[INCOMING.repr] = idx; - return idx; + idx } pub fn edge(&self, idx: EdgeIndex) -> &Edge { @@ -261,8 +261,8 @@ impl Graph { DepthFirstTraversal::with_start_node(self, start, direction) } - pub fn nodes_in_postorder<'a>( - &'a self, + pub fn nodes_in_postorder( + &self, direction: Direction, entry_node: NodeIndex, ) -> Vec { diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 46d6c65101a..340fe057096 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -65,6 +65,7 @@ impl rustc_serialize::Decodable for IdxSetBuf { /// /// In other words, `T` is the type used to index into the bitslice /// this type uses to represent the set of object it holds. +#[repr(transparent)] pub struct IdxSet { _pd: PhantomData, bits: [Word], diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 0d6cf260dcd..7ef88852685 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -573,7 +573,7 @@ impl ObligationForest { } let mut kill_list = vec![]; - for (predicate, index) in self.waiting_cache.iter_mut() { + for (predicate, index) in &mut self.waiting_cache { let new_index = node_rewrites[index.get()]; if new_index >= nodes_len { kill_list.push(predicate.clone()); diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index c12fc22baf0..e1bfdf35b27 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -107,7 +107,8 @@ impl Element { }; self.next = new_next; - return true + + true } fn len(&self) -> usize { diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index a8124fb7c5b..18a1e9129b3 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -77,7 +77,7 @@ impl TransitiveRelation { .. } = self; - map.entry(a.clone()) + *map.entry(a.clone()) .or_insert_with(|| { elements.push(a); @@ -86,7 +86,6 @@ impl TransitiveRelation { Index(elements.len() - 1) }) - .clone() } /// Applies the (partial) function to each edge and returns a new @@ -98,14 +97,12 @@ impl TransitiveRelation { { let mut result = TransitiveRelation::new(); for edge in &self.edges { - let r = f(&self.elements[edge.source.0]).and_then(|source| { + f(&self.elements[edge.source.0]).and_then(|source| { f(&self.elements[edge.target.0]).and_then(|target| { - Some(result.add(source, target)) + result.add(source, target); + Some(()) }) - }); - if r.is_none() { - return None; - } + })?; } Some(result) } @@ -372,7 +369,7 @@ impl TransitiveRelation { let mut changed = true; while changed { changed = false; - for edge in self.edges.iter() { + for edge in &self.edges { // add an edge from S -> T changed |= matrix.add(edge.source.0, edge.target.0); -- cgit 1.4.1-3-g733a5 From ef34a16c611419a1b3b3637dee5b97c4ccef1d03 Mon Sep 17 00:00:00 2001 From: memoryruins Date: Thu, 9 Aug 2018 17:31:15 -0400 Subject: [nll] librustc_data_structures: remove unused mut annotation in test --- src/librustc_data_structures/indexed_set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 2e95a45479c..09c734fc01b 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -326,7 +326,7 @@ fn test_set_up_to() { #[test] fn test_new_filled() { for i in 0..128 { - let mut idx_buf = IdxSetBuf::new_filled(i); + let idx_buf = IdxSetBuf::new_filled(i); let elems: Vec = idx_buf.iter().collect(); let expected: Vec = (0..i).collect(); assert_eq!(elems, expected); -- cgit 1.4.1-3-g733a5 From 9585c5dc1fa3cef34ebdc5a5d39af88db60c6f15 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 7 Aug 2018 16:03:57 +0200 Subject: Introduce const_cstr!() macro and use it where applicable. --- src/librustc_codegen_llvm/attributes.rs | 14 +++------ src/librustc_codegen_llvm/base.rs | 4 +-- src/librustc_codegen_llvm/builder.rs | 6 ++-- src/librustc_codegen_llvm/consts.rs | 2 +- src/librustc_codegen_llvm/debuginfo/metadata.rs | 4 +-- src/librustc_data_structures/const_cstr.rs | 42 +++++++++++++++++++++++++ src/librustc_data_structures/lib.rs | 1 + 7 files changed, 56 insertions(+), 17 deletions(-) create mode 100644 src/librustc_data_structures/const_cstr.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 714e8914e48..74f7e6f2ce7 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -9,7 +9,7 @@ // except according to those terms. //! Set and unset common attributes on LLVM values. -use std::ffi::{CStr, CString}; +use std::ffi::CString; use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; @@ -75,7 +75,7 @@ pub fn set_frame_pointer_elimination(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) if cx.sess().must_not_eliminate_frame_pointers() { llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, - cstr("no-frame-pointer-elim\0"), cstr("true\0")); + const_cstr!("no-frame-pointer-elim"), const_cstr!("true")); } } @@ -108,7 +108,7 @@ pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // This is defined in the `compiler-builtins` crate for each architecture. llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, - cstr("probe-stack\0"), cstr("__rust_probestack\0")); + const_cstr!("probe-stack"), const_cstr!("__rust_probestack")); } pub fn llvm_target_features(sess: &Session) -> impl Iterator { @@ -202,7 +202,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: DefId) { let val = CString::new(features).unwrap(); llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, - cstr("target-features\0"), &val); + const_cstr!("target-features"), &val); } // Note that currently the `wasm-import-module` doesn't do anything, but @@ -213,17 +213,13 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: DefId) { llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, - cstr("wasm-import-module\0"), + const_cstr!("wasm-import-module"), &module, ); } } } -fn cstr(s: &'static str) -> &CStr { - CStr::from_bytes_with_nul(s.as_bytes()).expect("null-terminated string") -} - pub fn provide(providers: &mut Providers) { providers.target_features_whitelist = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 54ff5d219b3..4415adc27d6 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -1255,8 +1255,8 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Create the llvm.used variable // This variable has type [N x i8*] and is stored in the llvm.metadata section if !cx.used_statics.borrow().is_empty() { - let name = CString::new("llvm.used").unwrap(); - let section = CString::new("llvm.metadata").unwrap(); + let name = const_cstr!("llvm.used"); + let section = const_cstr!("llvm.metadata"); let array = C_array(Type::i8(&cx).ptr_to(), &*cx.used_statics.borrow()); unsafe { diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index b174cd8c7ac..bc82886714a 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -975,7 +975,7 @@ impl Builder<'a, 'll, 'tcx> { parent: Option<&'ll Value>, args: &[&'ll Value]) -> &'ll Value { self.count_insn("cleanuppad"); - let name = CString::new("cleanuppad").unwrap(); + let name = const_cstr!("cleanuppad"); let ret = unsafe { llvm::LLVMRustBuildCleanupPad(self.llbuilder, parent, @@ -1001,7 +1001,7 @@ impl Builder<'a, 'll, 'tcx> { parent: &'ll Value, args: &[&'ll Value]) -> &'ll Value { self.count_insn("catchpad"); - let name = CString::new("catchpad").unwrap(); + let name = const_cstr!("catchpad"); let ret = unsafe { llvm::LLVMRustBuildCatchPad(self.llbuilder, parent, args.len() as c_uint, args.as_ptr(), @@ -1025,7 +1025,7 @@ impl Builder<'a, 'll, 'tcx> { num_handlers: usize, ) -> &'ll Value { self.count_insn("catchswitch"); - let name = CString::new("catchswitch").unwrap(); + let name = const_cstr!("catchswitch"); let ret = unsafe { llvm::LLVMRustBuildCatchSwitch(self.llbuilder, parent, unwind, num_handlers as c_uint, diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index fafc0e72322..5501e915976 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -328,7 +328,7 @@ pub fn codegen_static<'a, 'tcx>( } else { // If we created the global with the wrong type, // correct the type. - let empty_string = CString::new("").unwrap(); + let empty_string = const_cstr!(""); let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g)); let name_string = CString::new(name_str_ref.to_bytes()).unwrap(); llvm::LLVMSetValueName(g, empty_string.as_ptr()); diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 8ee2404e10c..3bd1a1519b6 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -883,7 +883,7 @@ pub fn compile_unit_metadata(tcx: TyCtxt, gcov_cu_info.as_ptr(), gcov_cu_info.len() as c_uint); - let llvm_gcov_ident = CString::new("llvm.gcov").unwrap(); + let llvm_gcov_ident = const_cstr!("llvm.gcov"); llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, llvm_gcov_ident.as_ptr(), gcov_metadata); @@ -1780,7 +1780,7 @@ pub fn create_vtable_metadata( // later on in llvm/lib/IR/Value.cpp. let empty_array = create_DIArray(DIB(cx), &[]); - let name = CString::new("vtable").unwrap(); + let name = const_cstr!("vtable"); // Create a new one each time. We don't want metadata caching // here, because each vtable will refer to a unique containing diff --git a/src/librustc_data_structures/const_cstr.rs b/src/librustc_data_structures/const_cstr.rs new file mode 100644 index 00000000000..4589d973b6a --- /dev/null +++ b/src/librustc_data_structures/const_cstr.rs @@ -0,0 +1,42 @@ +// Copyright 2018 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. + +/// This macro creates a zero-overhead &CStr by adding a NUL terminator to +/// the string literal passed into it at compile-time. Use it like: +/// +/// ``` +/// let some_const_cstr = const_cstr!("abc"); +/// ``` +/// +/// The above is roughly equivalent to: +/// +/// ``` +/// let some_const_cstr = CStr::from_bytes_with_nul(b"abc\0").unwrap() +/// ``` +/// +/// Note that macro only checks the string literal for internal NULs if +/// debug-assertions are enabled in order to avoid runtime overhead in release +/// builds. +#[macro_export] +macro_rules! const_cstr { + ($s:expr) => ({ + use std::ffi::CStr; + + let str_plus_nul = concat!($s, "\0"); + + if cfg!(debug_assertions) { + CStr::from_bytes_with_nul(str_plus_nul.as_bytes()).unwrap() + } else { + unsafe { + CStr::from_bytes_with_nul_unchecked(str_plus_nul.as_bytes()) + } + } + }) +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 3aa15f472a2..bd11a2977ff 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -60,6 +60,7 @@ pub mod array_vec; pub mod base_n; pub mod bitslice; pub mod bitvec; +pub mod const_cstr; pub mod flock; pub mod fx; pub mod graph; -- cgit 1.4.1-3-g733a5 From 88d84b38f19eff3c25ec88931f04bf2640edf2b5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 7 Aug 2018 16:04:34 +0200 Subject: Introduce SmallCStr and use it where applicable. --- src/librustc_codegen_llvm/attributes.rs | 2 +- src/librustc_codegen_llvm/back/write.rs | 10 +- src/librustc_codegen_llvm/base.rs | 5 +- src/librustc_codegen_llvm/builder.rs | 8 +- src/librustc_codegen_llvm/context.rs | 10 +- src/librustc_codegen_llvm/debuginfo/metadata.rs | 74 +++++++------ src/librustc_codegen_llvm/debuginfo/mod.rs | 7 +- src/librustc_codegen_llvm/debuginfo/namespace.rs | 4 +- src/librustc_codegen_llvm/declare.rs | 14 +-- src/librustc_codegen_llvm/llvm/mod.rs | 5 +- src/librustc_codegen_llvm/type_.rs | 4 +- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/small_c_str.rs | 131 +++++++++++++++++++++++ 13 files changed, 200 insertions(+), 75 deletions(-) create mode 100644 src/librustc_data_structures/small_c_str.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 74f7e6f2ce7..816242129f3 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -128,7 +128,7 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, - cstr("target-cpu\0"), + const_cstr!("target-cpu"), target_cpu.as_c_str()); } diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index cdfa874b177..ebe8b797414 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -31,6 +31,7 @@ use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::ty::TyCtxt; use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passes_entry}; use rustc_fs_util::{path2cstr, link_or_copy}; +use rustc_data_structures::small_c_str::SmallCStr; use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; use errors::emitter::{Emitter}; use syntax::attr; @@ -170,11 +171,8 @@ pub fn target_machine_factory(sess: &Session, find_features: bool) let singlethread = sess.target.target.options.singlethread; - let triple = &sess.target.target.llvm_target; - - let triple = CString::new(triple.as_bytes()).unwrap(); - let cpu = sess.target_cpu(); - let cpu = CString::new(cpu.as_bytes()).unwrap(); + let triple = SmallCStr::new(&sess.target.target.llvm_target); + let cpu = SmallCStr::new(sess.target_cpu()); let features = attributes::llvm_target_features(sess) .collect::>() .join(","); @@ -522,7 +520,7 @@ unsafe fn optimize(cgcx: &CodegenContext, // If we're verifying or linting, add them to the function pass // manager. let addpass = |pass_name: &str| { - let pass_name = CString::new(pass_name).unwrap(); + let pass_name = SmallCStr::new(pass_name); let pass = match llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()) { Some(pass) => pass, None => return false, diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 4415adc27d6..7ca6a89dd9b 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -73,6 +73,7 @@ use type_::Type; use type_of::LayoutLlvmExt; use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; +use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::sync::Lrc; use std::any::Any; @@ -533,7 +534,7 @@ pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) { None => return, }; unsafe { - let buf = CString::new(sect.as_str().as_bytes()).unwrap(); + let buf = SmallCStr::new(§.as_str()); llvm::LLVMSetSection(llval, buf.as_ptr()); } } @@ -681,7 +682,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, unsafe { llvm::LLVMSetInitializer(llglobal, llconst); let section_name = metadata::metadata_section_name(&tcx.sess.target.target); - let name = CString::new(section_name).unwrap(); + let name = SmallCStr::new(section_name); llvm::LLVMSetSection(llglobal, name.as_ptr()); // Also generate a .section directive to force no diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index bc82886714a..b0f88bd4189 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -18,9 +18,9 @@ use libc::{c_uint, c_char}; use rustc::ty::TyCtxt; use rustc::ty::layout::{Align, Size}; use rustc::session::{config, Session}; +use rustc_data_structures::small_c_str::SmallCStr; use std::borrow::Cow; -use std::ffi::CString; use std::ops::Range; use std::ptr; @@ -58,7 +58,7 @@ impl Builder<'a, 'll, 'tcx> { pub fn new_block<'b>(cx: &'a CodegenCx<'ll, 'tcx>, llfn: &'ll Value, name: &'b str) -> Self { let bx = Builder::with_cx(cx); let llbb = unsafe { - let name = CString::new(name).unwrap(); + let name = SmallCStr::new(name); llvm::LLVMAppendBasicBlockInContext( cx.llcx, llfn, @@ -118,7 +118,7 @@ impl Builder<'a, 'll, 'tcx> { } pub fn set_value_name(&self, value: &'ll Value, name: &str) { - let cname = CString::new(name.as_bytes()).unwrap(); + let cname = SmallCStr::new(name); unsafe { llvm::LLVMSetValueName(value, cname.as_ptr()); } @@ -436,7 +436,7 @@ impl Builder<'a, 'll, 'tcx> { let alloca = if name.is_empty() { llvm::LLVMBuildAlloca(self.llbuilder, ty, noname()) } else { - let name = CString::new(name).unwrap(); + let name = SmallCStr::new(name); llvm::LLVMBuildAlloca(self.llbuilder, ty, name.as_ptr()) }; diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 7a308bb6e88..781f8ebbb78 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -26,6 +26,7 @@ use type_::Type; use type_of::PointeeInfo; use rustc_data_structures::base_n; +use rustc_data_structures::small_c_str::SmallCStr; use rustc::mir::mono::Stats; use rustc::session::config::{self, DebugInfo}; use rustc::session::Session; @@ -34,7 +35,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; use rustc_target::spec::{HasTargetSpec, Target}; -use std::ffi::{CStr, CString}; +use std::ffi::CStr; use std::cell::{Cell, RefCell}; use std::iter; use std::str; @@ -161,7 +162,7 @@ pub unsafe fn create_module( llcx: &'ll llvm::Context, mod_name: &str, ) -> &'ll llvm::Module { - let mod_name = CString::new(mod_name).unwrap(); + let mod_name = SmallCStr::new(mod_name); let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); // Ensure the data-layout values hardcoded remain the defaults. @@ -201,11 +202,10 @@ pub unsafe fn create_module( } } - let data_layout = CString::new(&sess.target.target.data_layout[..]).unwrap(); + let data_layout = SmallCStr::new(&sess.target.target.data_layout); llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); - let llvm_target = sess.target.target.llvm_target.as_bytes(); - let llvm_target = CString::new(llvm_target).unwrap(); + let llvm_target = SmallCStr::new(&sess.target.target.llvm_target); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); if is_pie_binary(sess) { diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 3bd1a1519b6..223fa75723c 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -37,6 +37,7 @@ use rustc::ty::layout::{self, Align, LayoutOf, PrimitiveExt, Size, TyLayout}; use rustc::session::config; use rustc::util::nodemap::FxHashMap; use rustc_fs_util::path2cstr; +use rustc_data_structures::small_c_str::SmallCStr; use libc::{c_uint, c_longlong}; use std::ffi::CString; @@ -274,7 +275,7 @@ impl RecursiveTypeDescription<'ll, 'tcx> { // ... and attach them to the stub to complete it. set_members_of_composite_type(cx, metadata_stub, - &member_descriptions[..]); + member_descriptions); return MetadataCreationResult::new(metadata_stub, true); } } @@ -349,7 +350,7 @@ fn vec_slice_metadata( let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type); let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize); - let member_descriptions = [ + let member_descriptions = vec![ MemberDescription { name: "data_ptr".to_string(), type_metadata: data_ptr_metadata, @@ -374,7 +375,7 @@ fn vec_slice_metadata( slice_ptr_type, &slice_type_name[..], unique_type_id, - &member_descriptions, + member_descriptions, NO_SCOPE_METADATA, file_metadata, span); @@ -460,7 +461,7 @@ fn trait_pointer_metadata( let data_ptr_field = layout.field(cx, 0); let vtable_field = layout.field(cx, 1); - let member_descriptions = [ + let member_descriptions = vec![ MemberDescription { name: "pointer".to_string(), type_metadata: type_metadata(cx, @@ -485,7 +486,7 @@ fn trait_pointer_metadata( trait_object_type, &trait_type_name[..], unique_type_id, - &member_descriptions, + member_descriptions, containing_scope, file_metadata, syntax_pos::DUMMY_SP) @@ -746,8 +747,8 @@ fn file_metadata_raw(cx: &CodegenCx<'ll, '_>, debug!("file_metadata: file_name: {}, directory: {}", file_name, directory); - let file_name = CString::new(file_name).unwrap(); - let directory = CString::new(directory).unwrap(); + let file_name = SmallCStr::new(file_name); + let directory = SmallCStr::new(directory); let file_metadata = unsafe { llvm::LLVMRustDIBuilderCreateFile(DIB(cx), @@ -782,7 +783,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { }; let (size, align) = cx.size_and_align_of(t); - let name = CString::new(name).unwrap(); + let name = SmallCStr::new(name); let ty_metadata = unsafe { llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), @@ -813,7 +814,7 @@ fn pointer_type_metadata( ) -> &'ll DIType { let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); let name = compute_debuginfo_type_name(cx, pointer_type, false); - let name = CString::new(name).unwrap(); + let name = SmallCStr::new(&name); unsafe { llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), @@ -847,9 +848,9 @@ pub fn compile_unit_metadata(tcx: TyCtxt, let producer = format!("clang LLVM (rustc version {})", (option_env!("CFG_VERSION")).expect("CFG_VERSION")); - let name_in_debuginfo = name_in_debuginfo.to_string_lossy().into_owned(); - let name_in_debuginfo = CString::new(name_in_debuginfo).unwrap(); - let work_dir = CString::new(&tcx.sess.working_dir.0.to_string_lossy()[..]).unwrap(); + let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); + let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo); + let work_dir = SmallCStr::new(&tcx.sess.working_dir.0.to_string_lossy()); let producer = CString::new(producer).unwrap(); let flags = "\0"; let split_name = "\0"; @@ -1187,7 +1188,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { set_members_of_composite_type(cx, variant_type_metadata, - &member_descriptions[..]); + member_descriptions); vec![ MemberDescription { name: "".to_string(), @@ -1217,7 +1218,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { set_members_of_composite_type(cx, variant_type_metadata, - &member_descriptions); + member_descriptions); MemberDescription { name: "".to_string(), type_metadata: variant_type_metadata, @@ -1244,7 +1245,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { set_members_of_composite_type(cx, variant_type_metadata, - &variant_member_descriptions[..]); + variant_member_descriptions); // Encode the information about the null variant in the union // member's name. @@ -1416,8 +1417,7 @@ fn prepare_enum_metadata( let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx) .zip(&def.variants) .map(|(discr, v)| { - let token = v.name.as_str(); - let name = CString::new(token.as_bytes()).unwrap(); + let name = SmallCStr::new(&v.name.as_str()); unsafe { Some(llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), @@ -1442,7 +1442,7 @@ fn prepare_enum_metadata( type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP); let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str(); - let name = CString::new(discriminant_name.as_bytes()).unwrap(); + let name = SmallCStr::new(&discriminant_name); let discriminant_type_metadata = unsafe { llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), @@ -1482,10 +1482,10 @@ fn prepare_enum_metadata( let (enum_type_size, enum_type_align) = layout.size_and_align(); - let enum_name = CString::new(enum_name).unwrap(); - let unique_type_id_str = CString::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() - ).unwrap(); + let enum_name = SmallCStr::new(&enum_name); + let unique_type_id_str = SmallCStr::new( + debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id) + ); let enum_metadata = unsafe { llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), @@ -1531,7 +1531,7 @@ fn composite_type_metadata( composite_type: Ty<'tcx>, composite_type_name: &str, composite_type_unique_id: UniqueTypeId, - member_descriptions: &[MemberDescription<'ll>], + member_descriptions: Vec>, containing_scope: Option<&'ll DIScope>, // Ignore source location information as long as it @@ -1555,7 +1555,7 @@ fn composite_type_metadata( fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>, composite_type_metadata: &'ll DICompositeType, - member_descriptions: &[MemberDescription<'ll>]) { + member_descriptions: Vec>) { // In some rare cases LLVM metadata uniquing would lead to an existing type // description being used instead of a new one created in // create_struct_stub. This would cause a hard to trace assertion in @@ -1574,10 +1574,9 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>, } let member_metadata: Vec<_> = member_descriptions - .iter() + .into_iter() .map(|member_description| { - let member_name = member_description.name.as_bytes(); - let member_name = CString::new(member_name).unwrap(); + let member_name = CString::new(member_description.name).unwrap(); unsafe { Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), @@ -1613,10 +1612,10 @@ fn create_struct_stub( ) -> &'ll DICompositeType { let (struct_size, struct_align) = cx.size_and_align_of(struct_type); - let name = CString::new(struct_type_name).unwrap(); - let unique_type_id = CString::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() - ).unwrap(); + let name = SmallCStr::new(struct_type_name); + let unique_type_id = SmallCStr::new( + debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id) + ); let metadata_stub = unsafe { // LLVMRustDIBuilderCreateStructType() wants an empty array. A null // pointer will lead to hard to trace and debug LLVM assertions @@ -1651,10 +1650,10 @@ fn create_union_stub( ) -> &'ll DICompositeType { let (union_size, union_align) = cx.size_and_align_of(union_type); - let name = CString::new(union_type_name).unwrap(); - let unique_type_id = CString::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() - ).unwrap(); + let name = SmallCStr::new(union_type_name); + let unique_type_id = SmallCStr::new( + debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id) + ); let metadata_stub = unsafe { // LLVMRustDIBuilderCreateUnionType() wants an empty array. A null // pointer will lead to hard to trace and debug LLVM assertions @@ -1713,13 +1712,12 @@ pub fn create_global_var_metadata( let is_local_to_unit = is_node_local_to_unit(cx, def_id); let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx); let type_metadata = type_metadata(cx, variable_type, span); - let var_name = tcx.item_name(def_id).to_string(); - let var_name = CString::new(var_name).unwrap(); + let var_name = SmallCStr::new(&tcx.item_name(def_id).as_str()); let linkage_name = if no_mangle { None } else { let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)); - Some(CString::new(linkage_name.to_string()).unwrap()) + Some(SmallCStr::new(&linkage_name.as_str())) }; let global_align = cx.align_of(variable_type); diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index d4fb2549a75..fcb8bc3fe2b 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -34,6 +34,7 @@ use rustc::ty::{self, ParamEnv, Ty, InstanceDef}; use rustc::mir; use rustc::session::config::{self, DebugInfo}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; +use rustc_data_structures::small_c_str::SmallCStr; use value::Value; use libc::c_uint; @@ -265,7 +266,7 @@ pub fn create_function_debug_context( let is_local_to_unit = is_node_local_to_unit(cx, def_id); let function_name = CString::new(name).unwrap(); - let linkage_name = CString::new(linkage_name.to_string()).unwrap(); + let linkage_name = SmallCStr::new(&linkage_name.as_str()); let mut flags = DIFlags::FlagPrototyped; @@ -407,7 +408,7 @@ pub fn create_function_debug_context( let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); - let name = CString::new(name.as_str().as_bytes()).unwrap(); + let name = SmallCStr::new(&name.as_str()); Some(unsafe { Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), @@ -510,7 +511,7 @@ pub fn declare_local( }; let align = cx.align_of(variable_type); - let name = CString::new(variable_name.as_str().as_bytes()).unwrap(); + let name = SmallCStr::new(&variable_name.as_str()); match (variable_access, &[][..]) { (DirectVariable { alloca }, address_operations) | (IndirectVariable {alloca, address_operations}, _) => { diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs index 9f1141a7e7d..06f8a4b131b 100644 --- a/src/librustc_codegen_llvm/debuginfo/namespace.rs +++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs @@ -21,7 +21,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; use common::CodegenCx; -use std::ffi::CString; +use rustc_data_structures::small_c_str::SmallCStr; pub fn mangled_name_of_instance<'a, 'tcx>( cx: &CodegenCx<'a, 'tcx>, @@ -49,7 +49,7 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { data => data.as_interned_str().as_str() }; - let namespace_name = CString::new(namespace_name.as_bytes()).unwrap(); + let namespace_name = SmallCStr::new(&namespace_name); let scope = unsafe { llvm::LLVMRustDIBuilderCreateNameSpace( diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index a0310eecd59..5e743ac51bc 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -25,6 +25,7 @@ use llvm::AttributePlace::Function; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, LayoutOf}; use rustc::session::config::Sanitizer; +use rustc_data_structures::small_c_str::SmallCStr; use rustc_target::spec::PanicStrategy; use abi::{Abi, FnType, FnTypeExt}; use attributes; @@ -33,7 +34,6 @@ use common; use type_::Type; use value::Value; -use std::ffi::CString; /// Declare a global value. /// @@ -41,9 +41,7 @@ use std::ffi::CString; /// return its Value instead. pub fn declare_global(cx: &CodegenCx<'ll, '_>, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); - let namebuf = CString::new(name).unwrap_or_else(|_|{ - bug!("name {:?} contains an interior null byte", name) - }); + let namebuf = SmallCStr::new(name); unsafe { llvm::LLVMRustGetOrInsertGlobal(cx.llmod, namebuf.as_ptr(), ty) } @@ -61,9 +59,7 @@ fn declare_raw_fn( ty: &'ll Type, ) -> &'ll Value { debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); - let namebuf = CString::new(name).unwrap_or_else(|_|{ - bug!("name {:?} contains an interior null byte", name) - }); + let namebuf = SmallCStr::new(name); let llfn = unsafe { llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty) }; @@ -214,9 +210,7 @@ pub fn define_internal_fn( /// Get declared value by name. pub fn get_declared_value(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> { debug!("get_declared_value(name={:?})", name); - let namebuf = CString::new(name).unwrap_or_else(|_|{ - bug!("name {:?} contains an interior null byte", name) - }); + let namebuf = SmallCStr::new(name); unsafe { llvm::LLVMRustGetNamedValue(cx.llmod, namebuf.as_ptr()) } } diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs index 558d2a2bc87..4343c8c184e 100644 --- a/src/librustc_codegen_llvm/llvm/mod.rs +++ b/src/librustc_codegen_llvm/llvm/mod.rs @@ -24,9 +24,10 @@ pub use self::Linkage::*; use std::str::FromStr; use std::string::FromUtf8Error; use std::slice; -use std::ffi::{CString, CStr}; +use std::ffi::CStr; use std::cell::RefCell; use libc::{self, c_uint, c_char, size_t}; +use rustc_data_structures::small_c_str::SmallCStr; pub mod archive_ro; pub mod diagnostic; @@ -264,7 +265,7 @@ pub struct OperandBundleDef<'a> { impl OperandBundleDef<'a> { pub fn new(name: &str, vals: &[&'a Value]) -> Self { - let name = CString::new(name).unwrap(); + let name = SmallCStr::new(name); let def = unsafe { LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint) }; diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs index 9fa7cc46aee..51a233d7916 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/src/librustc_codegen_llvm/type_.rs @@ -19,8 +19,8 @@ use context::CodegenCx; use syntax::ast; use rustc::ty::layout::{self, Align, Size}; +use rustc_data_structures::small_c_str::SmallCStr; -use std::ffi::CString; use std::fmt; use libc::c_uint; @@ -201,7 +201,7 @@ impl Type { } pub fn named_struct(cx: &CodegenCx<'ll, '_>, name: &str) -> &'ll Type { - let name = CString::new(name).unwrap(); + let name = SmallCStr::new(name); unsafe { llvm::LLVMStructCreateNamed(cx.llcx, name.as_ptr()) } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index bd11a2977ff..8a586d8c233 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -70,6 +70,7 @@ pub mod obligation_forest; pub mod owning_ref; pub mod ptr_key; pub mod sip128; +pub mod small_c_str; pub mod small_vec; pub mod snapshot_map; pub use ena::snapshot_vec; diff --git a/src/librustc_data_structures/small_c_str.rs b/src/librustc_data_structures/small_c_str.rs new file mode 100644 index 00000000000..b0ad83e4979 --- /dev/null +++ b/src/librustc_data_structures/small_c_str.rs @@ -0,0 +1,131 @@ +// Copyright 2018 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. + +use std::ffi; +use std::ops::Deref; + +const SIZE: usize = 38; + +/// Like SmallVec but for C strings. +#[derive(Clone)] +pub enum SmallCStr { + OnStack { + data: [u8; SIZE], + len_with_nul: u8, + }, + OnHeap { + data: ffi::CString, + } +} + +impl SmallCStr { + #[inline] + pub fn new(s: &str) -> SmallCStr { + if s.len() < SIZE { + let mut data = [0; SIZE]; + data[.. s.len()].copy_from_slice(s.as_bytes()); + let len_with_nul = s.len() + 1; + + // Make sure once that this is a valid CStr + if let Err(e) = ffi::CStr::from_bytes_with_nul(&data[.. len_with_nul]) { + panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e); + } + + SmallCStr::OnStack { + data, + len_with_nul: len_with_nul as u8, + } + } else { + SmallCStr::OnHeap { + data: ffi::CString::new(s).unwrap() + } + } + } + + #[inline] + pub fn as_c_str(&self) -> &ffi::CStr { + match *self { + SmallCStr::OnStack { ref data, len_with_nul } => { + unsafe { + let slice = &data[.. len_with_nul as usize]; + ffi::CStr::from_bytes_with_nul_unchecked(slice) + } + } + SmallCStr::OnHeap { ref data } => { + data.as_c_str() + } + } + } + + #[inline] + pub fn len_with_nul(&self) -> usize { + match *self { + SmallCStr::OnStack { len_with_nul, .. } => { + len_with_nul as usize + } + SmallCStr::OnHeap { ref data } => { + data.as_bytes_with_nul().len() + } + } + } +} + +impl Deref for SmallCStr { + type Target = ffi::CStr; + + fn deref(&self) -> &ffi::CStr { + self.as_c_str() + } +} + + +#[test] +fn short() { + const TEXT: &str = "abcd"; + let reference = ffi::CString::new(TEXT.to_string()).unwrap(); + + let scs = SmallCStr::new(TEXT); + + assert_eq!(scs.len_with_nul(), TEXT.len() + 1); + assert_eq!(scs.as_c_str(), reference.as_c_str()); + assert!(if let SmallCStr::OnStack { .. } = scs { true } else { false }); +} + +#[test] +fn empty() { + const TEXT: &str = ""; + let reference = ffi::CString::new(TEXT.to_string()).unwrap(); + + let scs = SmallCStr::new(TEXT); + + assert_eq!(scs.len_with_nul(), TEXT.len() + 1); + assert_eq!(scs.as_c_str(), reference.as_c_str()); + assert!(if let SmallCStr::OnStack { .. } = scs { true } else { false }); +} + +#[test] +fn long() { + const TEXT: &str = "01234567890123456789012345678901234567890123456789\ + 01234567890123456789012345678901234567890123456789\ + 01234567890123456789012345678901234567890123456789"; + let reference = ffi::CString::new(TEXT.to_string()).unwrap(); + + let scs = SmallCStr::new(TEXT); + + assert_eq!(scs.len_with_nul(), TEXT.len() + 1); + assert_eq!(scs.as_c_str(), reference.as_c_str()); + assert!(if let SmallCStr::OnHeap { .. } = scs { true } else { false }); +} + +#[test] +#[should_panic] +fn internal_nul() { + let _ = SmallCStr::new("abcd\0def"); +} -- cgit 1.4.1-3-g733a5 From e5e6375352636360add297c1f5a1f37ce71506e9 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Sun, 5 Aug 2018 12:04:56 +0200 Subject: Move SmallVec and ThinVec out of libsyntax --- src/Cargo.lock | 1 + src/librustc/hir/lowering.rs | 25 +++---- src/librustc/hir/mod.rs | 2 +- src/librustc_allocator/Cargo.toml | 1 + src/librustc_allocator/expand.rs | 14 ++-- src/librustc_allocator/lib.rs | 1 + src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/small_vec.rs | 65 +++++++++++++++++ src/librustc_data_structures/thin_vec.rs | 59 ++++++++++++++++ src/librustc_driver/pretty.rs | 10 +-- src/libsyntax/ast.rs | 2 +- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/config.rs | 12 ++-- src/libsyntax/diagnostics/plugin.rs | 6 +- src/libsyntax/ext/base.rs | 57 +++++++-------- src/libsyntax/ext/build.rs | 11 +-- src/libsyntax/ext/expand.rs | 44 ++++++------ src/libsyntax/ext/placeholders.rs | 29 ++++---- src/libsyntax/ext/quote.rs | 7 +- src/libsyntax/ext/source_util.rs | 6 +- src/libsyntax/ext/tt/macro_parser.rs | 14 ++-- src/libsyntax/ext/tt/transcribe.rs | 4 +- src/libsyntax/fold.rs | 37 +++++----- src/libsyntax/lib.rs | 6 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/test.rs | 15 ++-- src/libsyntax/util/move_map.rs | 5 +- src/libsyntax/util/small_vector.rs | 81 ---------------------- src/libsyntax/util/thin_vec.rs | 59 ---------------- src/libsyntax_ext/asm.rs | 4 +- src/libsyntax_ext/concat_idents.rs | 4 +- src/libsyntax_ext/deriving/debug.rs | 4 +- src/libsyntax_ext/deriving/generic/mod.rs | 3 +- src/libsyntax_ext/global_asm.rs | 6 +- .../run-pass-fulldeps/auxiliary/issue-16723.rs | 6 +- .../run-pass-fulldeps/pprust-expr-roundtrip.rs | 3 +- 36 files changed, 304 insertions(+), 304 deletions(-) create mode 100644 src/librustc_data_structures/thin_vec.rs delete mode 100644 src/libsyntax/util/small_vector.rs delete mode 100644 src/libsyntax/util/thin_vec.rs (limited to 'src/librustc_data_structures') diff --git a/src/Cargo.lock b/src/Cargo.lock index 97e0bf0a99b..9465f45dc19 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2049,6 +2049,7 @@ version = "0.0.0" dependencies = [ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", "syntax 0.0.0", diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6b66fd8a2b2..9ae5ab7f8be 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -51,6 +51,8 @@ use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, ELIDED_LIFETIMES_IN_PATHS}; use middle::cstore::CrateStore; use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::small_vec::OneVector; +use rustc_data_structures::thin_vec::ThinVec; use session::Session; use util::common::FN_OUTPUT_NAME; use util::nodemap::{DefIdMap, NodeMap}; @@ -71,7 +73,6 @@ use syntax::std_inject; use syntax::symbol::{keywords, Symbol}; use syntax::tokenstream::{Delimited, TokenStream, TokenTree}; use syntax::parse::token::Token; -use syntax::util::small_vector::SmallVector; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, MultiSpan}; @@ -3136,12 +3137,12 @@ impl<'a> LoweringContext<'a> { &mut self, decl: &FnDecl, header: &FnHeader, - ids: &mut SmallVector, + ids: &mut OneVector, ) { if let Some(id) = header.asyncness.opt_return_id() { ids.push(hir::ItemId { id }); } - struct IdVisitor<'a> { ids: &'a mut SmallVector } + struct IdVisitor<'a> { ids: &'a mut OneVector } impl<'a, 'b> Visitor<'a> for IdVisitor<'b> { fn visit_ty(&mut self, ty: &'a Ty) { match ty.node { @@ -3174,21 +3175,21 @@ impl<'a> LoweringContext<'a> { } } - fn lower_item_id(&mut self, i: &Item) -> SmallVector { + fn lower_item_id(&mut self, i: &Item) -> OneVector { match i.node { ItemKind::Use(ref use_tree) => { - let mut vec = SmallVector::one(hir::ItemId { id: i.id }); + let mut vec = OneVector::one(hir::ItemId { id: i.id }); self.lower_item_id_use_tree(use_tree, i.id, &mut vec); vec } - ItemKind::MacroDef(..) => SmallVector::new(), + ItemKind::MacroDef(..) => OneVector::new(), ItemKind::Fn(ref decl, ref header, ..) => { - let mut ids = SmallVector::one(hir::ItemId { id: i.id }); + let mut ids = OneVector::one(hir::ItemId { id: i.id }); self.lower_impl_trait_ids(decl, header, &mut ids); ids }, ItemKind::Impl(.., None, _, ref items) => { - let mut ids = SmallVector::one(hir::ItemId { id: i.id }); + let mut ids = OneVector::one(hir::ItemId { id: i.id }); for item in items { if let ImplItemKind::Method(ref sig, _) = item.node { self.lower_impl_trait_ids(&sig.decl, &sig.header, &mut ids); @@ -3196,14 +3197,14 @@ impl<'a> LoweringContext<'a> { } ids }, - _ => SmallVector::one(hir::ItemId { id: i.id }), + _ => OneVector::one(hir::ItemId { id: i.id }), } } fn lower_item_id_use_tree(&mut self, tree: &UseTree, base_id: NodeId, - vec: &mut SmallVector) + vec: &mut OneVector) { match tree.kind { UseTreeKind::Nested(ref nested_vec) => for &(ref nested, id) in nested_vec { @@ -4295,8 +4296,8 @@ impl<'a> LoweringContext<'a> { } } - fn lower_stmt(&mut self, s: &Stmt) -> SmallVector { - SmallVector::one(match s.node { + fn lower_stmt(&mut self, s: &Stmt) -> OneVector { + OneVector::one(match s.node { StmtKind::Local(ref l) => Spanned { node: hir::StmtKind::Decl( P(Spanned { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 521499e4766..589f3c9d87c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -33,13 +33,13 @@ use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; -use syntax::util::ThinVec; use syntax::util::parser::ExprPrecedence; use ty::AdtKind; use ty::query::Providers; use rustc_data_structures::indexed_vec; use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope}; +use rustc_data_structures::thin_vec::ThinVec; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; use std::collections::BTreeMap; diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml index 1cbde181caf..83a918f2af8 100644 --- a/src/librustc_allocator/Cargo.toml +++ b/src/librustc_allocator/Cargo.toml @@ -10,6 +10,7 @@ test = false [dependencies] rustc = { path = "../librustc" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 05843852ee0..676dbeeeeb0 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -9,6 +9,7 @@ // except according to those terms. use rustc::middle::allocator::AllocatorKind; +use rustc_data_structures::small_vec::OneVector; use rustc_errors; use syntax::{ ast::{ @@ -28,8 +29,7 @@ use syntax::{ fold::{self, Folder}, parse::ParseSess, ptr::P, - symbol::Symbol, - util::small_vector::SmallVector, + symbol::Symbol }; use syntax_pos::Span; @@ -65,7 +65,7 @@ struct ExpandAllocatorDirectives<'a> { } impl<'a> Folder for ExpandAllocatorDirectives<'a> { - fn fold_item(&mut self, item: P) -> SmallVector> { + fn fold_item(&mut self, item: P) -> OneVector> { debug!("in submodule {}", self.in_submod); let name = if attr::contains_name(&item.attrs, "global_allocator") { @@ -78,20 +78,20 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { _ => { self.handler .span_err(item.span, "allocators must be statics"); - return SmallVector::one(item); + return OneVector::one(item); } } if self.in_submod > 0 { self.handler .span_err(item.span, "`global_allocator` cannot be used in submodules"); - return SmallVector::one(item); + return OneVector::one(item); } if self.found { self.handler .span_err(item.span, "cannot define more than one #[global_allocator]"); - return SmallVector::one(item); + return OneVector::one(item); } self.found = true; @@ -152,7 +152,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap(); // Return the item and new submodule - let mut ret = SmallVector::with_capacity(2); + let mut ret = OneVector::with_capacity(2); ret.push(item); ret.push(module); diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index a920bb0f2b9..d020fe96335 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -13,6 +13,7 @@ #[macro_use] extern crate log; extern crate rustc; +extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_target; extern crate syntax; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 421229a8909..5699512326a 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -79,6 +79,7 @@ pub mod sorted_map; #[macro_use] pub mod stable_hasher; pub mod sync; pub mod tiny_list; +pub mod thin_vec; pub mod transitive_relation; pub mod tuple_slice; pub use ena::unify; diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index e958fd7da61..6f101b20d88 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -29,6 +29,8 @@ use array_vec::Array; pub struct SmallVec(AccumulateVec); +pub type OneVector = SmallVec<[T; 1]>; + impl Clone for SmallVec where A: Array, A::Element: Clone { @@ -227,6 +229,69 @@ mod tests { use super::*; + #[test] + fn test_len() { + let v: OneVector = OneVector::new(); + assert_eq!(0, v.len()); + + assert_eq!(1, OneVector::one(1).len()); + assert_eq!(5, OneVector::many(vec![1, 2, 3, 4, 5]).len()); + } + + #[test] + fn test_push_get() { + let mut v = OneVector::new(); + v.push(1); + assert_eq!(1, v.len()); + assert_eq!(1, v[0]); + v.push(2); + assert_eq!(2, v.len()); + assert_eq!(2, v[1]); + v.push(3); + assert_eq!(3, v.len()); + assert_eq!(3, v[2]); + } + + #[test] + fn test_from_iter() { + let v: OneVector = (vec![1, 2, 3]).into_iter().collect(); + assert_eq!(3, v.len()); + assert_eq!(1, v[0]); + assert_eq!(2, v[1]); + assert_eq!(3, v[2]); + } + + #[test] + fn test_move_iter() { + let v = OneVector::new(); + let v: Vec = v.into_iter().collect(); + assert_eq!(v, Vec::new()); + + let v = OneVector::one(1); + assert_eq!(v.into_iter().collect::>(), [1]); + + let v = OneVector::many(vec![1, 2, 3]); + assert_eq!(v.into_iter().collect::>(), [1, 2, 3]); + } + + #[test] + #[should_panic] + fn test_expect_one_zero() { + let _: isize = OneVector::new().expect_one(""); + } + + #[test] + #[should_panic] + fn test_expect_one_many() { + OneVector::many(vec![1, 2]).expect_one(""); + } + + #[test] + fn test_expect_one_one() { + assert_eq!(1, OneVector::one(1).expect_one("")); + assert_eq!(1, OneVector::many(vec![1]).expect_one("")); + } + #[bench] fn fill_small_vec_1_10_with_cap(b: &mut Bencher) { b.iter(|| { diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs new file mode 100644 index 00000000000..546686b46b8 --- /dev/null +++ b/src/librustc_data_structures/thin_vec.rs @@ -0,0 +1,59 @@ +// 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. + +/// A vector type optimized for cases where this size is usually 0 (c.f. `SmallVector`). +/// The `Option>` wrapping allows us to represent a zero sized vector with `None`, +/// which uses only a single (null) pointer. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ThinVec(Option>>); + +impl ThinVec { + pub fn new() -> Self { + ThinVec(None) + } +} + +impl From> for ThinVec { + fn from(vec: Vec) -> Self { + if vec.is_empty() { + ThinVec(None) + } else { + ThinVec(Some(Box::new(vec))) + } + } +} + +impl Into> for ThinVec { + fn into(self) -> Vec { + match self { + ThinVec(None) => Vec::new(), + ThinVec(Some(vec)) => *vec, + } + } +} + +impl ::std::ops::Deref for ThinVec { + type Target = [T]; + fn deref(&self) -> &[T] { + match *self { + ThinVec(None) => &[], + ThinVec(Some(ref vec)) => vec, + } + } +} + +impl Extend for ThinVec { + fn extend>(&mut self, iter: I) { + match *self { + ThinVec(Some(ref mut vec)) => vec.extend(iter), + ThinVec(None) => *self = iter.into_iter().collect::>().into(), + } + } +} diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 3e74aef9e73..a66392833f6 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -24,6 +24,8 @@ use rustc::session::Session; use rustc::session::config::{Input, OutputFilenames}; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; +use rustc_data_structures::small_vec::OneVector; +use rustc_data_structures::thin_vec::ThinVec; use rustc_metadata::cstore::CStore; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; @@ -33,8 +35,6 @@ use syntax::fold::{self, Folder}; use syntax::print::{pprust}; use syntax::print::pprust::PrintState; use syntax::ptr::P; -use syntax::util::ThinVec; -use syntax::util::small_vector::SmallVector; use syntax_pos::{self, FileName}; use graphviz as dot; @@ -727,7 +727,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { self.run(is_const, |s| fold::noop_fold_item_kind(i, s)) } - fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, i: ast::TraitItem) -> OneVector { let is_const = match i.node { ast::TraitItemKind::Const(..) => true, ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => @@ -737,7 +737,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { self.run(is_const, |s| fold::noop_fold_trait_item(i, s)) } - fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, i: ast::ImplItem) -> OneVector { let is_const = match i.node { ast::ImplItemKind::Const(..) => true, ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => @@ -785,7 +785,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { node: ast::ExprKind::Loop(P(empty_block), None), id: self.sess.next_node_id(), span: syntax_pos::DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); let loop_stmt = ast::Stmt { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6925ed2afb8..919ffcb8d09 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -13,7 +13,6 @@ pub use self::UnsafeSource::*; pub use self::GenericArgs::*; pub use symbol::{Ident, Symbol as Name}; -pub use util::ThinVec; pub use util::parser::ExprPrecedence; use syntax_pos::{Span, DUMMY_SP}; @@ -25,6 +24,7 @@ use ptr::P; use rustc_data_structures::indexed_vec; use rustc_data_structures::indexed_vec::Idx; use symbol::{Symbol, keywords}; +use ThinVec; use tokenstream::{ThinTokenStream, TokenStream}; use serialize::{self, Encoder, Decoder}; diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index b3b173db70b..879f555ba03 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -33,8 +33,8 @@ use parse::{self, ParseSess, PResult}; use parse::token::{self, Token}; use ptr::P; use symbol::Symbol; +use ThinVec; use tokenstream::{TokenStream, TokenTree, Delimited}; -use util::ThinVec; use GLOBALS; use std::iter; diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 33643789139..4fe78bf829a 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -15,9 +15,9 @@ use ast; use codemap::Spanned; use edition::Edition; use parse::{token, ParseSess}; +use OneVector; use ptr::P; -use util::small_vector::SmallVector; /// A folder that strips out items that do not belong in the current configuration. pub struct StripUnconfigured<'a> { @@ -319,22 +319,22 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { Some(P(fold::noop_fold_expr(expr, self))) } - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + fn fold_stmt(&mut self, stmt: ast::Stmt) -> OneVector { match self.configure_stmt(stmt) { Some(stmt) => fold::noop_fold_stmt(stmt, self), - None => return SmallVector::new(), + None => return OneVector::new(), } } - fn fold_item(&mut self, item: P) -> SmallVector> { + fn fold_item(&mut self, item: P) -> OneVector> { fold::noop_fold_item(configure!(self, item), self) } - fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, item: ast::ImplItem) -> OneVector { fold::noop_fold_impl_item(configure!(self, item), self) } - fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, item: ast::TraitItem) -> OneVector { fold::noop_fold_trait_item(configure!(self, item), self) } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 72ce2740190..6a5a2a5e500 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -19,9 +19,9 @@ use ext::base::{ExtCtxt, MacEager, MacResult}; use ext::build::AstBuilder; use parse::token; use ptr::P; +use OneVector; use symbol::{keywords, Symbol}; use tokenstream::{TokenTree}; -use util::small_vector::SmallVector; use diagnostics::metadata::output_metadata; @@ -131,7 +131,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, let sym = Ident::with_empty_ctxt(Symbol::gensym(&format!( "__register_diagnostic_{}", code ))); - MacEager::items(SmallVector::many(vec![ + MacEager::items(OneVector::many(vec![ ecx.item_mod( span, span, @@ -214,7 +214,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, ), ); - MacEager::items(SmallVector::many(vec![ + MacEager::items(OneVector::many(vec![ P(ast::Item { ident: *name, attrs: Vec::new(), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index de391ee4219..482d8c2cf98 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -22,8 +22,9 @@ use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; use parse::token; use ptr::P; +use OneVector; use symbol::{keywords, Ident, Symbol}; -use util::small_vector::SmallVector; +use ThinVec; use std::collections::HashMap; use std::iter; @@ -315,7 +316,7 @@ impl IdentMacroExpander for F // Use a macro because forwarding to a simple function has type system issues macro_rules! make_stmts_default { ($me:expr) => { - $me.make_expr().map(|e| SmallVector::one(ast::Stmt { + $me.make_expr().map(|e| OneVector::one(ast::Stmt { id: ast::DUMMY_NODE_ID, span: e.span, node: ast::StmtKind::Expr(e), @@ -331,22 +332,22 @@ pub trait MacResult { None } /// Create zero or more items. - fn make_items(self: Box) -> Option>> { + fn make_items(self: Box) -> Option>> { None } /// Create zero or more impl items. - fn make_impl_items(self: Box) -> Option> { + fn make_impl_items(self: Box) -> Option> { None } /// Create zero or more trait items. - fn make_trait_items(self: Box) -> Option> { + fn make_trait_items(self: Box) -> Option> { None } /// Create zero or more items in an `extern {}` block - fn make_foreign_items(self: Box) -> Option> { None } + fn make_foreign_items(self: Box) -> Option> { None } /// Create a pattern. fn make_pat(self: Box) -> Option> { @@ -357,7 +358,7 @@ pub trait MacResult { /// /// By default this attempts to create an expression statement, /// returning None if that fails. - fn make_stmts(self: Box) -> Option> { + fn make_stmts(self: Box) -> Option> { make_stmts_default!(self) } @@ -393,11 +394,11 @@ macro_rules! make_MacEager { make_MacEager! { expr: P, pat: P, - items: SmallVector>, - impl_items: SmallVector, - trait_items: SmallVector, - foreign_items: SmallVector, - stmts: SmallVector, + items: OneVector>, + impl_items: OneVector, + trait_items: OneVector, + foreign_items: OneVector, + stmts: OneVector, ty: P, } @@ -406,23 +407,23 @@ impl MacResult for MacEager { self.expr } - fn make_items(self: Box) -> Option>> { + fn make_items(self: Box) -> Option>> { self.items } - fn make_impl_items(self: Box) -> Option> { + fn make_impl_items(self: Box) -> Option> { self.impl_items } - fn make_trait_items(self: Box) -> Option> { + fn make_trait_items(self: Box) -> Option> { self.trait_items } - fn make_foreign_items(self: Box) -> Option> { + fn make_foreign_items(self: Box) -> Option> { self.foreign_items } - fn make_stmts(self: Box) -> Option> { + fn make_stmts(self: Box) -> Option> { match self.stmts.as_ref().map_or(0, |s| s.len()) { 0 => make_stmts_default!(self), _ => self.stmts, @@ -482,7 +483,7 @@ impl DummyResult { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(codemap::respan(sp, ast::LitKind::Bool(false)))), span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }) } @@ -513,41 +514,41 @@ impl MacResult for DummyResult { Some(P(DummyResult::raw_pat(self.span))) } - fn make_items(self: Box) -> Option>> { + fn make_items(self: Box) -> Option>> { // this code needs a comment... why not always just return the Some() ? if self.expr_only { None } else { - Some(SmallVector::new()) + Some(OneVector::new()) } } - fn make_impl_items(self: Box) -> Option> { + fn make_impl_items(self: Box) -> Option> { if self.expr_only { None } else { - Some(SmallVector::new()) + Some(OneVector::new()) } } - fn make_trait_items(self: Box) -> Option> { + fn make_trait_items(self: Box) -> Option> { if self.expr_only { None } else { - Some(SmallVector::new()) + Some(OneVector::new()) } } - fn make_foreign_items(self: Box) -> Option> { + fn make_foreign_items(self: Box) -> Option> { if self.expr_only { None } else { - Some(SmallVector::new()) + Some(OneVector::new()) } } - fn make_stmts(self: Box) -> Option> { - Some(SmallVector::one(ast::Stmt { + fn make_stmts(self: Box) -> Option> { + Some(OneVector::one(ast::Stmt { id: ast::DUMMY_NODE_ID, node: ast::StmtKind::Expr(DummyResult::raw_expr(self.span)), span: self.span, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 61356507665..1a17aa3e8fb 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -16,6 +16,7 @@ use codemap::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use ptr::P; use symbol::{Symbol, keywords}; +use ThinVec; // Transitional re-exports so qquote can find the paths it is looking for mod syntax { @@ -519,7 +520,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -547,7 +548,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -564,7 +565,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: None, id: ast::DUMMY_NODE_ID, span, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -603,7 +604,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, node, span, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }) } @@ -678,7 +679,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { expr: e, span, is_shorthand: false, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), } } fn expr_struct(&self, span: Span, path: ast::Path, fields: Vec) -> P { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 12941a85669..f7ea781e021 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -26,12 +26,12 @@ use parse::{DirectoryOwnership, PResult, ParseSess}; use parse::token::{self, Token}; use parse::parser::Parser; use ptr::P; +use OneVector; use symbol::Symbol; use symbol::keywords; use syntax_pos::{Span, DUMMY_SP, FileName}; use syntax_pos::hygiene::ExpnFormat; use tokenstream::{TokenStream, TokenTree}; -use util::small_vector::SmallVector; use visit::{self, Visitor}; use std::collections::HashMap; @@ -131,7 +131,7 @@ macro_rules! ast_fragments { self.expand_fragment(AstFragment::$Kind(ast)).$make_ast() })*)* $($(fn $fold_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy { - self.expand_fragment(AstFragment::$Kind(SmallVector::one(ast_elt))).$make_ast() + self.expand_fragment(AstFragment::$Kind(OneVector::one(ast_elt))).$make_ast() })*)* } @@ -148,15 +148,15 @@ ast_fragments! { Expr(P) { "expression"; one fn fold_expr; fn visit_expr; fn make_expr; } Pat(P) { "pattern"; one fn fold_pat; fn visit_pat; fn make_pat; } Ty(P) { "type"; one fn fold_ty; fn visit_ty; fn make_ty; } - Stmts(SmallVector) { "statement"; many fn fold_stmt; fn visit_stmt; fn make_stmts; } - Items(SmallVector>) { "item"; many fn fold_item; fn visit_item; fn make_items; } - TraitItems(SmallVector) { + Stmts(OneVector) { "statement"; many fn fold_stmt; fn visit_stmt; fn make_stmts; } + Items(OneVector>) { "item"; many fn fold_item; fn visit_item; fn make_items; } + TraitItems(OneVector) { "trait item"; many fn fold_trait_item; fn visit_trait_item; fn make_trait_items; } - ImplItems(SmallVector) { + ImplItems(OneVector) { "impl item"; many fn fold_impl_item; fn visit_impl_item; fn make_impl_items; } - ForeignItems(SmallVector) { + ForeignItems(OneVector) { "foreign item"; many fn fold_foreign_item; fn visit_foreign_item; fn make_foreign_items; } } @@ -279,7 +279,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let orig_mod_span = krate.module.inner; - let krate_item = AstFragment::Items(SmallVector::one(P(ast::Item { + let krate_item = AstFragment::Items(OneVector::one(P(ast::Item { attrs: krate.attrs, span: krate.span, node: ast::ItemKind::Mod(krate.module), @@ -989,28 +989,28 @@ impl<'a> Parser<'a> { -> PResult<'a, AstFragment> { Ok(match kind { AstFragmentKind::Items => { - let mut items = SmallVector::new(); + let mut items = OneVector::new(); while let Some(item) = self.parse_item()? { items.push(item); } AstFragment::Items(items) } AstFragmentKind::TraitItems => { - let mut items = SmallVector::new(); + let mut items = OneVector::new(); while self.token != token::Eof { items.push(self.parse_trait_item(&mut false)?); } AstFragment::TraitItems(items) } AstFragmentKind::ImplItems => { - let mut items = SmallVector::new(); + let mut items = OneVector::new(); while self.token != token::Eof { items.push(self.parse_impl_item(&mut false)?); } AstFragment::ImplItems(items) } AstFragmentKind::ForeignItems => { - let mut items = SmallVector::new(); + let mut items = OneVector::new(); while self.token != token::Eof { if let Some(item) = self.parse_foreign_item()? { items.push(item); @@ -1019,7 +1019,7 @@ impl<'a> Parser<'a> { AstFragment::ForeignItems(items) } AstFragmentKind::Stmts => { - let mut stmts = SmallVector::new(); + let mut stmts = OneVector::new(); while self.token != token::Eof && // won't make progress on a `}` self.token != token::CloseDelim(token::Brace) { @@ -1086,12 +1086,12 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { /// Folds the item allowing tests to be expanded because they are still nameable. /// This should probably only be called with module items - fn fold_nameable(&mut self, item: P) -> SmallVector> { + fn fold_nameable(&mut self, item: P) -> OneVector> { fold::noop_fold_item(item, self) } /// Folds the item but doesn't allow tests to occur within it - fn fold_unnameable(&mut self, item: P) -> SmallVector> { + fn fold_unnameable(&mut self, item: P) -> OneVector> { let was_nameable = mem::replace(&mut self.tests_nameable, false); let items = fold::noop_fold_item(item, self); self.tests_nameable = was_nameable; @@ -1254,10 +1254,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }) } - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + fn fold_stmt(&mut self, stmt: ast::Stmt) -> OneVector { let mut stmt = match self.cfg.configure_stmt(stmt) { Some(stmt) => stmt, - None => return SmallVector::new(), + None => return OneVector::new(), }; // we'll expand attributes on expressions separately @@ -1313,7 +1313,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { result } - fn fold_item(&mut self, item: P) -> SmallVector> { + fn fold_item(&mut self, item: P) -> OneVector> { let item = configure!(self, item); let (attr, traits, mut item) = self.classify_item(item); @@ -1422,7 +1422,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { ui }); - SmallVector::many( + OneVector::many( self.fold_unnameable(item).into_iter() .chain(self.fold_unnameable(use_item))) } else { @@ -1433,7 +1433,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } } - fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, item: ast::TraitItem) -> OneVector { let item = configure!(self, item); let (attr, traits, item) = self.classify_item(item); @@ -1453,7 +1453,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } } - fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, item: ast::ImplItem) -> OneVector { let item = configure!(self, item); let (attr, traits, item) = self.classify_item(item); @@ -1490,7 +1490,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_foreign_item(&mut self, - foreign_item: ast::ForeignItem) -> SmallVector { + foreign_item: ast::ForeignItem) -> OneVector { let (attr, traits, foreign_item) = self.classify_item(foreign_item); if attr.is_some() || !traits.is_empty() { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 968cf508eda..1dc9bae8848 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -16,9 +16,10 @@ use ext::hygiene::Mark; use tokenstream::TokenStream; use fold::*; use ptr::P; +use OneVector; use symbol::keywords; +use ThinVec; use util::move_map::MoveMap; -use util::small_vector::SmallVector; use std::collections::HashMap; @@ -38,31 +39,31 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { let span = DUMMY_SP; let expr_placeholder = || P(ast::Expr { id, span, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), node: ast::ExprKind::Mac(mac_placeholder()), }); match kind { AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), - AstFragmentKind::Items => AstFragment::Items(SmallVector::one(P(ast::Item { + AstFragmentKind::Items => AstFragment::Items(OneVector::one(P(ast::Item { id, span, ident, vis, attrs, node: ast::ItemKind::Mac(mac_placeholder()), tokens: None, }))), - AstFragmentKind::TraitItems => AstFragment::TraitItems(SmallVector::one(ast::TraitItem { + AstFragmentKind::TraitItems => AstFragment::TraitItems(OneVector::one(ast::TraitItem { id, span, ident, attrs, generics, node: ast::TraitItemKind::Macro(mac_placeholder()), tokens: None, })), - AstFragmentKind::ImplItems => AstFragment::ImplItems(SmallVector::one(ast::ImplItem { + AstFragmentKind::ImplItems => AstFragment::ImplItems(OneVector::one(ast::ImplItem { id, span, ident, vis, attrs, generics, node: ast::ImplItemKind::Macro(mac_placeholder()), defaultness: ast::Defaultness::Final, tokens: None, })), AstFragmentKind::ForeignItems => - AstFragment::ForeignItems(SmallVector::one(ast::ForeignItem { + AstFragment::ForeignItems(OneVector::one(ast::ForeignItem { id, span, ident, vis, attrs, node: ast::ForeignItemKind::Macro(mac_placeholder()), })), @@ -72,8 +73,8 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty { id, span, node: ast::TyKind::Mac(mac_placeholder()), })), - AstFragmentKind::Stmts => AstFragment::Stmts(SmallVector::one({ - let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::ThinVec::new())); + AstFragmentKind::Stmts => AstFragment::Stmts(OneVector::one({ + let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ThinVec::new())); ast::Stmt { id, span, node: ast::StmtKind::Mac(mac) } })), } @@ -114,31 +115,31 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { } impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { - fn fold_item(&mut self, item: P) -> SmallVector> { + fn fold_item(&mut self, item: P) -> OneVector> { match item.node { ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), - ast::ItemKind::MacroDef(_) => return SmallVector::one(item), + ast::ItemKind::MacroDef(_) => return OneVector::one(item), _ => {} } noop_fold_item(item, self) } - fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, item: ast::TraitItem) -> OneVector { match item.node { ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(), _ => noop_fold_trait_item(item, self), } } - fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, item: ast::ImplItem) -> OneVector { match item.node { ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(), _ => noop_fold_impl_item(item, self), } } - fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVector { + fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> OneVector { match item.node { ast::ForeignItemKind::Macro(_) => self.remove(item.id).make_foreign_items(), _ => noop_fold_foreign_item(item, self), @@ -159,7 +160,7 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { } } - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + fn fold_stmt(&mut self, stmt: ast::Stmt) -> OneVector { let (style, mut stmts) = match stmt.node { ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()), _ => return noop_fold_stmt(stmt, self), diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 1ace4d4a880..bc891700fc1 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -34,6 +34,7 @@ pub mod rt { use parse::token::{self, Token}; use ptr::P; use symbol::Symbol; + use ThinVec; use tokenstream::{self, TokenTree, TokenStream}; @@ -274,7 +275,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(self.clone())), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }).to_tokens(cx) } } @@ -305,7 +306,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(dummy_spanned(lit))), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); if *self >= 0 { return lit.to_tokens(cx); @@ -314,7 +315,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Unary(ast::UnOp::Neg, lit), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }).to_tokens(cx) } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 0c36c072a03..9b7e0fe1ae5 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -17,9 +17,9 @@ use parse::{token, DirectoryOwnership}; use parse; use print::pprust; use ptr::P; +use OneVector; use symbol::Symbol; use tokenstream; -use util::small_vector::SmallVector; use std::fs::File; use std::io::prelude::*; @@ -111,8 +111,8 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T Some(panictry!(self.p.parse_expr())) } fn make_items(mut self: Box>) - -> Option>> { - let mut ret = SmallVector::new(); + -> Option>> { + let mut ret = OneVector::new(); while self.p.token != token::Eof { match panictry!(self.p.parse_item()) { Some(item) => ret.push(item), diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 3046525b714..82f88d1d864 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -92,9 +92,9 @@ use parse::{Directory, ParseSess}; use parse::parser::{Parser, PathStyle}; use parse::token::{self, DocComment, Nonterminal, Token}; use print::pprust; +use OneVector; use symbol::keywords; use tokenstream::TokenStream; -use util::small_vector::SmallVector; use std::mem; use std::ops::{Deref, DerefMut}; @@ -440,10 +440,10 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// A `ParseResult`. Note that matches are kept track of through the items generated. fn inner_parse_loop<'a>( sess: &ParseSess, - cur_items: &mut SmallVector>, + cur_items: &mut OneVector>, next_items: &mut Vec>, - eof_items: &mut SmallVector>, - bb_items: &mut SmallVector>, + eof_items: &mut OneVector>, + bb_items: &mut OneVector>, token: &Token, span: syntax_pos::Span, ) -> ParseResult<()> { @@ -644,15 +644,15 @@ pub fn parse( // This MatcherPos instance is allocated on the stack. All others -- and // there are frequently *no* others! -- are allocated on the heap. let mut initial = initial_matcher_pos(ms, parser.span.lo()); - let mut cur_items = SmallVector::one(MatcherPosHandle::Ref(&mut initial)); + let mut cur_items = OneVector::one(MatcherPosHandle::Ref(&mut initial)); let mut next_items = Vec::new(); loop { // Matcher positions black-box parsed by parser.rs (`parser`) - let mut bb_items = SmallVector::new(); + let mut bb_items = OneVector::new(); // Matcher positions that would be valid if the macro invocation was over now - let mut eof_items = SmallVector::new(); + let mut eof_items = OneVector::new(); assert!(next_items.is_empty()); // Process `cur_items` until either we have finished the input or we need to get some diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 1cdb6b0e5c9..d451227e77c 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -15,9 +15,9 @@ use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use ext::tt::quoted; use fold::noop_fold_tt; use parse::token::{self, Token, NtTT}; +use OneVector; use syntax_pos::{Span, DUMMY_SP}; use tokenstream::{TokenStream, TokenTree, Delimited}; -use util::small_vector::SmallVector; use std::rc::Rc; use rustc_data_structures::sync::Lrc; @@ -70,7 +70,7 @@ pub fn transcribe(cx: &ExtCtxt, interp: Option>>, src: Vec) -> TokenStream { - let mut stack = SmallVector::one(Frame::new(src)); + let mut stack = OneVector::one(Frame::new(src)); let interpolations = interp.unwrap_or_else(HashMap::new); /* just a convenience */ let mut repeats = Vec::new(); let mut result: Vec = Vec::new(); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9d5982c1e28..3209939d9b1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -24,9 +24,10 @@ use syntax_pos::Span; use codemap::{Spanned, respan}; use parse::token::{self, Token}; use ptr::P; +use OneVector; use symbol::keywords; +use ThinVec; use tokenstream::*; -use util::small_vector::SmallVector; use util::move_map::MoveMap; use rustc_data_structures::sync::Lrc; @@ -60,7 +61,7 @@ pub trait Folder : Sized { noop_fold_use_tree(use_tree, self) } - fn fold_foreign_item(&mut self, ni: ForeignItem) -> SmallVector { + fn fold_foreign_item(&mut self, ni: ForeignItem) -> OneVector { noop_fold_foreign_item(ni, self) } @@ -68,7 +69,7 @@ pub trait Folder : Sized { noop_fold_foreign_item_simple(ni, self) } - fn fold_item(&mut self, i: P) -> SmallVector> { + fn fold_item(&mut self, i: P) -> OneVector> { noop_fold_item(i, self) } @@ -88,11 +89,11 @@ pub trait Folder : Sized { noop_fold_item_kind(i, self) } - fn fold_trait_item(&mut self, i: TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, i: TraitItem) -> OneVector { noop_fold_trait_item(i, self) } - fn fold_impl_item(&mut self, i: ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, i: ImplItem) -> OneVector { noop_fold_impl_item(i, self) } @@ -108,7 +109,7 @@ pub trait Folder : Sized { noop_fold_block(b, self) } - fn fold_stmt(&mut self, s: Stmt) -> SmallVector { + fn fold_stmt(&mut self, s: Stmt) -> OneVector { noop_fold_stmt(s, self) } @@ -960,8 +961,8 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { } pub fn noop_fold_trait_item(i: TraitItem, folder: &mut T) - -> SmallVector { - SmallVector::one(TraitItem { + -> OneVector { + OneVector::one(TraitItem { id: folder.new_id(i.id), ident: folder.fold_ident(i.ident), attrs: fold_attrs(i.attrs, folder), @@ -989,8 +990,8 @@ pub fn noop_fold_trait_item(i: TraitItem, folder: &mut T) } pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) - -> SmallVector { - SmallVector::one(ImplItem { + -> OneVector { + OneVector::one(ImplItem { id: folder.new_id(i.id), vis: folder.fold_vis(i.vis), ident: folder.fold_ident(i.ident), @@ -1065,8 +1066,8 @@ pub fn noop_fold_crate(Crate {module, attrs, span}: Crate, } // fold one item into possibly many items -pub fn noop_fold_item(i: P, folder: &mut T) -> SmallVector> { - SmallVector::one(i.map(|i| folder.fold_item_simple(i))) +pub fn noop_fold_item(i: P, folder: &mut T) -> OneVector> { + OneVector::one(i.map(|i| folder.fold_item_simple(i))) } // fold one item into exactly one item @@ -1087,8 +1088,8 @@ pub fn noop_fold_item_simple(Item {id, ident, attrs, node, vis, span, } pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) --> SmallVector { - SmallVector::one(folder.fold_foreign_item_simple(ni)) +-> OneVector { + OneVector::one(folder.fold_foreign_item_simple(ni)) } pub fn noop_fold_foreign_item_simple(ni: ForeignItem, folder: &mut T) -> ForeignItem { @@ -1366,7 +1367,7 @@ pub fn noop_fold_exprs(es: Vec>, folder: &mut T) -> Vec(Stmt {node, span, id}: Stmt, folder: &mut T) -> SmallVector { +pub fn noop_fold_stmt(Stmt {node, span, id}: Stmt, folder: &mut T) -> OneVector { let id = folder.new_id(id); let span = folder.new_span(span); noop_fold_stmt_kind(node, folder).into_iter().map(|node| { @@ -1374,9 +1375,9 @@ pub fn noop_fold_stmt(Stmt {node, span, id}: Stmt, folder: &mut T) -> }).collect() } -pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> SmallVector { +pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> OneVector { match node { - StmtKind::Local(local) => SmallVector::one(StmtKind::Local(folder.fold_local(local))), + StmtKind::Local(local) => OneVector::one(StmtKind::Local(folder.fold_local(local))), StmtKind::Item(item) => folder.fold_item(item).into_iter().map(StmtKind::Item).collect(), StmtKind::Expr(expr) => { folder.fold_opt_expr(expr).into_iter().map(StmtKind::Expr).collect() @@ -1384,7 +1385,7 @@ pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> SmallVe StmtKind::Semi(expr) => { folder.fold_opt_expr(expr).into_iter().map(StmtKind::Semi).collect() } - StmtKind::Mac(mac) => SmallVector::one(StmtKind::Mac(mac.map(|(mac, semi, attrs)| { + StmtKind::Mac(mac) => OneVector::one(StmtKind::Mac(mac.map(|(mac, semi, attrs)| { (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into()) }))), } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 12ce478fe1d..c48ad0a802c 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -45,6 +45,8 @@ extern crate serialize as rustc_serialize; // used by deriving use rustc_data_structures::sync::Lock; use rustc_data_structures::bitvec::BitVector; +pub use rustc_data_structures::small_vec::OneVector; +pub use rustc_data_structures::thin_vec::ThinVec; use ast::AttrId; // A variant of 'try!' that panics on an Err. This is used as a crutch on the @@ -124,12 +126,8 @@ pub mod util { pub mod parser; #[cfg(test)] pub mod parser_testing; - pub mod small_vector; pub mod move_map; - mod thin_vec; - pub use self::thin_vec::ThinVec; - mod rc_slice; pub use self::rc_slice::RcSlice; } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 746e03d771a..0e45cacaf38 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -53,9 +53,9 @@ use util::parser::{AssocOp, Fixity}; use print::pprust; use ptr::P; use parse::PResult; +use ThinVec; use tokenstream::{self, Delimited, ThinTokenStream, TokenTree, TokenStream}; use symbol::{Symbol, keywords}; -use util::ThinVec; use std::borrow::Cow; use std::cmp; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 62dd00387d3..1cbaf3cc312 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -38,8 +38,9 @@ use parse::{token, ParseSess}; use print::pprust; use ast::{self, Ident}; use ptr::P; +use OneVector; use symbol::{self, Symbol, keywords}; -use util::small_vector::SmallVector; +use ThinVec; enum ShouldPanic { No, @@ -115,7 +116,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { folded } - fn fold_item(&mut self, i: P) -> SmallVector> { + fn fold_item(&mut self, i: P) -> OneVector> { let ident = i.ident; if ident.name != keywords::Invalid.name() { self.cx.path.push(ident); @@ -182,7 +183,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { if ident.name != keywords::Invalid.name() { self.cx.path.pop(); } - SmallVector::one(P(item)) + OneVector::one(P(item)) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac } @@ -194,7 +195,7 @@ struct EntryPointCleaner { } impl fold::Folder for EntryPointCleaner { - fn fold_item(&mut self, i: P) -> SmallVector> { + fn fold_item(&mut self, i: P) -> OneVector> { self.depth += 1; let folded = fold::noop_fold_item(i, self).expect_one("noop did something"); self.depth -= 1; @@ -234,7 +235,7 @@ impl fold::Folder for EntryPointCleaner { EntryPointType::OtherMain => folded, }; - SmallVector::one(folded) + OneVector::one(folded) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac } @@ -675,10 +676,10 @@ fn mk_test_descs(cx: &TestCtxt) -> P { mk_test_desc_and_fn_rec(cx, test) }).collect()), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), })), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }) } diff --git a/src/libsyntax/util/move_map.rs b/src/libsyntax/util/move_map.rs index 8cc37afa354..eb2c5a2458c 100644 --- a/src/libsyntax/util/move_map.rs +++ b/src/libsyntax/util/move_map.rs @@ -9,8 +9,7 @@ // except according to those terms. use std::ptr; - -use util::small_vector::SmallVector; +use OneVector; pub trait MoveMap: Sized { fn move_map(self, mut f: F) -> Self where F: FnMut(T) -> T { @@ -78,7 +77,7 @@ impl MoveMap for ::ptr::P<[T]> { } } -impl MoveMap for SmallVector { +impl MoveMap for OneVector { fn move_flat_map(mut self, mut f: F) -> Self where F: FnMut(T) -> I, I: IntoIterator diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs deleted file mode 100644 index 31e675836fc..00000000000 --- a/src/libsyntax/util/small_vector.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc_data_structures::small_vec::SmallVec; - -pub type SmallVector = SmallVec<[T; 1]>; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_len() { - let v: SmallVector = SmallVector::new(); - assert_eq!(0, v.len()); - - assert_eq!(1, SmallVector::one(1).len()); - assert_eq!(5, SmallVector::many(vec![1, 2, 3, 4, 5]).len()); - } - - #[test] - fn test_push_get() { - let mut v = SmallVector::new(); - v.push(1); - assert_eq!(1, v.len()); - assert_eq!(1, v[0]); - v.push(2); - assert_eq!(2, v.len()); - assert_eq!(2, v[1]); - v.push(3); - assert_eq!(3, v.len()); - assert_eq!(3, v[2]); - } - - #[test] - fn test_from_iter() { - let v: SmallVector = (vec![1, 2, 3]).into_iter().collect(); - assert_eq!(3, v.len()); - assert_eq!(1, v[0]); - assert_eq!(2, v[1]); - assert_eq!(3, v[2]); - } - - #[test] - fn test_move_iter() { - let v = SmallVector::new(); - let v: Vec = v.into_iter().collect(); - assert_eq!(v, Vec::new()); - - let v = SmallVector::one(1); - assert_eq!(v.into_iter().collect::>(), [1]); - - let v = SmallVector::many(vec![1, 2, 3]); - assert_eq!(v.into_iter().collect::>(), [1, 2, 3]); - } - - #[test] - #[should_panic] - fn test_expect_one_zero() { - let _: isize = SmallVector::new().expect_one(""); - } - - #[test] - #[should_panic] - fn test_expect_one_many() { - SmallVector::many(vec![1, 2]).expect_one(""); - } - - #[test] - fn test_expect_one_one() { - assert_eq!(1, SmallVector::one(1).expect_one("")); - assert_eq!(1, SmallVector::many(vec![1]).expect_one("")); - } -} diff --git a/src/libsyntax/util/thin_vec.rs b/src/libsyntax/util/thin_vec.rs deleted file mode 100644 index 546686b46b8..00000000000 --- a/src/libsyntax/util/thin_vec.rs +++ /dev/null @@ -1,59 +0,0 @@ -// 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. - -/// A vector type optimized for cases where this size is usually 0 (c.f. `SmallVector`). -/// The `Option>` wrapping allows us to represent a zero sized vector with `None`, -/// which uses only a single (null) pointer. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct ThinVec(Option>>); - -impl ThinVec { - pub fn new() -> Self { - ThinVec(None) - } -} - -impl From> for ThinVec { - fn from(vec: Vec) -> Self { - if vec.is_empty() { - ThinVec(None) - } else { - ThinVec(Some(Box::new(vec))) - } - } -} - -impl Into> for ThinVec { - fn into(self) -> Vec { - match self { - ThinVec(None) => Vec::new(), - ThinVec(Some(vec)) => *vec, - } - } -} - -impl ::std::ops::Deref for ThinVec { - type Target = [T]; - fn deref(&self) -> &[T] { - match *self { - ThinVec(None) => &[], - ThinVec(Some(ref vec)) => vec, - } - } -} - -impl Extend for ThinVec { - fn extend>(&mut self, iter: I) { - match *self { - ThinVec(Some(ref mut vec)) => vec.extend(iter), - ThinVec(None) => *self = iter.into_iter().collect::>().into(), - } - } -} diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 4ebb1fcb653..026ddccd7be 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -12,6 +12,8 @@ // use self::State::*; +use rustc_data_structures::thin_vec::ThinVec; + use syntax::ast; use syntax::ext::base; use syntax::ext::base::*; @@ -263,6 +265,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, ctxt: cx.backtrace(), })), span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), })) } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index a3c5c3df66e..c8cc11e4354 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::thin_vec::ThinVec; + use syntax::ast; use syntax::ext::base::*; use syntax::ext::base; @@ -68,7 +70,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)), span: self.ident.span, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), })) } diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index c2a7dea3316..df9c351ef1c 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -12,6 +12,8 @@ use deriving::path_std; use deriving::generic::*; use deriving::generic::ty::*; +use rustc_data_structures::thin_vec::ThinVec; + use syntax::ast::{self, Ident}; use syntax::ast::{Expr, MetaItem}; use syntax::ext::base::{Annotatable, ExtCtxt}; @@ -139,7 +141,7 @@ fn stmt_let_undescore(cx: &mut ExtCtxt, sp: Span, expr: P) -> ast::St init: Some(expr), id: ast::DUMMY_NODE_ID, span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); ast::Stmt { id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index f5e607fc23d..2e0ba65dc65 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -191,6 +191,7 @@ use std::cell::RefCell; use std::iter; use std::vec; +use rustc_data_structures::thin_vec::ThinVec; use rustc_target::spec::abi::Abi; use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; use syntax::ast::{VariantData, GenericParamKind, GenericArg}; @@ -1624,7 +1625,7 @@ impl<'a> TraitDef<'a> { ident: ident.unwrap(), pat, is_shorthand: false, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }, } }) diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 40ecd6e1519..7290b701e4d 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -18,6 +18,8 @@ /// LLVM's `module asm "some assembly here"`. All of LLVM's caveats /// therefore apply. +use rustc_data_structures::small_vec::OneVector; + use syntax::ast; use syntax::codemap::respan; use syntax::ext::base; @@ -28,8 +30,6 @@ use syntax::symbol::Symbol; use syntax_pos::Span; use syntax::tokenstream; -use syntax::util::small_vector::SmallVector; - pub const MACRO: &'static str = "global_asm"; pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, @@ -52,7 +52,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, None => return DummyResult::any(sp), }; - MacEager::items(SmallVector::one(P(ast::Item { + MacEager::items(OneVector::one(P(ast::Item { ident: ast::Ident::with_empty_ctxt(Symbol::intern("")), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, diff --git a/src/test/run-pass-fulldeps/auxiliary/issue-16723.rs b/src/test/run-pass-fulldeps/auxiliary/issue-16723.rs index 7f8a741465b..ff5d9a59bfa 100644 --- a/src/test/run-pass-fulldeps/auxiliary/issue-16723.rs +++ b/src/test/run-pass-fulldeps/auxiliary/issue-16723.rs @@ -15,12 +15,12 @@ extern crate syntax; extern crate rustc; +extern crate rustc_data_structures; extern crate rustc_plugin; extern crate syntax_pos; -use syntax::ast; +use rustc_data_structures::small_vec::OneVector; use syntax::ext::base::{ExtCtxt, MacResult, MacEager}; -use syntax::util::small_vector::SmallVector; use syntax::tokenstream; use rustc_plugin::Registry; @@ -31,7 +31,7 @@ pub fn plugin_registrar(reg: &mut Registry) { fn expand(cx: &mut ExtCtxt, _: syntax_pos::Span, _: &[tokenstream::TokenTree]) -> Box { - MacEager::items(SmallVector::many(vec![ + MacEager::items(OneVector::many(vec![ quote_item!(cx, struct Struct1;).unwrap(), quote_item!(cx, struct Struct2;).unwrap() ])) diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs index bbd81e790b8..3da50f16965 100644 --- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs @@ -30,8 +30,10 @@ #![feature(rustc_private)] +extern crate rustc_data_structures; extern crate syntax; +use rustc_data_structures::thin_vec::ThinVec; use syntax::ast::*; use syntax::codemap::{Spanned, DUMMY_SP, FileName}; use syntax::codemap::FilePathMapping; @@ -39,7 +41,6 @@ use syntax::fold::{self, Folder}; use syntax::parse::{self, ParseSess}; use syntax::print::pprust; use syntax::ptr::P; -use syntax::util::ThinVec; fn parse_expr(ps: &ParseSess, src: &str) -> P { -- cgit 1.4.1-3-g733a5 From 05ddad37d19bd32b8ef75464640c8b0e6a6e1516 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 13 Aug 2018 23:12:36 +0200 Subject: use ? to simplify `TransitiveRelation.maybe_map` --- src/librustc_data_structures/transitive_relation.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 18a1e9129b3..2acc29acb0c 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -97,12 +97,7 @@ impl TransitiveRelation { { let mut result = TransitiveRelation::new(); for edge in &self.edges { - f(&self.elements[edge.source.0]).and_then(|source| { - f(&self.elements[edge.target.0]).and_then(|target| { - result.add(source, target); - Some(()) - }) - })?; + result.add(f(&self.elements[edge.source.0])?, f(&self.elements[edge.target.0])?); } Some(result) } -- cgit 1.4.1-3-g733a5 From 5745597e6195fe0591737f242d02350001b6c590 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 14 Aug 2018 10:21:24 +1000 Subject: Speed up NLL with `HybridIdxSetBuf`. `HybridIdxSetBuf` is a sparse-when-small but dense-when-large index set that is very efficient for sets that (a) have few elements, (b) have large `universe_size` values, and (c) are cleared frequently. Which makes it perfect for the `gen_set` and `kill_set` sets used by the new borrow checker. This patch reduces the execution time of the five slowest NLL benchmarks by 55%, 21%, 16%, 10% and 9%. It also reduces the max-rss of three benchmarks by 53%, 33%, and 9%. --- src/librustc_data_structures/indexed_set.rs | 247 ++++++++++++++++++++++++++-- src/librustc_mir/dataflow/at_location.rs | 18 +- src/librustc_mir/dataflow/graphviz.rs | 35 ++-- src/librustc_mir/dataflow/mod.rs | 90 +++++----- src/librustc_mir/transform/rustc_peek.rs | 20 +-- 5 files changed, 320 insertions(+), 90 deletions(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 2e95a45479c..ed2e9787800 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use array_vec::ArrayVec; use std::borrow::{Borrow, BorrowMut, ToOwned}; use std::fmt; use std::iter; @@ -25,6 +26,8 @@ use rustc_serialize; /// /// In other words, `T` is the type used to index into the bitvector /// this type uses to represent the set of object it holds. +/// +/// The representation is dense, using one bit per possible element. #[derive(Eq, PartialEq)] pub struct IdxSetBuf { _pd: PhantomData, @@ -93,6 +96,8 @@ impl ToOwned for IdxSet { } } +const BITS_PER_WORD: usize = mem::size_of::() * 8; + impl fmt::Debug for IdxSetBuf { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { w.debug_list() @@ -111,8 +116,7 @@ impl fmt::Debug for IdxSet { impl IdxSetBuf { fn new(init: Word, universe_size: usize) -> Self { - let bits_per_word = mem::size_of::() * 8; - let num_words = (universe_size + (bits_per_word - 1)) / bits_per_word; + let num_words = (universe_size + (BITS_PER_WORD - 1)) / BITS_PER_WORD; IdxSetBuf { _pd: Default::default(), bits: vec![init; num_words], @@ -163,6 +167,16 @@ impl IdxSet { } } + /// Duplicates as a hybrid set. + pub fn to_hybrid(&self) -> HybridIdxSetBuf { + // This universe_size may be slightly larger than the one specified + // upon creation, due to rounding up to a whole word. That's ok. + let universe_size = self.bits.len() * BITS_PER_WORD; + + // Note: we currently don't bother trying to make a Sparse set. + HybridIdxSetBuf::Dense(self.to_owned(), universe_size) + } + /// Removes all elements pub fn clear(&mut self) { for b in &mut self.bits { @@ -180,11 +194,9 @@ impl IdxSet { /// Clear all elements above `universe_size`. fn trim_to(&mut self, universe_size: usize) { - let word_bits = mem::size_of::() * 8; - // `trim_block` is the first block where some bits have // to be cleared. - let trim_block = universe_size / word_bits; + let trim_block = universe_size / BITS_PER_WORD; // all the blocks above it have to be completely cleared. if trim_block < self.bits.len() { @@ -192,9 +204,9 @@ impl IdxSet { *b = 0; } - // at that block, the `universe_size % word_bits` lsbs + // at that block, the `universe_size % BITS_PER_WORD` lsbs // should remain. - let remaining_bits = universe_size % word_bits; + let remaining_bits = universe_size % BITS_PER_WORD; let mask = (1< IdxSet { bitwise(self.words_mut(), other.words(), &Union) } + /// Like `union()`, but takes a `SparseIdxSetBuf` argument. + fn union_sparse(&mut self, other: &SparseIdxSetBuf) -> bool { + let mut changed = false; + for elem in other.iter() { + changed |= self.add(&elem); + } + changed + } + + /// Like `union()`, but takes a `HybridIdxSetBuf` argument. + pub fn union_hybrid(&mut self, other: &HybridIdxSetBuf) -> bool { + match other { + HybridIdxSetBuf::Sparse(sparse, _) => self.union_sparse(sparse), + HybridIdxSetBuf::Dense(dense, _) => self.union(dense), + } + } + /// Set `self = self - other` and return true if `self` changed. /// (i.e., if any bits were removed). pub fn subtract(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Subtract) } + /// Like `subtract()`, but takes a `SparseIdxSetBuf` argument. + fn subtract_sparse(&mut self, other: &SparseIdxSetBuf) -> bool { + let mut changed = false; + for elem in other.iter() { + changed |= self.remove(&elem); + } + changed + } + + /// Like `subtract()`, but takes a `HybridIdxSetBuf` argument. + pub fn subtract_hybrid(&mut self, other: &HybridIdxSetBuf) -> bool { + match other { + HybridIdxSetBuf::Sparse(sparse, _) => self.subtract_sparse(sparse), + HybridIdxSetBuf::Dense(dense, _) => self.subtract(dense), + } + } + /// Set `self = self & other` and return true if `self` changed. /// (i.e., if any bits were removed). pub fn intersect(&mut self, other: &IdxSet) -> bool { @@ -276,11 +322,10 @@ impl<'a, T: Idx> Iterator for Iter<'a, T> { type Item = T; fn next(&mut self) -> Option { - let word_bits = mem::size_of::() * 8; loop { if let Some((ref mut word, offset)) = self.cur { let bit_pos = word.trailing_zeros() as usize; - if bit_pos != word_bits { + if bit_pos != BITS_PER_WORD { let bit = 1 << bit_pos; *word ^= bit; return Some(T::new(bit_pos + offset)) @@ -288,7 +333,189 @@ impl<'a, T: Idx> Iterator for Iter<'a, T> { } let (i, word) = self.iter.next()?; - self.cur = Some((*word, word_bits * i)); + self.cur = Some((*word, BITS_PER_WORD * i)); + } + } +} + +const SPARSE_MAX: usize = 8; + +/// A sparse index set with a maximum of SPARSE_MAX elements. Used by +/// HybridIdxSetBuf; do not use directly. +/// +/// The elements are stored as an unsorted vector with no duplicates. +#[derive(Clone, Debug)] +pub struct SparseIdxSetBuf(ArrayVec<[T; SPARSE_MAX]>); + +impl SparseIdxSetBuf { + fn new() -> Self { + SparseIdxSetBuf(ArrayVec::new()) + } + + fn len(&self) -> usize { + self.0.len() + } + + fn contains(&self, elem: &T) -> bool { + self.0.contains(elem) + } + + fn add(&mut self, elem: &T) -> bool { + // Ensure there are no duplicates. + if self.0.contains(elem) { + false + } else { + self.0.push(*elem); + true + } + } + + fn remove(&mut self, elem: &T) -> bool { + if let Some(i) = self.0.iter().position(|e| e == elem) { + // Swap the found element to the end, then pop it. + let len = self.0.len(); + self.0.swap(i, len - 1); + self.0.pop(); + true + } else { + false + } + } + + fn to_dense(&self, universe_size: usize) -> IdxSetBuf { + let mut dense = IdxSetBuf::new_empty(universe_size); + for elem in self.0.iter() { + dense.add(elem); + } + dense + } + + fn iter(&self) -> SparseIter { + SparseIter { + iter: self.0.iter(), + } + } +} + +pub struct SparseIter<'a, T: Idx> { + iter: slice::Iter<'a, T>, +} + +impl<'a, T: Idx> Iterator for SparseIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.iter.next().map(|e| *e) + } +} + +/// Like IdxSetBuf, but with a hybrid representation: sparse when there are few +/// elements in the set, but dense when there are many. It's especially +/// efficient for sets that typically have a small number of elements, but a +/// large `universe_size`, and are cleared frequently. +#[derive(Clone, Debug)] +pub enum HybridIdxSetBuf { + Sparse(SparseIdxSetBuf, usize), + Dense(IdxSetBuf, usize), +} + +impl HybridIdxSetBuf { + pub fn new_empty(universe_size: usize) -> Self { + HybridIdxSetBuf::Sparse(SparseIdxSetBuf::new(), universe_size) + } + + fn universe_size(&mut self) -> usize { + match *self { + HybridIdxSetBuf::Sparse(_, size) => size, + HybridIdxSetBuf::Dense(_, size) => size, + } + } + + pub fn clear(&mut self) { + let universe_size = self.universe_size(); + *self = HybridIdxSetBuf::new_empty(universe_size); + } + + /// Returns true iff set `self` contains `elem`. + pub fn contains(&self, elem: &T) -> bool { + match self { + HybridIdxSetBuf::Sparse(sparse, _) => sparse.contains(elem), + HybridIdxSetBuf::Dense(dense, _) => dense.contains(elem), + } + } + + /// Adds `elem` to the set `self`. + pub fn add(&mut self, elem: &T) -> bool { + match self { + HybridIdxSetBuf::Sparse(sparse, _) if sparse.len() < SPARSE_MAX => { + // The set is sparse and has space for `elem`. + sparse.add(elem) + } + HybridIdxSetBuf::Sparse(sparse, _) if sparse.contains(elem) => { + // The set is sparse and does not have space for `elem`, but + // that doesn't matter because `elem` is already present. + false + } + HybridIdxSetBuf::Sparse(_, _) => { + // The set is sparse and full. Convert to a dense set. + // + // FIXME: This code is awful, but I can't work out how else to + // appease the borrow checker. + let dummy = HybridIdxSetBuf::Sparse(SparseIdxSetBuf::new(), 0); + match mem::replace(self, dummy) { + HybridIdxSetBuf::Sparse(sparse, universe_size) => { + let mut dense = sparse.to_dense(universe_size); + let changed = dense.add(elem); + assert!(changed); + mem::replace(self, HybridIdxSetBuf::Dense(dense, universe_size)); + changed + } + _ => panic!("impossible"), + } + } + + HybridIdxSetBuf::Dense(dense, _) => dense.add(elem), + } + } + + /// Removes `elem` from the set `self`. + pub fn remove(&mut self, elem: &T) -> bool { + // Note: we currently don't bother going from Dense back to Sparse. + match self { + HybridIdxSetBuf::Sparse(sparse, _) => sparse.remove(elem), + HybridIdxSetBuf::Dense(dense, _) => dense.remove(elem), + } + } + + /// Converts to a dense set, consuming itself in the process. + pub fn to_dense(self) -> IdxSetBuf { + match self { + HybridIdxSetBuf::Sparse(sparse, universe_size) => sparse.to_dense(universe_size), + HybridIdxSetBuf::Dense(dense, _) => dense, + } + } + + /// Iteration order is unspecified. + pub fn iter(&self) -> HybridIter { + match self { + HybridIdxSetBuf::Sparse(sparse, _) => HybridIter::Sparse(sparse.iter()), + HybridIdxSetBuf::Dense(dense, _) => HybridIter::Dense(dense.iter()), + } + } +} + +pub enum HybridIter<'a, T: Idx> { + Sparse(SparseIter<'a, T>), + Dense(Iter<'a, T>), +} + +impl<'a, T: Idx> Iterator for HybridIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + match self { + HybridIter::Sparse(sparse) => sparse.next(), + HybridIter::Dense(dense) => dense.next(), } } } diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index 05453bd58c4..d2a8a9dcf4b 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -12,7 +12,7 @@ //! locations. use rustc::mir::{BasicBlock, Location}; -use rustc_data_structures::indexed_set::{IdxSetBuf, Iter}; +use rustc_data_structures::indexed_set::{HybridIdxSetBuf, IdxSetBuf, Iter}; use rustc_data_structures::indexed_vec::Idx; use dataflow::{BitDenotation, BlockSets, DataflowResults}; @@ -68,8 +68,8 @@ where { base_results: DataflowResults, curr_state: IdxSetBuf, - stmt_gen: IdxSetBuf, - stmt_kill: IdxSetBuf, + stmt_gen: HybridIdxSetBuf, + stmt_kill: HybridIdxSetBuf, } impl FlowAtLocation @@ -97,8 +97,8 @@ where pub fn new(results: DataflowResults) -> Self { let bits_per_block = results.sets().bits_per_block(); let curr_state = IdxSetBuf::new_empty(bits_per_block); - let stmt_gen = IdxSetBuf::new_empty(bits_per_block); - let stmt_kill = IdxSetBuf::new_empty(bits_per_block); + let stmt_gen = HybridIdxSetBuf::new_empty(bits_per_block); + let stmt_kill = HybridIdxSetBuf::new_empty(bits_per_block); FlowAtLocation { base_results: results, curr_state: curr_state, @@ -129,8 +129,8 @@ where F: FnOnce(Iter), { let mut curr_state = self.curr_state.clone(); - curr_state.union(&self.stmt_gen); - curr_state.subtract(&self.stmt_kill); + curr_state.union_hybrid(&self.stmt_gen); + curr_state.subtract_hybrid(&self.stmt_kill); f(curr_state.iter()); } } @@ -193,8 +193,8 @@ impl FlowsAtLocation for FlowAtLocation } fn apply_local_effect(&mut self, _loc: Location) { - self.curr_state.union(&self.stmt_gen); - self.curr_state.subtract(&self.stmt_kill); + self.curr_state.union_hybrid(&self.stmt_gen); + self.curr_state.subtract_hybrid(&self.stmt_kill); } } diff --git a/src/librustc_mir/dataflow/graphviz.rs b/src/librustc_mir/dataflow/graphviz.rs index 7475b4d82f4..97d54998771 100644 --- a/src/librustc_mir/dataflow/graphviz.rs +++ b/src/librustc_mir/dataflow/graphviz.rs @@ -168,13 +168,13 @@ where MWF: MirWithFlowState<'tcx>, let i = n.index(); macro_rules! dump_set_for { - ($set:ident) => { + ($set:ident, $interpret:ident) => { write!(w, "

    ")?; let flow = self.mbcx.flow_state(); - let entry_interp = flow.interpret_set(&flow.operator, - flow.sets.$set(i), - &self.render_idx); + let entry_interp = flow.$interpret(&flow.operator, + flow.sets.$set(i), + &self.render_idx); for e in &entry_interp { write!(w, "{:?}
    ", e)?; } @@ -184,7 +184,7 @@ where MWF: MirWithFlowState<'tcx>, write!(w, "
    ")?; @@ -198,10 +198,10 @@ where MWF: MirWithFlowState<'tcx>, write!(w, "
    {:?}
    {:?}")?; @@ -242,10 +237,12 @@ where MWF: MirWithFlowState<'tcx>, write!(w, "{:?}{:?}
  • ")?; + if let Some(l) = (Item { cx, item: &implementor.impl_item }).src_href() { + write!(w, "
    ")?; + write!(w, "[src]", + l, "goto source code")?; + write!(w, "
    ")?; + } + write!(w, "")?; + // If there's already another implementor that has the same abbridged name, use the + // full path, for example in `std::iter::ExactSizeIterator` + let use_absolute = match implementor.inner_impl().for_ { + clean::ResolvedPath { ref path, is_generic: false, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { ref path, is_generic: false, .. }, + .. + } => implementor_dups[path.last_name()].1, + _ => false, + }; + fmt_impl_for_trait_page(&implementor.inner_impl(), w, use_absolute)?; + for it in &implementor.inner_impl().items { + if let clean::TypedefItem(ref tydef, _) = it.inner { + write!(w, " ")?; + assoc_type(w, it, &vec![], Some(&tydef.type_), AssocItemLink::Anchor(None))?; + write!(w, ";")?; + } + } + writeln!(w, "