From b2ac1c9c6b595f39c79e13bc4e0a0411441c7543 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 16 Feb 2017 09:18:18 -0800 Subject: [PATCH 01/16] Additional docs for Vec, String, and slice trait impls --- src/libcollections/string.rs | 42 ++++++++++++++++++++++++++++++++++++ src/libcollections/vec.rs | 2 ++ src/libcore/slice.rs | 2 ++ src/libcore/str/mod.rs | 14 ++++++++++++ 4 files changed, 60 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 4c82e2e2e7e35..a1e6c7fe6fe54 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1629,6 +1629,43 @@ impl hash::Hash for String { } } +/// Implements the `+` operator for concatenating two strings. +/// +/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if +/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on +/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by +/// repeated concatenation. +/// +/// The string on the right-hand side is only borrowed; its contents are copied into the returned +/// `String`. +/// +/// # Examples +/// +/// Concatenating two `String`s takes the first by value and borrows the second: +/// +/// ``` +/// let a = String::from("hello"); +/// let b = String::from(" world"); +/// let c = a + &b; +/// // `a` is moved and can no longer be used here. +/// ``` +/// +/// If you want to keep using the first `String`, you can clone it and append to the clone instead: +/// +/// ``` +/// let a = String::from("hello"); +/// let b = String::from(" world"); +/// let c = a.clone() + &b; +/// // `a` is still valid here. +/// ``` +/// +/// Concatenating `&str` slices can be done by converting the first to a `String`: +/// +/// ``` +/// let a = "hello"; +/// let b = " world"; +/// let c = a.to_string() + b; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Add<&'a str> for String { type Output = String; @@ -1640,6 +1677,11 @@ impl<'a> Add<&'a str> for String { } } +/// Implements the `+=` operator for appending to a `String`. +/// +/// This has the same behavior as the [`push_str()`] method. +/// +/// [`push_str()`]: struct.String.html#method.push_str #[stable(feature = "stringaddassign", since = "1.12.0")] impl<'a> AddAssign<&'a str> for String { #[inline] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 9e3f117f9b20e..bc7f562452d3b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1776,6 +1776,7 @@ array_impls! { 30 31 32 } +/// Implements comparison of vectors, lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Vec { #[inline] @@ -1787,6 +1788,7 @@ impl PartialOrd for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for Vec {} +/// Implements ordering of vectors, lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Vec { #[inline] diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 3e0b842557353..0331c5d4ba401 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -2202,6 +2202,7 @@ impl PartialEq<[B]> for [A] where A: PartialEq { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for [T] {} +/// Implements comparison of vectors lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for [T] { fn cmp(&self, other: &[T]) -> Ordering { @@ -2209,6 +2210,7 @@ impl Ord for [T] { } } +/// Implements comparison of vectors lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for [T] { fn partial_cmp(&self, other: &[T]) -> Option { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 49a6b1b5fceb7..925cd84154a2e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1366,6 +1366,13 @@ mod traits { use ops; use str::eq_slice; + /// Implements ordering of strings. + /// + /// Strings are ordered lexicographically by their byte values. This orders Unicode code + /// points based on their positions in the code charts. This is not necessarily the same as + /// "alphabetical" order, which varies by language and locale. Sorting strings according to + /// culturally-accepted standards requires locale-specific data that is outside the scope of + /// the `str` type. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for str { #[inline] @@ -1387,6 +1394,13 @@ mod traits { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for str {} + /// Implements comparison operations on strings. + /// + /// Strings are compared lexicographically by their byte values. This compares Unicode code + /// points based on their positions in the code charts. This is not necessarily the same as + /// "alphabetical" order, which varies by language and locale. Comparing strings according to + /// culturally-accepted standards requires locale-specific data that is outside the scope of + /// the `str` type. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for str { #[inline] From 047a215b4d9cf762d3704ee02b76467897bbbe21 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 15 Feb 2017 22:47:11 +0100 Subject: [PATCH 02/16] Set rustdoc --test files' path relative to the current directory --- src/librustdoc/test.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1c37067d7f69d..c7000ee1e40e7 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -12,7 +12,7 @@ use std::env; use std::ffi::OsString; use std::io::prelude::*; use std::io; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::panic::{self, AssertUnwindSafe}; use std::process::Command; use std::rc::Rc; @@ -485,7 +485,15 @@ impl Collector { pub fn get_filename(&self) -> String { if let Some(ref codemap) = self.codemap { - codemap.span_to_filename(self.position) + let filename = codemap.span_to_filename(self.position); + if let Ok(cur_dir) = env::current_dir() { + if let Ok(path) = Path::new(&filename).strip_prefix(&cur_dir) { + if let Some(path) = path.to_str() { + return path.to_owned(); + } + } + } + filename } else if let Some(ref filename) = self.filename { filename.clone() } else { From 609133098bfbeae69fb9c65ca5438c411d27dfd6 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 17 Feb 2017 11:26:22 -0800 Subject: [PATCH 03/16] Follow rename of mx_handle_wait Magenta syscalls The mx_handle_wait_* syscalls in Magenta were renamed to mx_object_wait. The syscall is used in the Magenta/Fuchsia implementation of std::process, to wait on child processes. In addition, this patch enables the use of the system provided libbacktrace library on Fuchsia targets. Symbolization is not yet working, but at least it allows printing hex addresses in a backtrace and makes building succeed when the backtrace feature is not disabled. --- src/libstd/build.rs | 4 ++++ src/libstd/sys/unix/process/magenta.rs | 2 +- src/libstd/sys/unix/process/process_fuchsia.rs | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 0fca374f6e6d1..038dea77f3ead 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -59,6 +59,10 @@ fn main() { println!("cargo:rustc-link-lib=userenv"); println!("cargo:rustc-link-lib=shell32"); } else if target.contains("fuchsia") { + // use system-provided libbacktrace + if cfg!(feature = "backtrace") { + println!("cargo:rustc-link-lib=backtrace"); + } println!("cargo:rustc-link-lib=magenta"); println!("cargo:rustc-link-lib=mxio"); println!("cargo:rustc-link-lib=launchpad"); // for std::process diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs index a81bedcad22ff..08a827ce08142 100644 --- a/src/libstd/sys/unix/process/magenta.rs +++ b/src/libstd/sys/unix/process/magenta.rs @@ -111,7 +111,7 @@ extern { pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t, out: *const mx_handle_t) -> mx_handle_t; - pub fn mx_handle_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t, + pub fn mx_object_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t, pending: *mut mx_signals_t) -> mx_status_t; pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void, diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 0bb2e0c1a83d4..608e44ca9e86e 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -151,7 +151,7 @@ impl Process { let mut avail: mx_size_t = 0; unsafe { - mx_cvt(mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED, + mx_cvt(mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED, MX_TIME_INFINITE, ptr::null_mut()))?; mx_cvt(mx_object_get_info(self.handle.raw(), MX_INFO_PROCESS, &mut proc_info as *mut _ as *mut libc::c_void, @@ -174,7 +174,7 @@ impl Process { let mut avail: mx_size_t = 0; unsafe { - let status = mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED, + let status = mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED, 0, ptr::null_mut()); match status { 0 => { }, // Success From 5205e2f8b8094a5f3d0205593820391dfe481808 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 15 Feb 2017 14:52:27 -0800 Subject: [PATCH 04/16] Normalize labeled and unlabeled breaks --- src/librustc/cfg/construct.rs | 15 +-- src/librustc/hir/intravisit.rs | 20 +-- src/librustc/hir/lowering.rs | 115 ++++++++++++------ src/librustc/hir/mod.rs | 9 +- src/librustc/hir/print.rs | 12 +- src/librustc/middle/liveness.rs | 25 +--- .../calculate_svh/svh_visitor.rs | 6 +- src/librustc_mir/build/scope.rs | 22 ++-- src/librustc_mir/hair/cx/expr.rs | 4 +- src/librustc_mir/hair/mod.rs | 4 +- src/librustc_passes/loops.rs | 23 ++-- src/librustc_typeck/check/mod.rs | 14 +-- src/test/run-pass/loop-break-value.rs | 8 -- 13 files changed, 138 insertions(+), 139 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 595059332895d..bc3da13ccf82d 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -579,17 +579,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn find_scope(&self, expr: &hir::Expr, - label: Option) -> LoopScope { - match label { - None => *self.loop_scopes.last().unwrap(), - Some(label) => { - for l in &self.loop_scopes { - if l.loop_id == label.loop_id { - return *l; - } - } - span_bug!(expr.span, "no loop scope for id {}", label.loop_id); + label: hir::Label) -> LoopScope { + for l in &self.loop_scopes { + if l.loop_id == label.loop_id { + return *l; } } + span_bug!(expr.span, "no loop scope for id {}", label.loop_id); } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 1df6761506993..03b59aaf319c6 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1006,18 +1006,18 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprPath(ref qpath) => { visitor.visit_qpath(qpath, expression.id, expression.span); } - ExprBreak(None, ref opt_expr) => { + ExprBreak(label, ref opt_expr) => { + label.ident.map(|ident| { + visitor.visit_def_mention(Def::Label(label.loop_id)); + visitor.visit_name(ident.span, ident.node.name); + }); walk_list!(visitor, visit_expr, opt_expr); } - ExprBreak(Some(label), ref opt_expr) => { - visitor.visit_def_mention(Def::Label(label.loop_id)); - visitor.visit_name(label.span, label.name); - walk_list!(visitor, visit_expr, opt_expr); - } - ExprAgain(None) => {} - ExprAgain(Some(label)) => { - visitor.visit_def_mention(Def::Label(label.loop_id)); - visitor.visit_name(label.span, label.name); + ExprAgain(label) => { + label.ident.map(|ident| { + visitor.visit_def_mention(Def::Label(label.loop_id)); + visitor.visit_name(ident.span, ident.node.name); + }); } ExprRet(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8a4acb3d03880..d6f99327d4fa2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -50,6 +50,7 @@ use util::nodemap::{DefIdMap, NodeMap, FxHashMap}; use std::collections::BTreeMap; use std::iter; +use std::mem; use syntax::attr; use syntax::ast::*; @@ -79,6 +80,8 @@ pub struct LoweringContext<'a> { impl_items: BTreeMap, bodies: FxHashMap, + loop_scopes: Vec, + type_def_lifetime_params: DefIdMap, } @@ -112,6 +115,7 @@ pub fn lower_crate(sess: &Session, trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), bodies: FxHashMap(), + loop_scopes: Vec::new(), type_def_lifetime_params: DefIdMap(), }.lower_crate(krate) } @@ -244,6 +248,27 @@ impl<'a> LoweringContext<'a> { span } + fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let len = self.loop_scopes.len(); + self.loop_scopes.push(loop_id); + let result = f(self); + assert_eq!(len + 1, self.loop_scopes.len(), + "Loop scopes should be added and removed in stack order"); + self.loop_scopes.pop().unwrap(); + result + } + + fn with_new_loop_scopes(&mut self, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new()); + let result = f(self); + mem::replace(&mut self.loop_scopes, loop_scopes); + result + } + fn with_parent_def(&mut self, parent_id: NodeId, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { @@ -271,17 +296,23 @@ impl<'a> LoweringContext<'a> { o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name)) } - fn lower_label(&mut self, id: NodeId, label: Option>) -> Option { - label.map(|sp_ident| { - hir::Label { - span: sp_ident.span, - name: sp_ident.node.name, + fn lower_label(&mut self, label: Option<(NodeId, Spanned)>) -> hir::Label { + match label { + Some((id, label_ident)) => hir::Label { + ident: Some(label_ident), loop_id: match self.expect_full_def(id) { Def::Label(loop_id) => loop_id, _ => DUMMY_NODE_ID } + }, + None => hir::Label { + ident: None, + loop_id: match self.loop_scopes.last() { + Some(innermost_loop_id) => *innermost_loop_id, + _ => DUMMY_NODE_ID + } } - }) + } } fn lower_attrs(&mut self, attrs: &Vec) -> hir::HirVec { @@ -992,15 +1023,17 @@ impl<'a> LoweringContext<'a> { self.record_body(value, None)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - let body = self.lower_block(body); - let body = self.expr_block(body, ThinVec::new()); - let body_id = self.record_body(body, Some(decl)); - hir::ItemFn(self.lower_fn_decl(decl), - self.lower_unsafety(unsafety), - self.lower_constness(constness), - abi, - self.lower_generics(generics), - body_id) + self.with_new_loop_scopes(|this| { + let body = this.lower_block(body); + let body = this.expr_block(body, ThinVec::new()); + let body_id = this.record_body(body, Some(decl)); + hir::ItemFn(this.lower_fn_decl(decl), + this.lower_unsafety(unsafety), + this.lower_constness(constness), + abi, + this.lower_generics(generics), + body_id) + }) } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), @@ -1562,13 +1595,17 @@ impl<'a> LoweringContext<'a> { hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt) } ExprKind::While(ref cond, ref body, opt_ident) => { - hir::ExprWhile(P(self.lower_expr(cond)), self.lower_block(body), - self.lower_opt_sp_ident(opt_ident)) + self.with_loop_scope(e.id, |this| + hir::ExprWhile( + P(this.lower_expr(cond)), + this.lower_block(body), + this.lower_opt_sp_ident(opt_ident))) } ExprKind::Loop(ref body, opt_ident) => { - hir::ExprLoop(self.lower_block(body), - self.lower_opt_sp_ident(opt_ident), - hir::LoopSource::Loop) + self.with_loop_scope(e.id, |this| + hir::ExprLoop(this.lower_block(body), + this.lower_opt_sp_ident(opt_ident), + hir::LoopSource::Loop)) } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), @@ -1576,12 +1613,14 @@ impl<'a> LoweringContext<'a> { hir::MatchSource::Normal) } ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_parent_def(e.id, |this| { - let expr = this.lower_expr(body); - hir::ExprClosure(this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl), - this.record_body(expr, Some(decl)), - fn_decl_span) + self.with_new_loop_scopes(|this| { + this.with_parent_def(e.id, |this| { + let expr = this.lower_expr(body); + hir::ExprClosure(this.lower_capture_clause(capture_clause), + this.lower_fn_decl(decl), + this.record_body(expr, Some(decl)), + fn_decl_span) + }) }) } ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)), @@ -1660,10 +1699,13 @@ impl<'a> LoweringContext<'a> { hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) } ExprKind::Break(opt_ident, ref opt_expr) => { - hir::ExprBreak(self.lower_label(e.id, opt_ident), + hir::ExprBreak( + self.lower_label(opt_ident.map(|ident| (e.id, ident))), opt_expr.as_ref().map(|x| P(self.lower_expr(x)))) } - ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_label(e.id, opt_ident)), + ExprKind::Continue(opt_ident) => + hir::ExprAgain( + self.lower_label(opt_ident.map(|ident| (e.id, ident)))), ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))), ExprKind::InlineAsm(ref asm) => { let hir_asm = hir::InlineAsm { @@ -1804,9 +1846,14 @@ impl<'a> LoweringContext<'a> { // } // } + let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( + this.lower_block(body), + this.expr_break(e.span, ThinVec::new()), + P(this.lower_expr(sub_expr)), + )); + // ` => ` let pat_arm = { - let body = self.lower_block(body); let body_expr = P(self.expr_block(body, ThinVec::new())); let pat = self.lower_pat(pat); self.arm(hir_vec![pat], body_expr) @@ -1815,13 +1862,11 @@ impl<'a> LoweringContext<'a> { // `_ => break` let break_arm = { let pat_under = self.pat_wild(e.span); - let break_expr = self.expr_break(e.span, ThinVec::new()); self.arm(hir_vec![pat_under], break_expr) }; // `match { ... }` let arms = hir_vec![pat_arm, break_arm]; - let sub_expr = P(self.lower_expr(sub_expr)); let match_expr = self.expr(e.span, hir::ExprMatch(sub_expr, arms, @@ -1863,7 +1908,7 @@ impl<'a> LoweringContext<'a> { // `::std::option::Option::Some() => ` let pat_arm = { - let body_block = self.lower_block(body); + let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); let pat = self.lower_pat(pat); let some_pat = self.pat_some(e.span, pat); @@ -1873,7 +1918,8 @@ impl<'a> LoweringContext<'a> { // `::std::option::Option::None => break` let break_arm = { - let break_expr = self.expr_break(e.span, ThinVec::new()); + let break_expr = self.with_loop_scope(e.id, |this| + this.expr_break(e.span, ThinVec::new())); let pat = self.pat_none(e.span); self.arm(hir_vec![pat], break_expr) }; @@ -2151,7 +2197,8 @@ impl<'a> LoweringContext<'a> { } fn expr_break(&mut self, span: Span, attrs: ThinVec) -> P { - P(self.expr(span, hir::ExprBreak(None, None), attrs)) + let expr_break = hir::ExprBreak(self.lower_label(None), None); + P(self.expr(span, expr_break, attrs)) } fn expr_call(&mut self, span: Span, e: P, args: hir::HirVec) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4ebe416e1bfe6..fc5282d1af2f2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -36,7 +36,7 @@ use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; use syntax_pos::{Span, ExpnId, DUMMY_SP}; use syntax::codemap::{self, Spanned}; use syntax::abi::Abi; -use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect}; +use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; @@ -959,9 +959,9 @@ pub enum Expr_ { /// A referencing operation (`&a` or `&mut a`) ExprAddrOf(Mutability, P), /// A `break`, with an optional label to break - ExprBreak(Option