Skip to content

Rollup of 9 pull requests #36635

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
470 changes: 310 additions & 160 deletions src/liballoc/rc.rs

Large diffs are not rendered by default.

93 changes: 55 additions & 38 deletions src/libarena/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
//! of individual objects while the arena itself is still alive. The benefit
//! of an arena is very fast allocation; just a pointer bump.
//!
//! This crate has two arenas implemented: `TypedArena`, which is a simpler
//! arena but can only hold objects of a single type, and `Arena`, which is a
//! more complex, slower arena which can hold objects of any type.
//! This crate implements `TypedArena`, a simple arena that can only hold
//! objects of a single type.

#![crate_name = "arena"]
#![unstable(feature = "rustc_private", issue = "27812")]
Expand Down Expand Up @@ -51,16 +50,19 @@ use std::ptr;
use alloc::heap;
use alloc::raw_vec::RawVec;

/// A faster arena that can hold objects of only one type.
/// An arena that can hold objects of only one type.
pub struct TypedArena<T> {
/// The capacity of the first chunk (once it is allocated).
first_chunk_capacity: usize,

/// A pointer to the next object to be allocated.
ptr: Cell<*mut T>,

/// A pointer to the end of the allocated area. When this pointer is
/// reached, a new chunk is allocated.
end: Cell<*mut T>,

/// A vector arena segments.
/// A vector of arena chunks.
chunks: RefCell<Vec<TypedArenaChunk<T>>>,

/// Marker indicating that dropping the arena causes its owned
Expand All @@ -69,7 +71,7 @@ pub struct TypedArena<T> {
}

struct TypedArenaChunk<T> {
/// Pointer to the next arena segment.
/// The raw storage for the arena chunk.
storage: RawVec<T>,
}

Expand Down Expand Up @@ -117,26 +119,26 @@ impl<T> TypedArenaChunk<T> {
const PAGE: usize = 4096;

impl<T> TypedArena<T> {
/// Creates a new `TypedArena` with preallocated space for many objects.
/// Creates a new `TypedArena`.
#[inline]
pub fn new() -> TypedArena<T> {
// Reserve at least one page.
let elem_size = cmp::max(1, mem::size_of::<T>());
TypedArena::with_capacity(PAGE / elem_size)
}

/// Creates a new `TypedArena` with preallocated space for the given number of
/// objects.
/// Creates a new `TypedArena`. Each chunk used within the arena will have
/// space for at least the given number of objects.
#[inline]
pub fn with_capacity(capacity: usize) -> TypedArena<T> {
unsafe {
let chunk = TypedArenaChunk::<T>::new(cmp::max(1, capacity));
TypedArena {
ptr: Cell::new(chunk.start()),
end: Cell::new(chunk.end()),
chunks: RefCell::new(vec![chunk]),
_own: PhantomData,
}
TypedArena {
first_chunk_capacity: cmp::max(1, capacity),
// We set both `ptr` and `end` to 0 so that the first call to
// alloc() will trigger a grow().
ptr: Cell::new(0 as *mut T),
end: Cell::new(0 as *mut T),
chunks: RefCell::new(vec![]),
_own: PhantomData,
}
}

Expand Down Expand Up @@ -171,29 +173,37 @@ impl<T> TypedArena<T> {
fn grow(&self) {
unsafe {
let mut chunks = self.chunks.borrow_mut();
let prev_capacity = chunks.last().unwrap().storage.cap();
let new_capacity = prev_capacity.checked_mul(2).unwrap();
if chunks.last_mut().unwrap().storage.double_in_place() {
self.end.set(chunks.last().unwrap().end());
let (chunk, new_capacity);
if let Some(last_chunk) = chunks.last_mut() {
if last_chunk.storage.double_in_place() {
self.end.set(last_chunk.end());
return;
} else {
let prev_capacity = last_chunk.storage.cap();
new_capacity = prev_capacity.checked_mul(2).unwrap();
}
} else {
let chunk = TypedArenaChunk::<T>::new(new_capacity);
self.ptr.set(chunk.start());
self.end.set(chunk.end());
chunks.push(chunk);
new_capacity = self.first_chunk_capacity;
}
chunk = TypedArenaChunk::<T>::new(new_capacity);
self.ptr.set(chunk.start());
self.end.set(chunk.end());
chunks.push(chunk);
}
}
/// Clears the arena. Deallocates all but the longest chunk which may be reused.
pub fn clear(&mut self) {
unsafe {
// Clear the last chunk, which is partially filled.
let mut chunks_borrow = self.chunks.borrow_mut();
let last_idx = chunks_borrow.len() - 1;
self.clear_last_chunk(&mut chunks_borrow[last_idx]);
// If `T` is ZST, code below has no effect.
for mut chunk in chunks_borrow.drain(..last_idx) {
let cap = chunk.storage.cap();
chunk.destroy(cap);
if let Some(mut last_chunk) = chunks_borrow.pop() {
self.clear_last_chunk(&mut last_chunk);
// If `T` is ZST, code below has no effect.
for mut chunk in chunks_borrow.drain(..) {
let cap = chunk.storage.cap();
chunk.destroy(cap);
}
chunks_borrow.push(last_chunk);
}
}
}
Expand Down Expand Up @@ -230,13 +240,14 @@ impl<T> Drop for TypedArena<T> {
unsafe {
// Determine how much was filled.
let mut chunks_borrow = self.chunks.borrow_mut();
let mut last_chunk = chunks_borrow.pop().unwrap();
// Drop the contents of the last chunk.
self.clear_last_chunk(&mut last_chunk);
// The last chunk will be dropped. Destroy all other chunks.
for chunk in chunks_borrow.iter_mut() {
let cap = chunk.storage.cap();
chunk.destroy(cap);
if let Some(mut last_chunk) = chunks_borrow.pop() {
// Drop the contents of the last chunk.
self.clear_last_chunk(&mut last_chunk);
// The last chunk will be dropped. Destroy all other chunks.
for chunk in chunks_borrow.iter_mut() {
let cap = chunk.storage.cap();
chunk.destroy(cap);
}
}
// RawVec handles deallocation of `last_chunk` and `self.chunks`.
}
Expand All @@ -260,6 +271,12 @@ mod tests {
z: i32,
}

#[test]
pub fn test_unused() {
let arena: TypedArena<Point> = TypedArena::new();
assert!(arena.chunks.borrow().is_empty());
}

#[test]
fn test_arena_alloc_nested() {
struct Inner {
Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,7 +1037,7 @@ impl<T> [T] {
self.sort_by(|a, b| a.cmp(b))
}

/// Sorts the slice, in place, using `key` to extract a key by which to
/// Sorts the slice, in place, using `f` to extract a key by which to
/// order the sort by.
///
/// This sort is stable and `O(n log n)` worst-case but allocates
Expand Down
10 changes: 4 additions & 6 deletions src/libcore/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,16 +296,14 @@ impl<T> Option<T> {

/// Moves the value `v` out of the `Option<T>` if it is `Some(v)`.
///
/// # Panics
///
/// Panics if the self value equals `None`.
///
/// # Safety note
///
/// In general, because this function may panic, its use is discouraged.
/// Instead, prefer to use pattern matching and handle the `None`
/// case explicitly.
///
/// # Panics
///
/// Panics if the self value equals `None`.
///
/// # Examples
///
/// ```
Expand Down
1 change: 1 addition & 0 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub trait CodeMapper {
fn span_to_string(&self, sp: Span) -> String;
fn span_to_filename(&self, sp: Span) -> FileName;
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
}

impl CodeSuggestion {
Expand Down
13 changes: 12 additions & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3094,7 +3094,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some(field_name) = Self::suggest_field_name(variant,
&field.name,
skip_fields.collect()) {
err.span_label(field.name.span,&format!("did you mean `{}`?",field_name));
err.span_label(field.name.span,
&format!("field does not exist - did you mean `{}`?", field_name));
} else {
match ty.sty {
ty::TyAdt(adt, ..) if adt.is_enum() => {
err.span_label(field.name.span, &format!("`{}::{}` does not have this field",
ty, variant.name.as_str()));
}
_ => {
err.span_label(field.name.span, &format!("`{}` does not have this field", ty));
}
}
};
err.emit();
}
Expand Down
21 changes: 21 additions & 0 deletions src/libstd/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,15 @@ impl DirEntry {
}
}

#[stable(feature = "dir_entry_debug", since = "1.13.0")]
impl fmt::Debug for DirEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("DirEntry")
.field(&self.path())
.finish()
}
}

impl AsInner<fs_imp::DirEntry> for DirEntry {
fn as_inner(&self) -> &fs_imp::DirEntry { &self.0 }
}
Expand Down Expand Up @@ -2641,6 +2650,18 @@ mod tests {
}
}

#[test]
fn dir_entry_debug() {
let tmpdir = tmpdir();
let file_path = &tmpdir.join("b");
File::create(file_path).unwrap();
let mut read_dir = tmpdir.path().read_dir().unwrap();
let dir_entry = read_dir.next().unwrap().unwrap();
let actual = format!("{:?}", dir_entry);
let expected = format!("DirEntry(\"{}\")", file_path.display());
assert_eq!(actual, expected);
}

#[test]
fn read_dir_not_found() {
let res = fs::read_dir("/path/that/does/not/exist");
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/time/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl Duration {

/// Returns the number of whole seconds represented by this duration.
///
/// The extra precision represented by this duration is ignored (e.g. extra
/// The extra precision represented by this duration is ignored (i.e. extra
/// nanoseconds are not represented in the returned value).
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
Expand All @@ -93,7 +93,7 @@ impl Duration {
///
/// This method does **not** return the length of the duration when
/// represented by nanoseconds. The returned number always represents a
/// fractional portion of a second (e.g. it is less than one billion).
/// fractional portion of a second (i.e. it is less than one billion).
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
pub fn subsec_nanos(&self) -> u32 { self.nanos }
Expand Down
77 changes: 77 additions & 0 deletions src/libsyntax/codemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,46 @@ impl CodeMap {
}
}

/// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If
/// there are gaps between lhs and rhs, the resulting union will cross these gaps.
/// For this to work, the spans have to be:
/// * the expn_id of both spans much match
/// * the lhs span needs to end on the same line the rhs span begins
/// * the lhs span must start at or before the rhs span
pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
use std::cmp;

// make sure we're at the same expansion id
if sp_lhs.expn_id != sp_rhs.expn_id {
return None;
}

let lhs_end = match self.lookup_line(sp_lhs.hi) {
Ok(x) => x,
Err(_) => return None
};
let rhs_begin = match self.lookup_line(sp_rhs.lo) {
Ok(x) => x,
Err(_) => return None
};

// if we must cross lines to merge, don't merge
if lhs_end.line != rhs_begin.line {
return None;
}

// ensure these follow the expected order and we don't overlap
if (sp_lhs.lo <= sp_rhs.lo) && (sp_lhs.hi <= sp_rhs.lo) {
Some(Span {
lo: cmp::min(sp_lhs.lo, sp_rhs.lo),
hi: cmp::max(sp_lhs.hi, sp_rhs.hi),
expn_id: sp_lhs.expn_id,
})
} else {
None
}
}

pub fn span_to_string(&self, sp: Span) -> String {
if sp == COMMAND_LINE_SP {
return "<command line option>".to_string();
Expand Down Expand Up @@ -819,6 +859,9 @@ impl CodeMapper for CodeMap {
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
self.macro_backtrace(span)
}
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
self.merge_spans(sp_lhs, sp_rhs)
}
}

// _____________________________________________________________________________
Expand Down Expand Up @@ -1072,6 +1115,40 @@ mod tests {
blork.rs:1:1: 1:12\n `first line.`\n");
}

/// Test merging two spans on the same line
#[test]
fn span_merging() {
let cm = CodeMap::new();
let inputtext = "bbbb BB bb CCC\n";
let selection1 = " ~~ \n";
let selection2 = " ~~~\n";
cm.new_filemap_and_lines("blork.rs", None, inputtext);
let span1 = span_from_selection(inputtext, selection1);
let span2 = span_from_selection(inputtext, selection2);

if let Some(sp) = cm.merge_spans(span1, span2) {
let sstr = cm.span_to_expanded_string(sp);
assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n");
}
else {
assert!(false);
}
}

/// Test failing to merge two spans on different lines
#[test]
fn span_merging_fail() {
let cm = CodeMap::new();
let inputtext = "bbbb BB\ncc CCC\n";
let selection1 = " ~~\n \n";
let selection2 = " \n ~~~\n";
cm.new_filemap_and_lines("blork.rs", None, inputtext);
let span1 = span_from_selection(inputtext, selection1);
let span2 = span_from_selection(inputtext, selection2);

assert!(cm.merge_spans(span1, span2).is_none());
}

/// Returns the span corresponding to the `n`th occurrence of
/// `substring` in `source_text`.
trait CodeMapExtension {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ impl<'a> Parser<'a> {

self.expect(&token::OpenDelim(token::Bracket))?;
let meta_item = self.parse_meta_item()?;
let hi = self.last_span.hi;
self.expect(&token::CloseDelim(token::Bracket))?;
let hi = self.last_span.hi;

(mk_sp(lo, hi), meta_item, style)
}
Expand Down
Loading