From 82639d4f0429eedd868d25d78b69a9fd96e5d200 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Fri, 16 Sep 2016 21:44:15 +0300 Subject: [PATCH 01/11] fix top level attr spans --- src/libsyntax/parse/attr.rs | 2 +- src/test/ui/span/issue-36530.rs | 14 ++++++++++++++ src/test/ui/span/issue-36530.stderr | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/span/issue-36530.rs create mode 100644 src/test/ui/span/issue-36530.stderr diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index a0defbc09dc04..9eac024edb17e 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -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) } diff --git a/src/test/ui/span/issue-36530.rs b/src/test/ui/span/issue-36530.rs new file mode 100644 index 0000000000000..893c2168c2e16 --- /dev/null +++ b/src/test/ui/span/issue-36530.rs @@ -0,0 +1,14 @@ +// 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. + +#[foo] +mod foo { + #![foo] +} diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr new file mode 100644 index 0000000000000..dc6190c2e76b0 --- /dev/null +++ b/src/test/ui/span/issue-36530.stderr @@ -0,0 +1,18 @@ +error: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) + --> $DIR/issue-36530.rs:11:1 + | +11 | #[foo] + | ^^^^^^ + | + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) + --> $DIR/issue-36530.rs:13:5 + | +13 | #![foo] + | ^^^^^^^ + | + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: aborting due to 2 previous errors + From af67f0b389abca6851bbed78f25046a8c783d6b3 Mon Sep 17 00:00:00 2001 From: aclarry Date: Tue, 6 Sep 2016 13:40:33 -0400 Subject: [PATCH 02/11] Fix name of error test file --- src/test/compile-fail/{E560.rs => E0560.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/compile-fail/{E560.rs => E0560.rs} (100%) diff --git a/src/test/compile-fail/E560.rs b/src/test/compile-fail/E0560.rs similarity index 100% rename from src/test/compile-fail/E560.rs rename to src/test/compile-fail/E0560.rs From 313fb8fbf2bd4e99d36286474196599c5a5e6eaf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Sep 2016 14:08:57 +0200 Subject: [PATCH 03/11] Replace 'e.g.' by 'i.e.' --- src/libstd/time/duration.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 246c57ab23871..10a0c567e142f 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -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] @@ -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 } From 2ea3ab3a9022a93e45c4d50a1c43aec5f56ab4dc Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 19 Sep 2016 12:31:56 -0700 Subject: [PATCH 04/11] Add the ability to merge spans to codemap --- src/librustc_errors/lib.rs | 1 + src/libsyntax/codemap.rs | 82 ++++++++++++++++++++++++++++++++++++++ src/libsyntax_pos/lib.rs | 18 --------- 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d2f3eea85f228..bc599a8207656 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -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; + fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option; } impl CodeSuggestion { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index cd6f2874954b8..ce15bd89590bc 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -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 { + 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 + if sp_lhs.lo <= 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 "".to_string(); @@ -819,6 +859,9 @@ impl CodeMapper for CodeMap { fn macro_backtrace(&self, span: Span) -> Vec { self.macro_backtrace(span) } + fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { + self.merge_spans(sp_lhs, sp_rhs) + } } // _____________________________________________________________________________ @@ -1072,6 +1115,45 @@ 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); + + if let Some(_) = cm.merge_spans(span1, span2) { + assert!(false); + } + else { + assert!(true); + } + } + /// Returns the span corresponding to the `n`th occurrence of /// `substring` in `source_text`. trait CodeMapExtension { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d835f8058fa0e..0c0c62275d4db 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -96,24 +96,6 @@ impl Span { self.lo == other.lo && self.hi == other.hi } - /// Returns `Some(span)`, a union of `self` and `other`, on overlap. - pub fn merge(self, other: Span) -> Option { - if self.expn_id != other.expn_id { - return None; - } - - if (self.lo <= other.lo && self.hi > other.lo) || - (self.lo >= other.lo && self.lo < other.hi) { - Some(Span { - lo: cmp::min(self.lo, other.lo), - hi: cmp::max(self.hi, other.hi), - expn_id: self.expn_id, - }) - } else { - None - } - } - /// Returns `Some(span)`, where the start is trimmed by the end of `other` pub fn trim_start(self, other: Span) -> Option { if self.hi > other.hi { From 8b02aa1c800dd4c7a40a01e648507b0edfa07229 Mon Sep 17 00:00:00 2001 From: jacobpadkins Date: Mon, 19 Sep 2016 17:55:44 -0500 Subject: [PATCH 05/11] fixed the safety header/wording in option.rs --- src/libcore/option.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index b9fb2dc90c728..cb18feff73422 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -296,16 +296,14 @@ impl Option { /// Moves the value `v` out of the `Option` 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 /// /// ``` From 80a44779f7a211e075da9ed0ff2763afa00f43dc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Sep 2016 09:52:38 +1000 Subject: [PATCH 06/11] Lazily allocate TypedArena's first chunk. Currently `TypedArena` allocates its first chunk, which is usually 4096 bytes, as soon as it is created. If no allocations are ever made from the arena then this allocation (and the corresponding deallocation) is wasted effort. This commit changes `TypedArena` so it doesn't allocate the first chunk until the first allocation is made. This change speeds up rustc by a non-trivial amount because rustc uses `TypedArena` heavily: compilation speed (producing debug builds) on several of the rustc-benchmarks increases by 1.02--1.06x. The change should never cause a slow-down because the hot `alloc` function is unchanged. It does increase the size of `TypedArena` by one `usize` field, however. The commit also fixes some out-of-date comments. --- src/libarena/lib.rs | 93 +++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index b299b786b35a8..556757ec84daf 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -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")] @@ -51,8 +50,11 @@ 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 { + /// 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>, @@ -60,7 +62,7 @@ pub struct TypedArena { /// reached, a new chunk is allocated. end: Cell<*mut T>, - /// A vector arena segments. + /// A vector of arena chunks. chunks: RefCell>>, /// Marker indicating that dropping the arena causes its owned @@ -69,7 +71,7 @@ pub struct TypedArena { } struct TypedArenaChunk { - /// Pointer to the next arena segment. + /// The raw storage for the arena chunk. storage: RawVec, } @@ -117,7 +119,7 @@ impl TypedArenaChunk { const PAGE: usize = 4096; impl TypedArena { - /// Creates a new `TypedArena` with preallocated space for many objects. + /// Creates a new `TypedArena`. #[inline] pub fn new() -> TypedArena { // Reserve at least one page. @@ -125,18 +127,18 @@ impl TypedArena { 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 { - unsafe { - let chunk = TypedArenaChunk::::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, } } @@ -171,16 +173,22 @@ impl TypedArena { 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::::new(new_capacity); - self.ptr.set(chunk.start()); - self.end.set(chunk.end()); - chunks.push(chunk); + new_capacity = self.first_chunk_capacity; } + chunk = TypedArenaChunk::::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. @@ -188,12 +196,14 @@ impl TypedArena { 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); } } } @@ -230,13 +240,14 @@ impl Drop for TypedArena { 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`. } @@ -260,6 +271,12 @@ mod tests { z: i32, } + #[test] + pub fn test_unused() { + let arena: TypedArena = TypedArena::new(); + assert!(arena.chunks.borrow().is_empty()); + } + #[test] fn test_arena_alloc_nested() { struct Inner { From 429ba7ba9a61f2c24e92849d8d3b37ad7ffeb843 Mon Sep 17 00:00:00 2001 From: Nick Platt Date: Tue, 20 Sep 2016 11:20:19 -0400 Subject: [PATCH 07/11] Minor correction in `sort_by_key` doc comment --- src/libcollections/slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 5cdf4ee88c00c..54dc7ec06da16 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1037,7 +1037,7 @@ impl [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 From 23efc5453d2c43ac143cf5d4a695b9fd9e8c695d Mon Sep 17 00:00:00 2001 From: aclarry Date: Fri, 16 Sep 2016 00:10:32 -0400 Subject: [PATCH 08/11] Update E0560 to include label --- src/librustc_typeck/check/mod.rs | 13 ++++++++++++- src/test/compile-fail/E0559.rs | 2 +- src/test/compile-fail/E0560.rs | 4 +++- src/test/compile-fail/issue-19922.rs | 1 + src/test/compile-fail/numeric-fields.rs | 8 ++++++-- .../compile-fail/struct-fields-hints-no-dupe.rs | 2 +- src/test/compile-fail/struct-fields-hints.rs | 2 +- src/test/compile-fail/struct-fields-too-many.rs | 4 +++- src/test/compile-fail/suggest-private-fields.rs | 8 ++++---- src/test/compile-fail/union/union-fields.rs | 2 ++ src/test/compile-fail/union/union-suggest-field.rs | 2 +- 11 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index baa084212a2d9..7c9467bc5fed6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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(); } diff --git a/src/test/compile-fail/E0559.rs b/src/test/compile-fail/E0559.rs index aeeeae4222813..fa6c885843e4c 100644 --- a/src/test/compile-fail/E0559.rs +++ b/src/test/compile-fail/E0559.rs @@ -15,5 +15,5 @@ enum Field { fn main() { let s = Field::Fool { joke: 0 }; //~^ ERROR E0559 - //~| NOTE did you mean `x`? + //~| NOTE field does not exist - did you mean `x`? } diff --git a/src/test/compile-fail/E0560.rs b/src/test/compile-fail/E0560.rs index ec9b86ee1f00f..c6326a0f97740 100644 --- a/src/test/compile-fail/E0560.rs +++ b/src/test/compile-fail/E0560.rs @@ -13,5 +13,7 @@ struct Simba { } fn main() { - let s = Simba { mother: 1, father: 0 }; //~ ERROR E0560 + let s = Simba { mother: 1, father: 0 }; + //~^ ERROR E0560 + //~| NOTE `Simba` does not have this field } diff --git a/src/test/compile-fail/issue-19922.rs b/src/test/compile-fail/issue-19922.rs index a8350fe0986c0..d7b2f2b3f991e 100644 --- a/src/test/compile-fail/issue-19922.rs +++ b/src/test/compile-fail/issue-19922.rs @@ -15,4 +15,5 @@ enum Homura { fn main() { let homura = Homura::Akemi { kaname: () }; //~^ ERROR variant `Homura::Akemi` has no field named `kaname` + //~| NOTE field does not exist - did you mean `madoka`? } diff --git a/src/test/compile-fail/numeric-fields.rs b/src/test/compile-fail/numeric-fields.rs index c4aff9471b8a1..a67707257d2f2 100644 --- a/src/test/compile-fail/numeric-fields.rs +++ b/src/test/compile-fail/numeric-fields.rs @@ -13,8 +13,12 @@ struct S(u8, u16); fn main() { - let s = S{0b1: 10, 0: 11}; //~ ERROR struct `S` has no field named `0b1` + let s = S{0b1: 10, 0: 11}; + //~^ ERROR struct `S` has no field named `0b1` + //~| NOTE field does not exist - did you mean `1`? match s { - S{0: a, 0x1: b, ..} => {} //~ ERROR does not have a field named `0x1` + S{0: a, 0x1: b, ..} => {} + //~^ ERROR does not have a field named `0x1` + //~| NOTE struct `S::{{constructor}}` does not have field `0x1` } } diff --git a/src/test/compile-fail/struct-fields-hints-no-dupe.rs b/src/test/compile-fail/struct-fields-hints-no-dupe.rs index f25f01af33fd1..de78503d9044f 100644 --- a/src/test/compile-fail/struct-fields-hints-no-dupe.rs +++ b/src/test/compile-fail/struct-fields-hints-no-dupe.rs @@ -19,7 +19,7 @@ fn main() { foo : 5, bar : 42, //~^ ERROR struct `A` has no field named `bar` - //~| NOTE did you mean `barr`? + //~| NOTE field does not exist - did you mean `barr`? car : 9, }; } diff --git a/src/test/compile-fail/struct-fields-hints.rs b/src/test/compile-fail/struct-fields-hints.rs index 62ec6e6b0d249..628f03f3272ca 100644 --- a/src/test/compile-fail/struct-fields-hints.rs +++ b/src/test/compile-fail/struct-fields-hints.rs @@ -19,6 +19,6 @@ fn main() { foo : 5, bar : 42, //~^ ERROR struct `A` has no field named `bar` - //~| NOTE did you mean `car`? + //~| NOTE field does not exist - did you mean `car`? }; } diff --git a/src/test/compile-fail/struct-fields-too-many.rs b/src/test/compile-fail/struct-fields-too-many.rs index 5d16573f2f1e3..0848ada731a65 100644 --- a/src/test/compile-fail/struct-fields-too-many.rs +++ b/src/test/compile-fail/struct-fields-too-many.rs @@ -15,6 +15,8 @@ struct BuildData { fn main() { let foo = BuildData { foo: 0, - bar: 0 //~ ERROR struct `BuildData` has no field named `bar` + bar: 0 + //~^ ERROR struct `BuildData` has no field named `bar` + //~| NOTE `BuildData` does not have this field }; } diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs index 906bfc78498e4..3672e0e90c2a2 100644 --- a/src/test/compile-fail/suggest-private-fields.rs +++ b/src/test/compile-fail/suggest-private-fields.rs @@ -24,18 +24,18 @@ fn main () { let k = B { aa: 20, //~^ ERROR struct `xc::B` has no field named `aa` - //~| NOTE did you mean `a`? + //~| NOTE field does not exist - did you mean `a`? bb: 20, //~^ ERROR struct `xc::B` has no field named `bb` - //~| NOTE did you mean `a`? + //~| NOTE field does not exist - did you mean `a`? }; // local crate struct let l = A { aa: 20, //~^ ERROR struct `A` has no field named `aa` - //~| NOTE did you mean `a`? + //~| NOTE field does not exist - did you mean `a`? bb: 20, //~^ ERROR struct `A` has no field named `bb` - //~| NOTE did you mean `b`? + //~| NOTE field does not exist - did you mean `b`? }; } diff --git a/src/test/compile-fail/union/union-fields.rs b/src/test/compile-fail/union/union-fields.rs index a1721dda7decb..3ee95c2ef4258 100644 --- a/src/test/compile-fail/union/union-fields.rs +++ b/src/test/compile-fail/union/union-fields.rs @@ -21,6 +21,7 @@ fn main() { let u = U { a: 0, b: 1 }; //~ ERROR union expressions should have exactly one field let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field //~^ ERROR union `U` has no field named `c` + //~| NOTE `U` does not have this field let u = U { ..u }; //~ ERROR union expressions should have exactly one field //~^ ERROR functional record update syntax requires a struct @@ -29,6 +30,7 @@ fn main() { let U { a, b } = u; //~ ERROR union patterns should have exactly one field let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field //~^ ERROR union `U` does not have a field named `c` + //~| NOTE union `U` does not have field `c` let U { .. } = u; //~ ERROR union patterns should have exactly one field //~^ ERROR `..` cannot be used in union patterns let U { a, .. } = u; //~ ERROR `..` cannot be used in union patterns diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs index 92811b6b5be11..ce421428d883b 100644 --- a/src/test/compile-fail/union/union-suggest-field.rs +++ b/src/test/compile-fail/union/union-suggest-field.rs @@ -21,7 +21,7 @@ impl U { fn main() { let u = U { principle: 0 }; //~^ ERROR union `U` has no field named `principle` - //~| NOTE did you mean `principal`? + //~| NOTE field does not exist - did you mean `principal`? let w = u.principial; //~ ERROR attempted access of field `principial` on type `U` //~^ HELP did you mean `principal`? From e4b18422ad3ee6bf1e749ccd337a25736a78c0bb Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 20 Sep 2016 15:39:05 -0700 Subject: [PATCH 09/11] Check for overlapping and simplify unit test --- src/libsyntax/codemap.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index ce15bd89590bc..6d68ce3646d53 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -392,8 +392,8 @@ impl CodeMap { return None; } - // ensure these follow the expected order - if sp_lhs.lo <= sp_rhs.lo { + // 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), @@ -1146,12 +1146,7 @@ mod tests { let span1 = span_from_selection(inputtext, selection1); let span2 = span_from_selection(inputtext, selection2); - if let Some(_) = cm.merge_spans(span1, span2) { - assert!(false); - } - else { - assert!(true); - } + assert!(cm.merge_spans(span1, span2).is_none()); } /// Returns the span corresponding to the `n`th occurrence of From c316ae56e65169edacda1faace93a09cdbaa3d7f Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Sat, 17 Sep 2016 11:22:04 -0700 Subject: [PATCH 10/11] Tweak std::rc docs Fixes #29372. --- src/liballoc/rc.rs | 470 ++++++++++++++++++++++++++++++--------------- 1 file changed, 310 insertions(+), 160 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 32e5587ff4128..e0f635f195bcd 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -10,90 +10,138 @@ #![allow(deprecated)] -//! Unsynchronized reference-counted boxes (the `Rc` type) which are usable -//! only within a single thread. +//! Single-threaded reference-counting pointers. //! -//! The `Rc` type provides shared ownership of an immutable value. -//! Destruction is deterministic, and will occur as soon as the last owner is -//! gone. It is marked as non-sendable because it avoids the overhead of atomic -//! reference counting. +//! The type [`Rc`][rc] provides shared ownership of a value, allocated +//! in the heap. Invoking [`clone`][clone] on `Rc` produces a new pointer +//! to the same value in the heap. When the last `Rc` pointer to a given +//! value is destroyed, the pointed-to value is also destroyed. //! -//! The `downgrade` method can be used to create a non-owning `Weak` pointer -//! to the box. A `Weak` pointer can be upgraded to an `Rc` pointer, but -//! will return `None` if the value has already been dropped. +//! Shared pointers in Rust disallow mutation by default, and `Rc` is no +//! exception. If you need to mutate through an `Rc`, use [`Cell`][cell] or +//! [`RefCell`][refcell]. //! -//! For example, a tree with parent pointers can be represented by putting the -//! nodes behind strong `Rc` pointers, and then storing the parent pointers -//! as `Weak` pointers. +//! `Rc` uses non-atomic reference counting. This means that overhead is very +//! low, but an `Rc` cannot be sent between threads, and consequently `Rc` +//! does not implement [`Send`][send]. As a result, the Rust compiler +//! will check *at compile time* that you are not sending `Rc`s between +//! threads. If you need multi-threaded, atomic reference counting, use +//! [`sync::Arc`][arc]. +//! +//! The [`downgrade`][downgrade] method can be used to create a non-owning +//! [`Weak`][weak] pointer. A `Weak` pointer can be [`upgrade`][upgrade]d +//! to an `Rc`, but this will return [`None`][option] if the value has +//! already been dropped. +//! +//! A cycle between `Rc` pointers will never be deallocated. For this reason, +//! `Weak` is used to break cycles. For example, a tree could have strong +//! `Rc` pointers from parent nodes to children, and `Weak` pointers from +//! children back to their parents. +//! +//! `Rc` automatically dereferences to `T` (via the [`Deref`][deref] trait), +//! so you can call `T`'s methods on a value of type `Rc`. To avoid name +//! clashes with `T`'s methods, the methods of `Rc` itself are [associated +//! functions][assoc], called using function-like syntax: +//! +//! ``` +//! # use std::rc::Rc; +//! # let my_rc = Rc::new(()); +//! Rc::downgrade(&my_rc); +//! ``` +//! +//! `Weak` does not auto-dereference to `T`, because the value may have +//! already been destroyed. +//! +//! [rc]: struct.Rc.html +//! [weak]: struct.Weak.html +//! [clone]: ../../std/clone/trait.Clone.html#tymethod.clone +//! [cell]: ../../std/cell/struct.Cell.html +//! [refcell]: ../../std/cell/struct.RefCell.html +//! [send]: ../../std/marker/trait.Send.html +//! [arc]: ../../std/sync/struct.Arc.html +//! [deref]: ../../std/ops/trait.Deref.html +//! [downgrade]: struct.Rc.html#method.downgrade +//! [upgrade]: struct.Weak.html#method.upgrade +//! [option]: ../../std/option/enum.Option.html +//! [assoc]: ../../book/method-syntax.html#associated-functions //! //! # Examples //! //! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. //! We want to have our `Gadget`s point to their `Owner`. We can't do this with //! unique ownership, because more than one gadget may belong to the same -//! `Owner`. `Rc` allows us to share an `Owner` between multiple `Gadget`s, +//! `Owner`. `Rc` allows us to share an `Owner` between multiple `Gadget`s, //! and have the `Owner` remain allocated as long as any `Gadget` points at it. //! -//! ```rust +//! ``` //! use std::rc::Rc; //! //! struct Owner { -//! name: String +//! name: String, //! // ...other fields //! } //! //! struct Gadget { //! id: i32, -//! owner: Rc +//! owner: Rc, //! // ...other fields //! } //! //! fn main() { -//! // Create a reference counted Owner. -//! let gadget_owner : Rc = Rc::new( -//! Owner { name: String::from("Gadget Man") } +//! // Create a reference-counted `Owner`. +//! let gadget_owner: Rc = Rc::new( +//! Owner { +//! name: "Gadget Man".to_string(), +//! } //! ); //! -//! // Create Gadgets belonging to gadget_owner. To increment the reference -//! // count we clone the `Rc` object. -//! let gadget1 = Gadget { id: 1, owner: gadget_owner.clone() }; -//! let gadget2 = Gadget { id: 2, owner: gadget_owner.clone() }; +//! // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc` +//! // value gives us a new pointer to the same `Owner` value, incrementing +//! // the reference count in the process. +//! let gadget1 = Gadget { +//! id: 1, +//! owner: gadget_owner.clone(), +//! }; +//! let gadget2 = Gadget { +//! id: 2, +//! owner: gadget_owner.clone(), +//! }; //! +//! // Dispose of our local variable `gadget_owner`. //! drop(gadget_owner); //! -//! // Despite dropping gadget_owner, we're still able to print out the name -//! // of the Owner of the Gadgets. This is because we've only dropped the -//! // reference count object, not the Owner it wraps. As long as there are -//! // other `Rc` objects pointing at the same Owner, it will remain -//! // allocated. Notice that the `Rc` wrapper around Gadget.owner gets -//! // automatically dereferenced for us. +//! // Despite dropping `gadget_owner`, we're still able to print out the name +//! // of the `Owner` of the `Gadget`s. This is because we've only dropped a +//! // single `Rc`, not the `Owner` it points to. As long as there are +//! // other `Rc` values pointing at the same `Owner`, it will remain +//! // allocated. The field projection `gadget1.owner.name` works because +//! // `Rc` automatically dereferences to `Owner`. //! println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name); //! println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name); //! -//! // At the end of the method, gadget1 and gadget2 get destroyed, and with -//! // them the last counted references to our Owner. Gadget Man now gets -//! // destroyed as well. +//! // At the end of the function, `gadget1` and `gadget2` are destroyed, and +//! // with them the last counted references to our `Owner`. Gadget Man now +//! // gets destroyed as well. //! } //! ``` //! //! If our requirements change, and we also need to be able to traverse from -//! Owner → Gadget, we will run into problems: an `Rc` pointer from Owner -//! → Gadget introduces a cycle between the objects. This means that their -//! reference counts can never reach 0, and the objects will remain allocated: a -//! memory leak. In order to get around this, we can use `Weak` pointers. -//! These pointers don't contribute to the total count. +//! `Owner` to `Gadget`, we will run into problems. An `Rc` pointer from `Owner` +//! to `Gadget` introduces a cycle between the values. This means that their +//! reference counts can never reach 0, and the values will remain allocated +//! forever: a memory leak. In order to get around this, we can use `Weak` +//! pointers. //! //! Rust actually makes it somewhat difficult to produce this loop in the first -//! place: in order to end up with two objects that point at each other, one of -//! them needs to be mutable. This is problematic because `Rc` enforces -//! memory safety by only giving out shared references to the object it wraps, +//! place. In order to end up with two values that point at each other, one of +//! them needs to be mutable. This is difficult because `Rc` enforces +//! memory safety by only giving out shared references to the value it wraps, //! and these don't allow direct mutation. We need to wrap the part of the -//! object we wish to mutate in a `RefCell`, which provides *interior +//! value we wish to mutate in a [`RefCell`][refcell], which provides *interior //! mutability*: a method to achieve mutability through a shared reference. -//! `RefCell` enforces Rust's borrowing rules at runtime. Read the `Cell` -//! documentation for more details on interior mutability. +//! `RefCell` enforces Rust's borrowing rules at runtime. //! -//! ```rust +//! ``` //! use std::rc::Rc; //! use std::rc::Weak; //! use std::cell::RefCell; @@ -111,41 +159,58 @@ //! } //! //! fn main() { -//! // Create a reference counted Owner. Note the fact that we've put the -//! // Owner's vector of Gadgets inside a RefCell so that we can mutate it -//! // through a shared reference. -//! let gadget_owner : Rc = Rc::new( +//! // Create a reference-counted `Owner`. Note that we've put the `Owner`'s +//! // vector of `Gadget`s inside a `RefCell` so that we can mutate it through +//! // a shared reference. +//! let gadget_owner: Rc = Rc::new( //! Owner { //! name: "Gadget Man".to_string(), -//! gadgets: RefCell::new(Vec::new()), +//! gadgets: RefCell::new(vec![]), //! } //! ); //! -//! // Create Gadgets belonging to gadget_owner as before. -//! let gadget1 = Rc::new(Gadget{id: 1, owner: gadget_owner.clone()}); -//! let gadget2 = Rc::new(Gadget{id: 2, owner: gadget_owner.clone()}); +//! // Create `Gadget`s belonging to `gadget_owner`, as before. +//! let gadget1 = Rc::new( +//! Gadget { +//! id: 1, +//! owner: gadget_owner.clone(), +//! } +//! ); +//! let gadget2 = Rc::new( +//! Gadget { +//! id: 2, +//! owner: gadget_owner.clone(), +//! } +//! ); +//! +//! // Add the `Gadget`s to their `Owner`. +//! { +//! let mut gadgets = gadget_owner.gadgets.borrow_mut(); +//! gadgets.push(Rc::downgrade(&gadget1)); +//! gadgets.push(Rc::downgrade(&gadget2)); //! -//! // Add the Gadgets to their Owner. To do this we mutably borrow from -//! // the RefCell holding the Owner's Gadgets. -//! gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget1)); -//! gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget2)); +//! // `RefCell` dynamic borrow ends here. +//! } //! -//! // Iterate over our Gadgets, printing their details out -//! for gadget_opt in gadget_owner.gadgets.borrow().iter() { +//! // Iterate over our `Gadget`s, printing their details out. +//! for gadget_weak in gadget_owner.gadgets.borrow().iter() { //! -//! // gadget_opt is a Weak. Since weak pointers can't guarantee -//! // that their object is still allocated, we need to call upgrade() -//! // on them to turn them into a strong reference. This returns an -//! // Option, which contains a reference to our object if it still -//! // exists. -//! let gadget = gadget_opt.upgrade().unwrap(); +//! // `gadget_weak` is a `Weak`. Since `Weak` pointers can't +//! // guarantee the value is still allocated, we need to call +//! // `upgrade`, which returns an `Option>`. +//! // +//! // In this case we know the value still exists, so we simply +//! // `unwrap` the `Option`. In a more complicated program, you might +//! // need graceful error handling for a `None` result. +//! +//! let gadget = gadget_weak.upgrade().unwrap(); //! println!("Gadget {} owned by {}", gadget.id, gadget.owner.name); //! } //! -//! // At the end of the method, gadget_owner, gadget1 and gadget2 get -//! // destroyed. There are now no strong (`Rc`) references to the gadgets. -//! // Once they get destroyed, the Gadgets get destroyed. This zeroes the -//! // reference count on Gadget Man, they get destroyed as well. +//! // At the end of the function, `gadget_owner`, `gadget1`, and `gadget2` +//! // are destroyed. There are now no strong (`Rc`) pointers to the +//! // gadgets, so they are destroyed. This zeroes the reference count on +//! // Gadget Man, so he gets destroyed as well. //! } //! ``` @@ -179,15 +244,14 @@ struct RcBox { } -/// A reference-counted pointer type over an immutable value. +/// A single-threaded reference-counting pointer. /// -/// See the [module level documentation](./index.html) for more details. +/// See the [module-level documentation](./index.html) for more details. /// -/// Note: the inherent methods defined on `Rc` are all associated functions, -/// which means that you have to call them as e.g. `Rc::get_mut(&value)` instead -/// of `value.get_mut()`. This is so that there are no conflicts with methods -/// on the inner type `T`, which are what you want to call in the majority of -/// cases. +/// The inherent methods of `Rc` are all associated functions, which means +/// that you have to call them as e.g. `Rc::get_mut(&value)` instead of +/// `value.get_mut()`. This avoids conflicts with methods of the inner +/// type `T`. #[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { @@ -229,9 +293,9 @@ impl Rc { } } - /// Unwraps the contained value if the `Rc` has exactly one strong reference. + /// Returns the contained value, if the `Rc` has exactly one strong reference. /// - /// Otherwise, an `Err` is returned with the same `Rc`. + /// Otherwise, an `Err` is returned with the same `Rc` that was passed in. /// /// This will succeed even if there are outstanding weak references. /// @@ -245,7 +309,7 @@ impl Rc { /// /// let x = Rc::new(4); /// let _y = x.clone(); - /// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4))); + /// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4); /// ``` #[inline] #[stable(feature = "rc_unique", since = "1.4.0")] @@ -268,7 +332,7 @@ impl Rc { } } - /// Checks if `Rc::try_unwrap` would return `Ok`. + /// Checks whether `Rc::try_unwrap` would return `Ok`. /// /// # Examples /// @@ -284,7 +348,7 @@ impl Rc { /// let x = Rc::new(4); /// let _y = x.clone(); /// assert!(!Rc::would_unwrap(&x)); - /// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4))); + /// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4); /// ``` #[unstable(feature = "rc_would_unwrap", reason = "just added for niche usecase", @@ -295,7 +359,9 @@ impl Rc { } impl Rc { - /// Creates a new `Weak` reference from this value. + /// Creates a new [`Weak`][weak] pointer to this value. + /// + /// [weak]: struct.Weak.html /// /// # Examples /// @@ -312,7 +378,22 @@ impl Rc { Weak { ptr: this.ptr } } - /// Get the number of weak references to this value. + /// Gets the number of [`Weak`][weak] pointers to this value. + /// + /// [weak]: struct.Weak.html + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_counts)] + /// + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let _weak_five = Rc::downgrade(&five); + /// + /// assert_eq!(1, Rc::weak_count(&five)); + /// ``` #[inline] #[unstable(feature = "rc_counts", reason = "not clearly useful", issue = "28356")] @@ -320,7 +401,20 @@ impl Rc { this.weak() - 1 } - /// Get the number of strong references to this value. + /// Gets the number of strong (`Rc`) pointers to this value. + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_counts)] + /// + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let _also_five = five.clone(); + /// + /// assert_eq!(2, Rc::strong_count(&five)); + /// ``` #[inline] #[unstable(feature = "rc_counts", reason = "not clearly useful", issue = "28356")] @@ -328,8 +422,10 @@ impl Rc { this.strong() } - /// Returns true if there are no other `Rc` or `Weak` values that share - /// the same inner value. + /// Returns true if there are no other `Rc` or [`Weak`][weak] pointers to + /// this inner value. + /// + /// [weak]: struct.Weak.html /// /// # Examples /// @@ -349,10 +445,19 @@ impl Rc { Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 } - /// Returns a mutable reference to the contained value if the `Rc` has - /// one strong reference and no weak references. + /// Returns a mutable reference to the inner value, if there are + /// no other `Rc` or [`Weak`][weak] pointers to the same value. + /// + /// Returns [`None`][option] otherwise, because it is not safe to + /// mutate a shared value. /// - /// Returns `None` if the `Rc` is not unique. + /// See also [`make_mut`][make_mut], which will [`clone`][clone] + /// the inner value when it's shared. + /// + /// [weak]: struct.Weak.html + /// [option]: ../../std/option/enum.Option.html + /// [make_mut]: struct.Rc.html#method.make_mut + /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone /// /// # Examples /// @@ -381,8 +486,8 @@ impl Rc { #[unstable(feature = "ptr_eq", reason = "newly added", issue = "36497")] - /// Return whether two `Rc` references point to the same value - /// (not just values that compare equal). + /// Returns true if the two `Rc`s point to the same value (not + /// just values that compare as equal). /// /// # Examples /// @@ -406,11 +511,17 @@ impl Rc { } impl Rc { - /// Make a mutable reference into the given `Rc` by cloning the inner - /// data if the `Rc` doesn't have one strong reference and no weak - /// references. + /// Makes a mutable reference into the given `Rc`. + /// + /// If there are other `Rc` or [`Weak`][weak] pointers to the same value, + /// then `make_mut` will invoke [`clone`][clone] on the inner value to + /// ensure unique ownership. This is also referred to as clone-on-write. /// - /// This is also referred to as a copy-on-write. + /// See also [`get_mut`][get_mut], which will fail rather than cloning. + /// + /// [weak]: struct.Weak.html + /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone + /// [get_mut]: struct.Rc.html#method.get_mut /// /// # Examples /// @@ -419,16 +530,15 @@ impl Rc { /// /// let mut data = Rc::new(5); /// - /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// let mut other_data = data.clone(); // Won't clone inner data - /// *Rc::make_mut(&mut data) += 1; // Clones inner data - /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything + /// *Rc::make_mut(&mut data) += 1; // Won't clone anything + /// let mut other_data = data.clone(); // Won't clone inner data + /// *Rc::make_mut(&mut data) += 1; // Clones inner data + /// *Rc::make_mut(&mut data) += 1; // Won't clone anything + /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything /// - /// // Note: data and other_data now point to different numbers + /// // Now `data` and `other_data` point to different values. /// assert_eq!(*data, 8); /// assert_eq!(*other_data, 12); - /// /// ``` #[inline] #[stable(feature = "rc_unique", since = "1.4.0")] @@ -470,30 +580,30 @@ impl Deref for Rc { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { - /// Drops the `Rc`. + /// Drops the `Rc`. /// /// This will decrement the strong reference count. If the strong reference - /// count becomes zero and the only other references are `Weak` ones, - /// `drop`s the inner value. + /// count reaches zero then the only other references (if any) are `Weak`, + /// so we `drop` the inner value. /// /// # Examples /// /// ``` /// use std::rc::Rc; /// - /// { - /// let five = Rc::new(5); + /// struct Foo; /// - /// // stuff - /// - /// drop(five); // explicit drop + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } /// } - /// { - /// let five = Rc::new(5); /// - /// // stuff + /// let foo = Rc::new(Foo); + /// let foo2 = foo.clone(); /// - /// } // implicit drop + /// drop(foo); // Doesn't print anything + /// drop(foo2); // Prints "dropped!" /// ``` #[unsafe_destructor_blind_to_params] fn drop(&mut self) { @@ -519,10 +629,10 @@ impl Drop for Rc { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Rc { - /// Makes a clone of the `Rc`. + /// Makes a clone of the `Rc` pointer. /// - /// When you clone an `Rc`, it will create another pointer to the data and - /// increase the strong reference counter. + /// This creates another pointer to the same inner value, increasing the + /// strong reference count. /// /// # Examples /// @@ -550,6 +660,7 @@ impl Default for Rc { /// use std::rc::Rc; /// /// let x: Rc = Default::default(); + /// assert_eq!(*x, 0); /// ``` #[inline] fn default() -> Rc { @@ -559,9 +670,9 @@ impl Default for Rc { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for Rc { - /// Equality for two `Rc`s. + /// Equality for two `Rc`s. /// - /// Two `Rc`s are equal if their inner value are equal. + /// Two `Rc`s are equal if their inner values are equal. /// /// # Examples /// @@ -570,16 +681,16 @@ impl PartialEq for Rc { /// /// let five = Rc::new(5); /// - /// five == Rc::new(5); + /// assert!(five == Rc::new(5)); /// ``` #[inline(always)] fn eq(&self, other: &Rc) -> bool { **self == **other } - /// Inequality for two `Rc`s. + /// Inequality for two `Rc`s. /// - /// Two `Rc`s are unequal if their inner value are unequal. + /// Two `Rc`s are unequal if their inner values are unequal. /// /// # Examples /// @@ -588,7 +699,7 @@ impl PartialEq for Rc { /// /// let five = Rc::new(5); /// - /// five != Rc::new(5); + /// assert!(five != Rc::new(6)); /// ``` #[inline(always)] fn ne(&self, other: &Rc) -> bool { @@ -601,7 +712,7 @@ impl Eq for Rc {} #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Rc { - /// Partial comparison for two `Rc`s. + /// Partial comparison for two `Rc`s. /// /// The two are compared by calling `partial_cmp()` on their inner values. /// @@ -609,17 +720,18 @@ impl PartialOrd for Rc { /// /// ``` /// use std::rc::Rc; + /// use std::cmp::Ordering; /// /// let five = Rc::new(5); /// - /// five.partial_cmp(&Rc::new(5)); + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Rc::new(6))); /// ``` #[inline(always)] fn partial_cmp(&self, other: &Rc) -> Option { (**self).partial_cmp(&**other) } - /// Less-than comparison for two `Rc`s. + /// Less-than comparison for two `Rc`s. /// /// The two are compared by calling `<` on their inner values. /// @@ -630,14 +742,14 @@ impl PartialOrd for Rc { /// /// let five = Rc::new(5); /// - /// five < Rc::new(5); + /// assert!(five < Rc::new(6)); /// ``` #[inline(always)] fn lt(&self, other: &Rc) -> bool { **self < **other } - /// 'Less-than or equal to' comparison for two `Rc`s. + /// 'Less than or equal to' comparison for two `Rc`s. /// /// The two are compared by calling `<=` on their inner values. /// @@ -648,14 +760,14 @@ impl PartialOrd for Rc { /// /// let five = Rc::new(5); /// - /// five <= Rc::new(5); + /// assert!(five <= Rc::new(5)); /// ``` #[inline(always)] fn le(&self, other: &Rc) -> bool { **self <= **other } - /// Greater-than comparison for two `Rc`s. + /// Greater-than comparison for two `Rc`s. /// /// The two are compared by calling `>` on their inner values. /// @@ -666,14 +778,14 @@ impl PartialOrd for Rc { /// /// let five = Rc::new(5); /// - /// five > Rc::new(5); + /// assert!(five > Rc::new(4)); /// ``` #[inline(always)] fn gt(&self, other: &Rc) -> bool { **self > **other } - /// 'Greater-than or equal to' comparison for two `Rc`s. + /// 'Greater than or equal to' comparison for two `Rc`s. /// /// The two are compared by calling `>=` on their inner values. /// @@ -684,7 +796,7 @@ impl PartialOrd for Rc { /// /// let five = Rc::new(5); /// - /// five >= Rc::new(5); + /// assert!(five >= Rc::new(5)); /// ``` #[inline(always)] fn ge(&self, other: &Rc) -> bool { @@ -694,7 +806,7 @@ impl PartialOrd for Rc { #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Rc { - /// Comparison for two `Rc`s. + /// Comparison for two `Rc`s. /// /// The two are compared by calling `cmp()` on their inner values. /// @@ -702,10 +814,11 @@ impl Ord for Rc { /// /// ``` /// use std::rc::Rc; + /// use std::cmp::Ordering; /// /// let five = Rc::new(5); /// - /// five.partial_cmp(&Rc::new(5)); + /// assert_eq!(Ordering::Less, five.cmp(&Rc::new(6))); /// ``` #[inline] fn cmp(&self, other: &Rc) -> Ordering { @@ -748,12 +861,18 @@ impl From for Rc { } } -/// A weak version of `Rc`. +/// A weak version of [`Rc`][rc]. +/// +/// `Weak` pointers do not count towards determining if the inner value +/// should be dropped. +/// +/// The typical way to obtain a `Weak` pointer is to call +/// [`Rc::downgrade`][downgrade]. /// -/// Weak references do not count when determining if the inner value should be -/// dropped. +/// See the [module-level documentation](./index.html) for more details. /// -/// See the [module level documentation](./index.html) for more. +/// [rc]: struct.Rc.html +/// [downgrade]: struct.Rc.html#method.downgrade #[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { @@ -769,10 +888,14 @@ impl !marker::Sync for Weak {} impl, U: ?Sized> CoerceUnsized> for Weak {} impl Weak { - /// Constructs a new `Weak` without an accompanying instance of T. + /// Constructs a new `Weak`, without an accompanying instance of `T`. /// - /// This allocates memory for T, but does not initialize it. Calling - /// Weak::upgrade() on the return value always gives None. + /// This allocates memory for `T`, but does not initialize it. Calling + /// [`upgrade`][upgrade] on the return value always gives + /// [`None`][option]. + /// + /// [upgrade]: struct.Weak.html#method.upgrade + /// [option]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -780,6 +903,7 @@ impl Weak { /// use std::rc::Weak; /// /// let empty: Weak = Weak::new(); + /// assert!(empty.upgrade().is_none()); /// ``` #[stable(feature = "downgraded_weak", since = "1.10.0")] pub fn new() -> Weak { @@ -796,12 +920,13 @@ impl Weak { } impl Weak { - /// Upgrades a weak reference to a strong reference. + /// Upgrades the `Weak` pointer to an [`Rc`][rc], if possible. /// - /// Upgrades the `Weak` reference to an `Rc`, if possible. + /// Returns [`None`][option] if the strong count has reached zero and the + /// inner value was destroyed. /// - /// Returns `None` if there were no strong references and the data was - /// destroyed. + /// [rc]: struct.Rc.html + /// [option]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -813,6 +938,13 @@ impl Weak { /// let weak_five = Rc::downgrade(&five); /// /// let strong_five: Option> = weak_five.upgrade(); + /// assert!(strong_five.is_some()); + /// + /// // Destroy all strong pointers. + /// drop(strong_five); + /// drop(five); + /// + /// assert!(weak_five.upgrade().is_none()); /// ``` #[stable(feature = "rc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { @@ -827,7 +959,7 @@ impl Weak { #[stable(feature = "rc_weak", since = "1.4.0")] impl Drop for Weak { - /// Drops the `Weak`. + /// Drops the `Weak` pointer. /// /// This will decrement the weak reference count. /// @@ -836,21 +968,22 @@ impl Drop for Weak { /// ``` /// use std::rc::Rc; /// - /// { - /// let five = Rc::new(5); - /// let weak_five = Rc::downgrade(&five); - /// - /// // stuff + /// struct Foo; /// - /// drop(weak_five); // explicit drop + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } /// } - /// { - /// let five = Rc::new(5); - /// let weak_five = Rc::downgrade(&five); /// - /// // stuff + /// let foo = Rc::new(Foo); + /// let weak_foo = Rc::downgrade(&foo); + /// let other_weak_foo = weak_foo.clone(); /// - /// } // implicit drop + /// drop(weak_foo); // Doesn't print anything + /// drop(foo); // Prints "dropped!" + /// + /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { unsafe { @@ -868,9 +1001,10 @@ impl Drop for Weak { #[stable(feature = "rc_weak", since = "1.4.0")] impl Clone for Weak { - /// Makes a clone of the `Weak`. + /// Makes a clone of the `Weak` pointer. /// - /// This increases the weak reference count. + /// This creates another pointer to the same inner value, increasing the + /// weak reference count. /// /// # Examples /// @@ -897,7 +1031,23 @@ impl fmt::Debug for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Creates a new `Weak`. + /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// + /// This allocates memory for `T`, but does not initialize it. Calling + /// [`upgrade`][upgrade] on the return value always gives + /// [`None`][option]. + /// + /// [upgrade]: struct.Weak.html#method.upgrade + /// [option]: ../../std/option/enum.Option.html + /// + /// # Examples + /// + /// ``` + /// use std::rc::Weak; + /// + /// let empty: Weak = Default::default(); + /// assert!(empty.upgrade().is_none()); + /// ``` fn default() -> Weak { Weak::new() } From 8b8681e9035dea7cecc23b0e723294936c595a05 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 21 Sep 2016 14:57:04 -0400 Subject: [PATCH 11/11] Implement Debug for DirEntry. --- src/libstd/fs.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 698ec4f1b7389..05f95beac7b28 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -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 for DirEntry { fn as_inner(&self) -> &fs_imp::DirEntry { &self.0 } } @@ -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");