diff options
Diffstat (limited to 'src')
35 files changed, 698 insertions, 359 deletions
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 39d99af8d6a..93054f39790 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -1702,8 +1702,11 @@ fn run_codegen_test(config: &Config, props: &TestProps, testfile: &Path) { } fn charset() -> &'static str { - if cfg!(any(target_os = "bitrig", target_os = "freebsd")) { + // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset + if cfg!(target_os = "bitrig") { "auto" + } else if cfg!(target_os = "freebsd") { + "ISO-8859-1" } else { "UTF-8" } diff --git a/src/doc/complement-design-faq.md b/src/doc/complement-design-faq.md index e887ed0cc52..5e99876f5da 100644 --- a/src/doc/complement-design-faq.md +++ b/src/doc/complement-design-faq.md @@ -99,7 +99,7 @@ Second, it makes cost explicit. In general, the only safe way to have a non-exhaustive match would be to panic the thread if nothing is matched, though it could fall through if the type of the `match` expression is `()`. This sort of hidden cost and special casing is against the language's philosophy. It's -easy to ignore certain cases by using the `_` wildcard: +easy to ignore all unspecified cases by using the `_` wildcard: ```rust,ignore match val.do_something() { diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index a599b8a855e..1784c253f7f 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -360,10 +360,12 @@ rand="0.3.0" The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: everything that follows it is part of it, until the next section starts. Cargo uses the dependencies section to know what dependencies on external -crates you have, and what versions you require. In this case, we’ve used version `0.3.0`. +crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`, +which Cargo understands to be any release that’s compatible with this specific version. Cargo understands [Semantic Versioning][semver], which is a standard for writing version -numbers. If we wanted to use the latest version we could use `*` or we could use a range -of versions. [Cargo’s documentation][cargodoc] contains more details. +numbers. If we wanted to use only `0.3.0` exactly, we could use `=0.3.0`. If we +wanted to use the latest version we could use `*`; We could use a range of +versions. [Cargo’s documentation][cargodoc] contains more details. [semver]: http://semver.org [cargodoc]: http://doc.crates.io/crates-io.html diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 7dcf7a76da0..905012bbb64 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -148,4 +148,5 @@ pub fn oom() -> ! { // optimize it out). #[doc(hidden)] #[unstable(feature = "issue_14344_fixme")] +#[cfg(stage0)] pub fn fixme_14344_be_sure_to_link_to_collections() {} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 42adbe10e50..3c90a2c54e1 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -138,6 +138,7 @@ pub mod btree_set { // FIXME(#14344) this shouldn't be necessary #[doc(hidden)] #[unstable(feature = "issue_14344_fixme")] +#[cfg(stage0)] pub fn fixme_14344_be_sure_to_link_to_collections() {} #[cfg(not(test))] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c032471b6b6..3848263c530 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -67,7 +67,7 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; -use core::iter::{repeat, FromIterator}; +use core::iter::FromIterator; use core::marker::PhantomData; use core::mem; use core::ops::{Index, IndexMut, Deref}; @@ -1106,12 +1106,35 @@ impl<T: Clone> Vec<T> { let len = self.len(); if new_len > len { - self.extend(repeat(value).take(new_len - len)); + self.extend_with_element(new_len - len, value); } else { self.truncate(new_len); } } + /// Extend the vector by `n` additional clones of `value`. + fn extend_with_element(&mut self, n: usize, value: T) { + self.reserve(n); + + unsafe { + let len = self.len(); + let mut ptr = self.as_mut_ptr().offset(len as isize); + // Write all elements except the last one + for i in 1..n { + ptr::write(ptr, value.clone()); + ptr = ptr.offset(1); + // Increment the length in every step in case clone() panics + self.set_len(len + i); + } + + if n > 0 { + // We can write the last element directly without cloning needlessly + ptr::write(ptr, value); + self.set_len(len + n); + } + } + } + /// Appends all elements in a slice to the `Vec`. /// /// Iterates over the slice `other`, clones each element, and then appends @@ -1294,25 +1317,9 @@ unsafe fn dealloc<T>(ptr: *mut T, len: usize) { #[doc(hidden)] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> { - unsafe { - let mut v = Vec::with_capacity(n); - let mut ptr = v.as_mut_ptr(); - - // Write all elements except the last one - for i in 1..n { - ptr::write(ptr, Clone::clone(&elem)); - ptr = ptr.offset(1); - v.set_len(i); // Increment the length in every step in case Clone::clone() panics - } - - if n > 0 { - // We can write the last element directly without cloning needlessly - ptr::write(ptr, elem); - v.set_len(n); - } - - v - } + let mut v = Vec::with_capacity(n); + v.extend_with_element(n, elem); + v } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0bb519ec095..47030bf0fb3 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -273,6 +273,8 @@ impl<'a> Display for Arguments<'a> { /// /// Generally speaking, you should just `derive` a `Debug` implementation. /// +/// When used with the alternate format specifier `#?`, the output is pretty-printed. +/// /// For more information on formatters, see [the module-level documentation][module]. /// /// [module]: ../index.html @@ -314,6 +316,12 @@ impl<'a> Display for Arguments<'a> { /// println!("The origin is: {:?}", origin); /// ``` /// +/// This outputs: +/// +/// ```text +/// The origin is: Point { x: 0, y: 0 } +/// ``` +/// /// There are a number of `debug_*` methods on `Formatter` to help you with manual /// implementations, such as [`debug_struct`][debug_struct]. /// @@ -321,6 +329,29 @@ impl<'a> Display for Arguments<'a> { /// on `Formatter` support pretty printing using the alternate flag: `{:#?}`. /// /// [debug_struct]: ../std/fmt/struct.Formatter.html#method.debug_struct +/// +/// Pretty printing with `#?`: +/// +/// ``` +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// let origin = Point { x: 0, y: 0 }; +/// +/// println!("The origin is: {:#?}", origin); +/// ``` +/// +/// This outputs: +/// +/// ```text +/// The origin is: Point { +/// x: 0, +/// y: 0 +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \ defined in your crate, add `#[derive(Debug)]` or \ @@ -379,6 +410,8 @@ pub trait Display { /// /// The `Octal` trait should format its output as a number in base-8. /// +/// The alternate flag, `#`, adds a `0o` in front of the output. +/// /// For more information on formatters, see [the module-level documentation][module]. /// /// [module]: ../index.html @@ -391,6 +424,7 @@ pub trait Display { /// let x = 42; // 42 is '52' in octal /// /// assert_eq!(format!("{:o}", x), "52"); +/// assert_eq!(format!("{:#o}", x), "0o52"); /// ``` /// /// Implementing `Octal` on a type: @@ -423,6 +457,8 @@ pub trait Octal { /// /// The `Binary` trait should format its output as a number in binary. /// +/// The alternate flag, `#`, adds a `0b` in front of the output. +/// /// For more information on formatters, see [the module-level documentation][module]. /// /// [module]: ../index.html @@ -435,6 +471,7 @@ pub trait Octal { /// let x = 42; // 42 is '101010' in binary /// /// assert_eq!(format!("{:b}", x), "101010"); +/// assert_eq!(format!("{:#b}", x), "0b101010"); /// ``` /// /// Implementing `Binary` on a type: @@ -468,6 +505,8 @@ pub trait Binary { /// The `LowerHex` trait should format its output as a number in hexidecimal, with `a` through `f` /// in lower case. /// +/// The alternate flag, `#`, adds a `0x` in front of the output. +/// /// For more information on formatters, see [the module-level documentation][module]. /// /// [module]: ../index.html @@ -480,6 +519,7 @@ pub trait Binary { /// let x = 42; // 42 is '2a' in hex /// /// assert_eq!(format!("{:x}", x), "2a"); +/// assert_eq!(format!("{:#x}", x), "0x2a"); /// ``` /// /// Implementing `LowerHex` on a type: @@ -513,6 +553,8 @@ pub trait LowerHex { /// The `UpperHex` trait should format its output as a number in hexidecimal, with `A` through `F` /// in upper case. /// +/// The alternate flag, `#`, adds a `0x` in front of the output. +/// /// For more information on formatters, see [the module-level documentation][module]. /// /// [module]: ../index.html @@ -525,6 +567,7 @@ pub trait LowerHex { /// let x = 42; // 42 is '2A' in hex /// /// assert_eq!(format!("{:X}", x), "2A"); +/// assert_eq!(format!("{:#X}", x), "0x2A"); /// ``` /// /// Implementing `UpperHex` on a type: diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index a8c995f37cc..00e7ff3c4df 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1368,10 +1368,14 @@ pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] { /// /// The `len` argument is the number of **elements**, not the number of bytes. /// +/// # Unsafety +/// /// This function is unsafe as there is no guarantee that the given pointer is /// valid for `len` elements, nor whether the lifetime inferred is a suitable /// lifetime for the returned slice. /// +/// `p` must be non-null, even for zero-length slices. +/// /// # Caveat /// /// The lifetime for the returned slice is inferred from its usage. To @@ -1459,12 +1463,30 @@ pub mod bytes { #[stable(feature = "rust1", since = "1.0.0")] impl<A, B> PartialEq<[B]> for [A] where A: PartialEq<B> { fn eq(&self, other: &[B]) -> bool { - self.len() == other.len() && - order::eq(self.iter(), other.iter()) + if self.len() != other.len() { + return false; + } + + for i in 0..self.len() { + if !self[i].eq(&other[i]) { + return false; + } + } + + true } fn ne(&self, other: &[B]) -> bool { - self.len() != other.len() || - order::ne(self.iter(), other.iter()) + if self.len() != other.len() { + return true; + } + + for i in 0..self.len() { + if self[i].ne(&other[i]) { + return true; + } + } + + false } } diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 2c5ebc25f6b..102894bec13 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -6431,6 +6431,7 @@ pub mod funcs { } #[doc(hidden)] +#[cfg(stage0)] pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen correctly #[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c329f2fb012..3dbc80d352d 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1211,7 +1211,6 @@ register_diagnostics! { E0138, E0139, E0264, // unknown external lang item - E0266, // expected item E0269, // not all control paths return a value E0270, // computation may converge in a function marked as diverging E0272, // rustc_on_unimplemented attribute refers to non-existent type parameter diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index b677e7b8570..a9e9f17bdce 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -2136,11 +2136,7 @@ fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>, let mut rbml_w = Encoder::new(wr); encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name); - encode_crate_triple(&mut rbml_w, - &tcx.sess - .opts - .target_triple - ); + encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple); encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash); encode_dylib_dependency_formats(&mut rbml_w, &ecx); diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 41beabc9588..312a4708e8d 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -13,68 +13,90 @@ use ast_map; use session::Session; -use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefMap}; +use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefVariant, DefMap}; +use util::nodemap::NodeMap; use syntax::{ast, ast_util}; use syntax::codemap::Span; use syntax::visit::Visitor; use syntax::visit; +use std::cell::RefCell; + struct CheckCrateVisitor<'a, 'ast: 'a> { sess: &'a Session, def_map: &'a DefMap, - ast_map: &'a ast_map::Map<'ast> + ast_map: &'a ast_map::Map<'ast>, + // `discriminant_map` is a cache that associates the `NodeId`s of local + // variant definitions with the discriminant expression that applies to + // each one. If the variant uses the default values (starting from `0`), + // then `None` is stored. + discriminant_map: RefCell<NodeMap<Option<&'ast ast::Expr>>>, } -impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> { - fn visit_item(&mut self, it: &ast::Item) { +impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { + fn visit_item(&mut self, it: &'ast ast::Item) { match it.node { - ast::ItemStatic(_, _, ref expr) | - ast::ItemConst(_, ref expr) => { + ast::ItemStatic(..) | + ast::ItemConst(..) => { let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &it.span); recursion_visitor.visit_item(it); - visit::walk_expr(self, &*expr) }, - _ => visit::walk_item(self, it) + ast::ItemEnum(ref enum_def, ref generics) => { + // We could process the whole enum, but handling the variants + // with discriminant expressions one by one gives more specific, + // less redundant output. + for variant in &enum_def.variants { + if let Some(_) = variant.node.disr_expr { + let mut recursion_visitor = + CheckItemRecursionVisitor::new(self, &variant.span); + recursion_visitor.populate_enum_discriminants(enum_def); + recursion_visitor.visit_variant(variant, generics); + } + } + } + _ => {} } + visit::walk_item(self, it) } - fn visit_trait_item(&mut self, ti: &ast::TraitItem) { + fn visit_trait_item(&mut self, ti: &'ast ast::TraitItem) { match ti.node { ast::ConstTraitItem(_, ref default) => { - if let Some(ref expr) = *default { + if let Some(_) = *default { let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ti.span); recursion_visitor.visit_trait_item(ti); - visit::walk_expr(self, &*expr) } } - _ => visit::walk_trait_item(self, ti) + _ => {} } + visit::walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &ast::ImplItem) { + fn visit_impl_item(&mut self, ii: &'ast ast::ImplItem) { match ii.node { - ast::ConstImplItem(_, ref expr) => { + ast::ConstImplItem(..) => { let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ii.span); recursion_visitor.visit_impl_item(ii); - visit::walk_expr(self, &*expr) } - _ => visit::walk_impl_item(self, ii) + _ => {} } + visit::walk_impl_item(self, ii) } } pub fn check_crate<'ast>(sess: &Session, - krate: &ast::Crate, + krate: &'ast ast::Crate, def_map: &DefMap, ast_map: &ast_map::Map<'ast>) { let mut visitor = CheckCrateVisitor { sess: sess, def_map: def_map, - ast_map: ast_map + ast_map: ast_map, + discriminant_map: RefCell::new(NodeMap()), }; visit::walk_crate(&mut visitor, krate); sess.abort_if_errors(); @@ -85,23 +107,25 @@ struct CheckItemRecursionVisitor<'a, 'ast: 'a> { sess: &'a Session, ast_map: &'a ast_map::Map<'ast>, def_map: &'a DefMap, - idstack: Vec<ast::NodeId> + discriminant_map: &'a RefCell<NodeMap<Option<&'ast ast::Expr>>>, + idstack: Vec<ast::NodeId>, } impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { - fn new(v: &CheckCrateVisitor<'a, 'ast>, span: &'a Span) + fn new(v: &'a CheckCrateVisitor<'a, 'ast>, span: &'a Span) -> CheckItemRecursionVisitor<'a, 'ast> { CheckItemRecursionVisitor { root_span: span, sess: v.sess, ast_map: v.ast_map, def_map: v.def_map, - idstack: Vec::new() + discriminant_map: &v.discriminant_map, + idstack: Vec::new(), } } fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F) where F: Fn(&mut Self) { - if self.idstack.iter().any(|x| x == &(id)) { + if self.idstack.iter().any(|x| *x == id) { span_err!(self.sess, *self.root_span, E0265, "recursive constant"); return; } @@ -109,29 +133,94 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { f(self); self.idstack.pop(); } + // If a variant has an expression specifying its discriminant, then it needs + // to be checked just like a static or constant. However, if there are more + // variants with no explicitly specified discriminant, those variants will + // increment the same expression to get their values. + // + // So for every variant, we need to track whether there is an expression + // somewhere in the enum definition that controls its discriminant. We do + // this by starting from the end and searching backward. + fn populate_enum_discriminants(&self, enum_definition: &'ast ast::EnumDef) { + // Get the map, and return if we already processed this enum or if it + // has no variants. + let mut discriminant_map = self.discriminant_map.borrow_mut(); + match enum_definition.variants.first() { + None => { return; } + Some(variant) if discriminant_map.contains_key(&variant.node.id) => { + return; + } + _ => {} + } + + // Go through all the variants. + let mut variant_stack: Vec<ast::NodeId> = Vec::new(); + for variant in enum_definition.variants.iter().rev() { + variant_stack.push(variant.node.id); + // When we find an expression, every variant currently on the stack + // is affected by that expression. + if let Some(ref expr) = variant.node.disr_expr { + for id in &variant_stack { + discriminant_map.insert(*id, Some(expr)); + } + variant_stack.clear() + } + } + // If we are at the top, that always starts at 0, so any variant on the + // stack has a default value and does not need to be checked. + for id in &variant_stack { + discriminant_map.insert(*id, None); + } + } } -impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> { - fn visit_item(&mut self, it: &ast::Item) { +impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { + fn visit_item(&mut self, it: &'ast ast::Item) { self.with_item_id_pushed(it.id, |v| visit::walk_item(v, it)); } - fn visit_trait_item(&mut self, ti: &ast::TraitItem) { + fn visit_enum_def(&mut self, enum_definition: &'ast ast::EnumDef, + generics: &'ast ast::Generics) { + self.populate_enum_discriminants(enum_definition); + visit::walk_enum_def(self, enum_definition, generics); + } + + fn visit_variant(&mut self, variant: &'ast ast::Variant, + _: &'ast ast::Generics) { + let variant_id = variant.node.id; + let maybe_expr; + if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) { + // This is necessary because we need to let the `discriminant_map` + // borrow fall out of scope, so that we can reborrow farther down. + maybe_expr = (*get_expr).clone(); + } else { + self.sess.span_bug(variant.span, + "`check_static_recursion` attempted to visit \ + variant with unknown discriminant") + } + // If `maybe_expr` is `None`, that's because no discriminant is + // specified that affects this variant. Thus, no risk of recursion. + if let Some(expr) = maybe_expr { + self.with_item_id_pushed(expr.id, |v| visit::walk_expr(v, expr)); + } + } + + fn visit_trait_item(&mut self, ti: &'ast ast::TraitItem) { self.with_item_id_pushed(ti.id, |v| visit::walk_trait_item(v, ti)); } - fn visit_impl_item(&mut self, ii: &ast::ImplItem) { + fn visit_impl_item(&mut self, ii: &'ast ast::ImplItem) { self.with_item_id_pushed(ii.id, |v| visit::walk_impl_item(v, ii)); } - fn visit_expr(&mut self, e: &ast::Expr) { + fn visit_expr(&mut self, e: &'ast ast::Expr) { match e.node { ast::ExprPath(..) => { match self.def_map.borrow().get(&e.id).map(|d| d.base_def) { Some(DefStatic(def_id, _)) | Some(DefAssociatedConst(def_id, _)) | - Some(DefConst(def_id)) if - ast_util::is_local(def_id) => { + Some(DefConst(def_id)) + if ast_util::is_local(def_id) => { match self.ast_map.get(def_id.node) { ast_map::NodeItem(item) => self.visit_item(item), @@ -141,11 +230,28 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> { self.visit_impl_item(item), ast_map::NodeForeignItem(_) => {}, _ => { - span_err!(self.sess, e.span, E0266, - "expected item, found {}", - self.ast_map.node_to_string(def_id.node)); - return; - }, + self.sess.span_bug( + e.span, + &format!("expected item, found {}", + self.ast_map.node_to_string(def_id.node))); + } + } + } + // For variants, we only want to check expressions that + // affect the specific variant used, but we need to check + // the whole enum definition to see what expression that + // might be (if any). + Some(DefVariant(enum_id, variant_id, false)) + if ast_util::is_local(enum_id) => { + if let ast::ItemEnum(ref enum_def, ref generics) = + self.ast_map.expect_item(enum_id.local_id()).node { + self.populate_enum_discriminants(enum_def); + let variant = self.ast_map.expect_variant(variant_id.local_id()); + self.visit_variant(variant, generics); + } else { + self.sess.span_bug(e.span, + "`check_static_recursion` found \ + non-enum in DefVariant"); } } _ => () diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 162bf6ed9a9..77575cd6b24 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -76,12 +76,14 @@ pub fn time<T, U, F>(do_it: bool, what: &str, u: U, f: F) -> T where } // Memory reporting +#[cfg(unix)] fn get_resident() -> Option<usize> { - if cfg!(unix) { - get_proc_self_statm_field(1) - } else { - None - } + get_proc_self_statm_field(1) +} + +#[cfg(windows)] +fn get_resident() -> Option<usize> { + get_working_set_size() } // Like std::macros::try!, but for Option<>. @@ -89,6 +91,39 @@ macro_rules! option_try( ($e:expr) => (match $e { Some(e) => e, None => return None }) ); +#[cfg(windows)] +fn get_working_set_size() -> Option<usize> { + use libc::{BOOL, DWORD, HANDLE, SIZE_T, GetCurrentProcess}; + use std::mem; + #[repr(C)] #[allow(non_snake_case)] + struct PROCESS_MEMORY_COUNTERS { + cb: DWORD, + PageFaultCount: DWORD, + PeakWorkingSetSize: SIZE_T, + WorkingSetSize: SIZE_T, + QuotaPeakPagedPoolUsage: SIZE_T, + QuotaPagedPoolUsage: SIZE_T, + QuotaPeakNonPagedPoolUsage: SIZE_T, + QuotaNonPagedPoolUsage: SIZE_T, + PagefileUsage: SIZE_T, + PeakPagefileUsage: SIZE_T, + } + type PPROCESS_MEMORY_COUNTERS = *mut PROCESS_MEMORY_COUNTERS; + #[link(name = "psapi")] + extern "system" { + fn GetProcessMemoryInfo(Process: HANDLE, + ppsmemCounters: PPROCESS_MEMORY_COUNTERS, + cb: DWORD) -> BOOL; + } + let mut pmc: PROCESS_MEMORY_COUNTERS = unsafe { mem::zeroed() }; + pmc.cb = mem::size_of_val(&pmc) as DWORD; + match unsafe { GetProcessMemoryInfo(GetCurrentProcess(), &mut pmc, pmc.cb) } { + 0 => None, + _ => Some(pmc.WorkingSetSize as usize), + } +} + +#[cfg_attr(windows, allow(dead_code))] fn get_proc_self_statm_field(field: usize) -> Option<usize> { use std::fs::File; use std::io::Read; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ae6136a049a..9541076df82 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -804,8 +804,8 @@ fn write_out_deps(sess: &Session, match *output_type { config::OutputTypeExe => { for output in sess.crate_types.borrow().iter() { - let p = link::filename_for_input(sess, *output, - id, &file); + let p = link::filename_for_input(sess, *output, id, + outputs); out_filenames.push(p); } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 36438ccc784..7ccada1079f 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -452,10 +452,8 @@ impl RustcDefaultCalls { let metadata = driver::collect_crate_metadata(sess, attrs); *sess.crate_metadata.borrow_mut() = metadata; for &style in &crate_types { - let fname = link::filename_for_input(sess, - style, - &id, - &t_outputs.with_extension("")); + let fname = link::filename_for_input(sess, style, &id, + &t_outputs); println!("{}", fname.file_name().unwrap() .to_string_lossy()); } @@ -481,17 +479,6 @@ pub fn commit_date_str() -> Option<&'static str> { option_env!("CFG_VER_DATE") } -/// Returns a stage string, such as "stage0". -pub fn stage_str() -> Option<&'static str> { - if cfg!(stage0) { - Some("stage0") - } else if cfg!(stage1) { - Some("stage1") - } else { - None - } -} - /// Prints version information pub fn version(binary: &str, matches: &getopts::Matches) { let verbose = matches.opt_present("verbose"); @@ -504,9 +491,6 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(release_str())); - if let Some(stage) = stage_str() { - println!("stage: {}", stage); - } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5d10b0d9a57..0ec3979ccfb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1844,11 +1844,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { visit::walk_ty_param_bounds_helper(this, bounds); for trait_item in trait_items { - // Create a new rib for the trait_item-specific type - // parameters. - // - // FIXME #4951: Do we need a node ID here? - match trait_item.node { ast::ConstTraitItem(_, ref default) => { // Only impose the restrictions of diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index e0495226d90..21bc61593c9 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -417,11 +417,10 @@ pub fn link_binary(sess: &Session, // Remove the temporary object file and metadata if we aren't saving temps if !sess.opts.cg.save_temps { - let obj_filename = outputs.temp_path(OutputTypeObject); - if !sess.opts.output_types.contains(&OutputTypeObject) { - remove(sess, &obj_filename); + for obj in object_filenames(sess, outputs) { + remove(sess, &obj); } - remove(sess, &obj_filename.with_extension("metadata.o")); + remove(sess, &outputs.with_extension("metadata.o")); } out_filenames @@ -465,26 +464,25 @@ fn is_writeable(p: &Path) -> bool { pub fn filename_for_input(sess: &Session, crate_type: config::CrateType, - name: &str, - out_filename: &Path) -> PathBuf { - let libname = format!("{}{}", name, sess.opts.cg.extra_filename); + crate_name: &str, + outputs: &OutputFilenames) -> PathBuf { + let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename); match crate_type { config::CrateTypeRlib => { - out_filename.with_file_name(&format!("lib{}.rlib", libname)) + outputs.out_directory.join(&format!("lib{}.rlib", libname)) } config::CrateTypeDylib => { let (prefix, suffix) = (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); - out_filename.with_file_name(&format!("{}{}{}", - prefix, - libname, - suffix)) + outputs.out_directory.join(&format!("{}{}{}", prefix, libname, + suffix)) } config::CrateTypeStaticlib => { - out_filename.with_file_name(&format!("lib{}.a", libname)) + outputs.out_directory.join(&format!("lib{}.a", libname)) } config::CrateTypeExecutable => { let suffix = &sess.target.target.options.exe_suffix; + let out_filename = outputs.path(OutputTypeExe); if suffix.is_empty() { out_filename.to_path_buf() } else { @@ -499,50 +497,47 @@ fn link_binary_output(sess: &Session, crate_type: config::CrateType, outputs: &OutputFilenames, crate_name: &str) -> PathBuf { - let obj_filename = outputs.temp_path(OutputTypeObject); + let objects = object_filenames(sess, outputs); let out_filename = match outputs.single_output_file { Some(ref file) => file.clone(), - None => { - let out_filename = outputs.path(OutputTypeExe); - filename_for_input(sess, crate_type, crate_name, &out_filename) - } + None => filename_for_input(sess, crate_type, crate_name, outputs), }; - // Make sure the output and obj_filename are both writeable. - // Mac, FreeBSD, and Windows system linkers check this already -- - // however, the Linux linker will happily overwrite a read-only file. - // We should be consistent. - let obj_is_writeable = is_writeable(&obj_filename); - let out_is_writeable = is_writeable(&out_filename); - if !out_is_writeable { - sess.fatal(&format!("output file {} is not writeable -- check its \ - permissions.", - out_filename.display())); - } - else if !obj_is_writeable { - sess.fatal(&format!("object file {} is not writeable -- check its \ - permissions.", - obj_filename.display())); + // Make sure files are writeable. Mac, FreeBSD, and Windows system linkers + // check this already -- however, the Linux linker will happily overwrite a + // read-only file. We should be consistent. + for file in objects.iter().chain(Some(&out_filename)) { + if !is_writeable(file) { + sess.fatal(&format!("output file {} is not writeable -- check its \ + permissions", file.display())); + } } match crate_type { config::CrateTypeRlib => { - link_rlib(sess, Some(trans), &obj_filename, &out_filename).build(); + link_rlib(sess, Some(trans), &objects, &out_filename).build(); } config::CrateTypeStaticlib => { - link_staticlib(sess, &obj_filename, &out_filename); + link_staticlib(sess, &objects, &out_filename); } config::CrateTypeExecutable => { - link_natively(sess, trans, false, &obj_filename, &out_filename); + link_natively(sess, trans, false, &objects, &out_filename, outputs); } config::CrateTypeDylib => { - link_natively(sess, trans, true, &obj_filename, &out_filename); + link_natively(sess, trans, true, &objects, &out_filename, outputs); } } out_filename } +fn object_filenames(sess: &Session, outputs: &OutputFilenames) -> Vec<PathBuf> { + (0..sess.opts.cg.codegen_units).map(|i| { + let ext = format!("{}.o", i); + outputs.temp_path(OutputTypeObject).with_extension(&ext) + }).collect() +} + fn archive_search_paths(sess: &Session) -> Vec<PathBuf> { let mut search = Vec::new(); sess.target_filesearch(PathKind::Native).for_each_lib_search_path(|path, _| { @@ -552,6 +547,19 @@ fn archive_search_paths(sess: &Session) -> Vec<PathBuf> { return search; } +fn archive_config<'a>(sess: &'a Session, + output: &Path) -> ArchiveConfig<'a> { + ArchiveConfig { + handler: &sess.diagnostic().handler, + dst: output.to_path_buf(), + lib_search_paths: archive_search_paths(sess), + slib_prefix: sess.target.target.options.staticlib_prefix.clone(), + slib_suffix: sess.target.target.options.staticlib_suffix.clone(), + ar_prog: get_ar_prog(sess), + command_path: command_path(sess), + } +} + // Create an 'rlib' // // An rlib in its current incarnation is essentially a renamed .a file. The @@ -560,21 +568,13 @@ fn archive_search_paths(sess: &Session) -> Vec<PathBuf> { // native libraries and inserting all of the contents into this archive. fn link_rlib<'a>(sess: &'a Session, trans: Option<&CrateTranslation>, // None == no metadata/bytecode - obj_filename: &Path, + objects: &[PathBuf], out_filename: &Path) -> ArchiveBuilder<'a> { - info!("preparing rlib from {:?} to {:?}", obj_filename, out_filename); - let handler = &sess.diagnostic().handler; - let config = ArchiveConfig { - handler: handler, - dst: out_filename.to_path_buf(), - lib_search_paths: archive_search_paths(sess), - slib_prefix: sess.target.target.options.staticlib_prefix.clone(), - slib_suffix: sess.target.target.options.staticlib_suffix.clone(), - ar_prog: get_ar_prog(sess), - command_path: command_path(sess), - }; - let mut ab = ArchiveBuilder::create(config); - ab.add_file(obj_filename).unwrap(); + info!("preparing rlib from {:?} to {:?}", objects, out_filename); + let mut ab = ArchiveBuilder::create(archive_config(sess, out_filename)); + for obj in objects { + ab.add_file(obj).unwrap(); + } for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() { match kind { @@ -600,7 +600,7 @@ fn link_rlib<'a>(sess: &'a Session, // this is as follows: // // * When performing LTO, this archive will be modified to remove - // obj_filename from above. The reason for this is described below. + // objects from above. The reason for this is described below. // // * When the system linker looks at an archive, it will attempt to // determine the architecture of the archive in order to see whether its @@ -639,15 +639,14 @@ fn link_rlib<'a>(sess: &'a Session, // For LTO purposes, the bytecode of this library is also inserted // into the archive. If codegen_units > 1, we insert each of the // bitcode files. - for i in 0..sess.opts.cg.codegen_units { + for obj in objects { // Note that we make sure that the bytecode filename in the // archive is never exactly 16 bytes long by adding a 16 byte // extension to it. This is to work around a bug in LLDB that // would cause it to crash if the name of a file in an archive // was exactly 16 bytes. - let bc_filename = obj_filename.with_extension(&format!("{}.bc", i)); - let bc_deflated_filename = obj_filename.with_extension( - &format!("{}.bytecode.deflate", i)); + let bc_filename = obj.with_extension("bc"); + let bc_deflated_filename = obj.with_extension("bytecode.deflate"); let mut bc_data = Vec::new(); match fs::File::open(&bc_filename).and_then(|mut f| { @@ -750,8 +749,8 @@ fn write_rlib_bytecode_object_v1(writer: &mut Write, // There's no need to include metadata in a static archive, so ensure to not // link in the metadata object file (and also don't prepare the archive with a // metadata file). -fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) { - let ab = link_rlib(sess, None, obj_filename, out_filename); +fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path) { + let ab = link_rlib(sess, None, objects, out_filename); let mut ab = match sess.target.target.options.is_like_osx { true => ab.build().extend(), false => ab, @@ -806,8 +805,9 @@ fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) { // This will invoke the system linker/cc to create the resulting file. This // links to all upstream files as well. fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, - obj_filename: &Path, out_filename: &Path) { - info!("preparing dylib? ({}) from {:?} to {:?}", dylib, obj_filename, + objects: &[PathBuf], out_filename: &Path, + outputs: &OutputFilenames) { + info!("preparing dylib? ({}) from {:?} to {:?}", dylib, objects, out_filename); let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir"); @@ -828,7 +828,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker> }; link_args(&mut *linker, sess, dylib, tmpdir.path(), - trans, obj_filename, out_filename); + trans, objects, out_filename, outputs); if !sess.target.target.options.no_compiler_rt { linker.link_staticlib("compiler-rt"); } @@ -884,8 +884,9 @@ fn link_args(cmd: &mut Linker, dylib: bool, tmpdir: &Path, trans: &CrateTranslation, - obj_filename: &Path, - out_filename: &Path) { + objects: &[PathBuf], + out_filename: &Path, + outputs: &OutputFilenames) { // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. @@ -895,7 +896,9 @@ fn link_args(cmd: &mut Linker, let t = &sess.target.target; cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); - cmd.add_object(obj_filename); + for obj in objects { + cmd.add_object(obj); + } cmd.output_filename(out_filename); // Stack growth requires statically linking a __morestack function. Note @@ -922,7 +925,7 @@ fn link_args(cmd: &mut Linker, // executable. This metadata is in a separate object file from the main // object file, so we link that in here. if dylib { - cmd.add_object(&obj_filename.with_extension("metadata.o")); + cmd.add_object(&outputs.with_extension("metadata.o")); } // Try to strip as much out of the generated object by removing unused @@ -1127,7 +1130,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0) } cstore::RequireStatic => { - add_static_crate(cmd, sess, tmpdir, &src.rlib.unwrap().0) + add_static_crate(cmd, sess, tmpdir, dylib, &src.rlib.unwrap().0) } } @@ -1143,71 +1146,80 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, } // Adds the static "rlib" versions of all crates to the command line. + // There's a bit of magic which happens here specifically related to LTO and + // dynamic libraries. Specifically: + // + // * For LTO, we remove upstream object files. + // * For dylibs we remove metadata and bytecode from upstream rlibs + // + // When performing LTO, all of the bytecode from the upstream libraries has + // already been included in our object file output. As a result we need to + // remove the object files in the upstream libraries so the linker doesn't + // try to include them twice (or whine about duplicate symbols). We must + // continue to include the rest of the rlib, however, as it may contain + // static native libraries which must be linked in. + // + // When making a dynamic library, linkers by default don't include any + // object files in an archive if they're not necessary to resolve the link. + // We basically want to convert the archive (rlib) to a dylib, though, so we + // *do* want everything included in the output, regardless of whether the + // linker thinks it's needed or not. As a result we must use the + // --whole-archive option (or the platform equivalent). When using this + // option the linker will fail if there are non-objects in the archive (such + // as our own metadata and/or bytecode). All in all, for rlibs to be + // entirely included in dylibs, we need to remove all non-object files. + // + // Note, however, that if we're not doing LTO or we're not producing a dylib + // (aka we're making an executable), we can just pass the rlib blindly to + // the linker (fast) because it's fine if it's not actually included as + // we're at the end of the dependency chain. fn add_static_crate(cmd: &mut Linker, sess: &Session, tmpdir: &Path, - cratepath: &Path) { - // When performing LTO on an executable output, all of the - // bytecode from the upstream libraries has already been - // included in our object file output. We need to modify all of - // the upstream archives to remove their corresponding object - // file to make sure we don't pull the same code in twice. - // - // We must continue to link to the upstream archives to be sure - // to pull in native static dependencies. As the final caveat, - // on Linux it is apparently illegal to link to a blank archive, - // so if an archive no longer has any object files in it after - // we remove `lib.o`, then don't link against it at all. - // - // If we're not doing LTO, then our job is simply to just link - // against the archive. - if sess.lto() { - 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), - (), |()| { - let dst = tmpdir.join(cratepath.file_name().unwrap()); - match fs::copy(&cratepath, &dst) { - Ok(..) => {} - Err(e) => { - sess.fatal(&format!("failed to copy {} to {}: {}", - cratepath.display(), - dst.display(), e)); - } + dylib: bool, cratepath: &Path) { + if !sess.lto() && !dylib { + cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); + return + } + + let dst = tmpdir.join(cratepath.file_name().unwrap()); + 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), (), |()| { + let err = (|| { + io::copy(&mut try!(fs::File::open(&cratepath)), + &mut try!(fs::File::create(&dst))) + })(); + if let Err(e) = err { + sess.fatal(&format!("failed to copy {} to {}: {}", + cratepath.display(), dst.display(), e)); + } + + let mut archive = Archive::open(archive_config(sess, &dst)); + archive.remove_file(METADATA_FILENAME); + + let mut any_objects = false; + for f in archive.files() { + if f.ends_with("bytecode.deflate") { + archive.remove_file(&f); + continue } - // Fix up permissions of the copy, as fs::copy() preserves - // permissions, but the original file may have been installed - // by a package manager and may be read-only. - match fs::metadata(&dst).and_then(|m| { - let mut perms = m.permissions(); - perms.set_readonly(false); - fs::set_permissions(&dst, perms) - }) { - Ok(..) => {} - Err(e) => { - sess.fatal(&format!("failed to chmod {} when preparing \ - for LTO: {}", dst.display(), e)); + let canonical = f.replace("-", "_"); + let canonical_name = name.replace("-", "_"); + if sess.lto() && canonical.starts_with(&canonical_name) && + canonical.ends_with(".o") { + let num = &f[name.len()..f.len() - 2]; + if num.len() > 0 && num[1..].parse::<u32>().is_ok() { + archive.remove_file(&f); + continue } } - let handler = &sess.diagnostic().handler; - let config = ArchiveConfig { - handler: handler, - dst: dst.clone(), - lib_search_paths: archive_search_paths(sess), - slib_prefix: sess.target.target.options.staticlib_prefix.clone(), - slib_suffix: sess.target.target.options.staticlib_suffix.clone(), - ar_prog: get_ar_prog(sess), - command_path: command_path(sess), - }; - let mut archive = Archive::open(config); - archive.remove_file(&format!("{}.o", name)); - let files = archive.files(); - if files.iter().any(|s| s.ends_with(".o")) { - cmd.link_rlib(&dst); - } - }); - } else { - cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); - } + any_objects = true; + } + + if any_objects { + cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); + } + }); } // Same thing as above, but for dynamic crates instead of static crates. diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 7253334d699..518a6c24840 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -30,6 +30,7 @@ pub trait Linker { fn link_framework(&mut self, framework: &str); fn link_staticlib(&mut self, lib: &str); fn link_rlib(&mut self, lib: &Path); + fn link_whole_rlib(&mut self, lib: &Path); fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]); fn include_path(&mut self, path: &Path); fn framework_path(&mut self, path: &Path); @@ -96,6 +97,17 @@ impl<'a> Linker for GnuLinker<'a> { } } + fn link_whole_rlib(&mut self, lib: &Path) { + if self.sess.target.target.options.is_like_osx { + let mut v = OsString::from("-Wl,-force_load,"); + v.push(lib); + self.cmd.arg(&v); + } else { + self.cmd.arg("-Wl,--whole-archive").arg(lib) + .arg("-Wl,--no-whole-archive"); + } + } + fn gc_sections(&mut self, is_dylib: bool) { // The dead_strip option to the linker specifies that functions and data // unreachable by the entry point will be removed. This is quite useful @@ -250,6 +262,10 @@ impl<'a> Linker for MsvcLinker<'a> { // not supported? self.link_staticlib(lib); } + fn link_whole_rlib(&mut self, path: &Path) { + // not supported? + self.link_rlib(path); + } fn optimize(&mut self) { // Needs more investigation of `/OPT` arguments } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index e13a5e97f75..dfeb866c5b3 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -56,33 +56,14 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, }; let archive = ArchiveRO::open(&path).expect("wanted an rlib"); - let file = path.file_name().unwrap().to_str().unwrap(); - let file = &file[3..file.len() - 5]; // chop off lib/.rlib - debug!("reading {}", file); - for i in 0.. { - let filename = format!("{}.{}.bytecode.deflate", file, i); - let msg = format!("check for {}", filename); - let bc_encoded = time(sess.time_passes(), &msg, (), |_| { - archive.iter().find(|section| { - section.name() == Some(&filename[..]) - }) - }); - let bc_encoded = match bc_encoded { - Some(data) => data, - None => { - if i == 0 { - // No bitcode was found at all. - sess.fatal(&format!("missing compressed bytecode in {}", - path.display())); - } - // No more bitcode files to read. - break - } - }; - let bc_encoded = bc_encoded.data(); + let bytecodes = archive.iter().filter_map(|child| { + child.name().map(|name| (name, child)) + }).filter(|&(name, _)| name.ends_with("bytecode.deflate")); + for (name, data) in bytecodes { + let bc_encoded = data.data(); let bc_decoded = if is_versioned_bytecode_format(bc_encoded) { - time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| { + time(sess.time_passes(), &format!("decode {}", name), (), |_| { // Read the version let version = extract_bytecode_format_version(bc_encoded); @@ -106,7 +87,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } }) } else { - time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| { + time(sess.time_passes(), &format!("decode {}", name), (), |_| { // the object must be in the old, pre-versioning format, so simply // inflate everything and let LLVM decide if it can make sense of it match flate::inflate_bytes(bc_encoded) { @@ -120,10 +101,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, }; let ptr = bc_decoded.as_ptr(); - debug!("linking {}, part {}", name, i); - time(sess.time_passes(), - &format!("ll link {}.{}", name, i), - (), + debug!("linking {}", name); + time(sess.time_passes(), &format!("ll link {}", name), (), |()| unsafe { if !llvm::LLVMRustLinkInExternalBitcode(llmod, ptr as *const libc::c_char, diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 90ddba4e09c..0a9db8a651e 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -27,7 +27,6 @@ use std::ffi::{CStr, CString}; use std::fs; use std::mem; use std::path::Path; -use std::process::Stdio; use std::ptr; use std::str; use std::sync::{Arc, Mutex}; @@ -619,6 +618,8 @@ pub fn run_passes(sess: &Session, let needs_crate_bitcode = sess.crate_types.borrow().contains(&config::CrateTypeRlib) && sess.opts.output_types.contains(&config::OutputTypeExe); + let needs_crate_object = + sess.opts.output_types.contains(&config::OutputTypeExe); if needs_crate_bitcode { modules_config.emit_bc = true; } @@ -696,7 +697,8 @@ pub fn run_passes(sess: &Session, if sess.opts.cg.codegen_units == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - copy_gracefully(&crate_output.with_extension(ext), &crate_output.path(output_type)); + copy_gracefully(&crate_output.with_extension(ext), + &crate_output.path(output_type)); if !sess.opts.cg.save_temps && !keep_numbered { // The user just wants `foo.x`, not `foo.0.x`. remove(sess, &crate_output.with_extension(ext)); @@ -715,76 +717,11 @@ pub fn run_passes(sess: &Session, } }; - let link_obj = |output_path: &Path| { - // Running `ld -r` on a single input is kind of pointless. - if sess.opts.cg.codegen_units == 1 { - copy_gracefully(&crate_output.with_extension("0.o"), output_path); - // Leave the .0.o file around, to mimic the behavior of the normal - // code path. - return; - } - - // Some builds of MinGW GCC will pass --force-exe-suffix to ld, which - // will automatically add a .exe extension if the extension is not - // already .exe or .dll. To ensure consistent behavior on Windows, we - // add the .exe suffix explicitly and then rename the output file to - // the desired path. This will give the correct behavior whether or - // not GCC adds --force-exe-suffix. - let windows_output_path = - if sess.target.target.options.is_like_windows { - Some(output_path.with_extension("o.exe")) - } else { - None - }; - - let (pname, mut cmd) = get_linker(sess); - - cmd.args(&sess.target.target.options.pre_link_args); - cmd.arg("-nostdlib"); - - for index in 0..trans.modules.len() { - cmd.arg(&crate_output.with_extension(&format!("{}.o", index))); - } - - cmd.arg("-r").arg("-o") - .arg(windows_output_path.as_ref().map(|s| &**s).unwrap_or(output_path)); - - cmd.args(&sess.target.target.options.post_link_args); - - if sess.opts.debugging_opts.print_link_args { - println!("{:?}", &cmd); - } - - cmd.stdin(Stdio::null()); - match cmd.status() { - Ok(status) => { - if !status.success() { - sess.err(&format!("linking of {} with `{:?}` failed", - output_path.display(), cmd)); - sess.abort_if_errors(); - } - }, - Err(e) => { - sess.err(&format!("could not exec the linker `{}`: {}", - pname, e)); - sess.abort_if_errors(); - }, - } - - match windows_output_path { - Some(ref windows_path) => { - fs::rename(windows_path, output_path).unwrap(); - }, - None => { - // The file is already named according to `output_path`. - } - } - }; - // Flag to indicate whether the user explicitly requested bitcode. // Otherwise, we produced it only as a temporary output, and will need // to get rid of it. let mut user_wants_bitcode = false; + let mut user_wants_objects = false; for output_type in output_types { match *output_type { config::OutputTypeBitcode => { @@ -801,17 +738,10 @@ pub fn run_passes(sess: &Session, copy_if_one_unit("0.s", config::OutputTypeAssembly, false); } config::OutputTypeObject => { - link_obj(&crate_output.path(config::OutputTypeObject)); - } - config::OutputTypeExe => { - // If config::OutputTypeObject is already in the list, then - // `crate.o` will be handled by the config::OutputTypeObject case. - // Otherwise, we need to create the temporary object so we - // can run the linker. - if !sess.opts.output_types.contains(&config::OutputTypeObject) { - link_obj(&crate_output.temp_path(config::OutputTypeObject)); - } + user_wants_objects = true; + copy_if_one_unit("0.o", config::OutputTypeObject, true); } + config::OutputTypeExe | config::OutputTypeDepInfo => {} } } @@ -848,15 +778,18 @@ pub fn run_passes(sess: &Session, let keep_numbered_bitcode = needs_crate_bitcode || (user_wants_bitcode && sess.opts.cg.codegen_units > 1); + let keep_numbered_objects = needs_crate_object || + (user_wants_objects && sess.opts.cg.codegen_units > 1); + for i in 0..trans.modules.len() { - if modules_config.emit_obj { + if modules_config.emit_obj && !keep_numbered_objects { let ext = format!("{}.o", i); - remove(sess, &crate_output.with_extension(&ext[..])); + remove(sess, &crate_output.with_extension(&ext)); } if modules_config.emit_bc && !keep_numbered_bitcode { let ext = format!("{}.bc", i); - remove(sess, &crate_output.with_extension(&ext[..])); + remove(sess, &crate_output.with_extension(&ext)); } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e2f35983eb4..5027be5fb62 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1550,6 +1550,31 @@ impl Foo for Bar { ``` "##, +E0191: r##" +Trait objects need to have all associated types specified. Erroneous code +example: + +``` +trait Trait { + type Bar; +} + +type Foo = Trait; // error: the value of the associated type `Bar` (from + // the trait `Trait`) must be specified +``` + +Please verify you specified all associated types of the trait and that you +used the right trait. Example: + +``` +trait Trait { + type Bar; +} + +type Foo = Trait<Bar=i32>; // ok! +``` +"##, + E0192: r##" Negative impls are only allowed for traits with default impls. For more information see the [opt-in builtin traits RFC](https://github.com/rust-lang/ @@ -1831,6 +1856,47 @@ extern "rust-intrinsic" { ``` "##, +E0220: r##" +You used an associated type which isn't defined in the trait. +Erroneous code example: + +``` +trait Trait { + type Bar; +} + +type Foo = Trait<F=i32>; // error: associated type `F` not found for + // `Trait` +``` + +Please verify you used the right trait or you didn't misspell the +associated type name. Example: + +``` +trait Trait { + type Bar; +} + +type Foo = Trait<Bar=i32>; // ok! +``` +"##, + +E0232: r##" +The attribute must have a value. Erroneous code example: + +``` +#[rustc_on_unimplemented] // error: this attribute must have a value +trait Bar {} +``` + +Please supply the missing value of the attribute. Example: + +``` +#[rustc_on_unimplemented = "foo"] // ok! +trait Bar {} +``` +"##, + E0243: r##" This error indicates that not enough type parameters were found in a type or trait. @@ -2074,7 +2140,6 @@ register_diagnostics! { E0188, // can not cast a immutable reference to a mutable pointer E0189, // deprecated: can only cast a boxed pointer to a boxed object E0190, // deprecated: can only cast a &-pointer to an &-object - E0191, // value of the associated type must be specified E0193, // cannot bound type where clause bounds may only be attached to types // involving type parameters E0194, @@ -2092,7 +2157,6 @@ register_diagnostics! { E0217, // ambiguous associated type, defined in multiple supertraits E0218, // no associated type defined E0219, // associated type defined in higher-ranked supertrait - E0220, // associated type not found for type parameter E0221, // ambiguous associated type in bounds //E0222, // Error code E0045 (variadic function must have C calling // convention) duplicate @@ -2105,7 +2169,6 @@ register_diagnostics! { E0229, // associated type bindings are not allowed here E0230, // there is no type parameter on trait E0231, // only named substitution parameters are allowed - E0232, // this attribute must have a value E0233, E0234, E0235, // structure constructor specifies a structure of type but diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 1d0152e2751..98d8bc6bdaf 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -19,9 +19,8 @@ use error; use fmt; use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; use ptr; -use iter; -/// Wraps a `Read` and buffers input from it +/// Wraps a `Read` and buffers input from it. /// /// It can be excessively inefficient to work directly with a `Read` instance. /// For example, every call to `read` on `TcpStream` results in a system call. @@ -54,20 +53,18 @@ pub struct BufReader<R> { } impl<R: Read> BufReader<R> { - /// Creates a new `BufReader` with a default buffer capacity + /// Creates a new `BufReader` with a default buffer capacity. #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: R) -> BufReader<R> { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufReader` with the specified buffer capacity + /// Creates a new `BufReader` with the specified buffer capacity. #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> { - let mut buf = Vec::with_capacity(cap); - buf.extend(iter::repeat(0).take(cap)); BufReader { inner: inner, - buf: buf, + buf: vec![0; cap], pos: 0, cap: 0, } @@ -183,7 +180,7 @@ impl<R: Seek> Seek for BufReader<R> { } } -/// Wraps a Writer and buffers output to it +/// Wraps a Writer and buffers output to it. /// /// It can be excessively inefficient to work directly with a `Write`. For /// example, every call to `write` on `TcpStream` results in a system call. A @@ -205,13 +202,13 @@ pub struct BufWriter<W: Write> { pub struct IntoInnerError<W>(W, Error); impl<W: Write> BufWriter<W> { - /// Creates a new `BufWriter` with a default buffer capacity + /// Creates a new `BufWriter` with a default buffer capacity. #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> BufWriter<W> { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufWriter` with the specified buffer capacity + /// Creates a new `BufWriter` with the specified buffer capacity. #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> { BufWriter { @@ -253,11 +250,11 @@ impl<W: Write> BufWriter<W> { #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } - /// Gets a mutable reference to the underlying write. + /// Gets a mutable reference to the underlying writer. /// /// # Warning /// - /// It is inadvisable to directly read from the underlying writer. + /// It is inadvisable to directly write to the underlying writer. #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 9021f32fad0..50c44299dc7 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -16,7 +16,7 @@ use cmp; use rustc_unicode::str as core_str; use error as std_error; use fmt; -use iter::{self, Iterator, Extend}; +use iter::{Iterator}; use marker::Sized; use ops::{Drop, FnOnce}; use option::Option::{self, Some, None}; @@ -106,7 +106,7 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> if new_write_size < DEFAULT_BUF_SIZE { new_write_size *= 2; } - buf.extend(iter::repeat(0).take(new_write_size)); + buf.resize(len + new_write_size, 0); } match r.read(&mut buf[len..]) { @@ -984,6 +984,14 @@ mod tests { let mut v = Vec::new(); assert_eq!(c.read_to_end(&mut v).unwrap(), 1); assert_eq!(v, b"1"); + + let cap = 1024 * 1024; + let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>(); + let mut v = Vec::new(); + let (a, b) = data.split_at(data.len() / 2); + assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); + assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); + assert_eq!(v, data); } #[test] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 73e45619774..caf3f497e10 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -146,6 +146,7 @@ #![feature(unique)] #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(vec_push_all)] +#![feature(vec_resize)] #![feature(wrapping)] #![feature(zero_one)] #![cfg_attr(windows, feature(str_utf16))] diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 710928a00c1..649052d123c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -90,6 +90,11 @@ pub trait Visitor<'v> : Sized { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) } + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, + generics: &'v Generics) { + walk_enum_def(self, enum_definition, generics) + } + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) } /// Visits an optional reference to a lifetime. The `span` is the span of some surrounding @@ -268,7 +273,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); - walk_enum_def(visitor, enum_definition, type_parameters) + visitor.visit_enum_def(enum_definition, type_parameters) } ItemDefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) diff --git a/src/test/auxiliary/issue-14344-1.rs b/src/test/auxiliary/issue-14344-1.rs new file mode 100644 index 00000000000..78c03bac33f --- /dev/null +++ b/src/test/auxiliary/issue-14344-1.rs @@ -0,0 +1,15 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "rlib"] + +pub fn foo() {} diff --git a/src/test/auxiliary/issue-14344-2.rs b/src/test/auxiliary/issue-14344-2.rs new file mode 100644 index 00000000000..9df35e50adb --- /dev/null +++ b/src/test/auxiliary/issue-14344-2.rs @@ -0,0 +1,13 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate issue_14344_1; + +pub fn bar() {} diff --git a/src/test/auxiliary/issue-25185-1.rs b/src/test/auxiliary/issue-25185-1.rs new file mode 100644 index 00000000000..b9da39cbbcb --- /dev/null +++ b/src/test/auxiliary/issue-25185-1.rs @@ -0,0 +1,18 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "rlib"] + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + pub fn rust_dbg_extern_identity_u32(u: u32) -> u32; +} diff --git a/src/test/auxiliary/issue-25185-2.rs b/src/test/auxiliary/issue-25185-2.rs new file mode 100644 index 00000000000..00b5277d6c0 --- /dev/null +++ b/src/test/auxiliary/issue-25185-2.rs @@ -0,0 +1,13 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate issue_25185_1; + +pub use issue_25185_1::rust_dbg_extern_identity_u32; diff --git a/src/test/compile-fail/issue-23302.rs b/src/test/compile-fail/issue-23302.rs new file mode 100644 index 00000000000..7ac8cf45edb --- /dev/null +++ b/src/test/compile-fail/issue-23302.rs @@ -0,0 +1,24 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that an enum with recursion in the discriminant throws +// the appropriate error (rather than, say, blowing the stack). +enum X { + A = X::A as isize, //~ ERROR E0265 +} + +// Since `Y::B` here defaults to `Y::A+1`, this is also a +// recursive definition. +enum Y { + A = Y::B as isize, //~ ERROR E0265 + B, +} + +fn main() { } diff --git a/src/test/run-make/execution-engine/Makefile b/src/test/run-make/execution-engine/Makefile index 387905f45d8..ef646c5bf5d 100644 --- a/src/test/run-make/execution-engine/Makefile +++ b/src/test/run-make/execution-engine/Makefile @@ -1,8 +1,14 @@ -include ../tools.mk +# FIXME: ignore freebsd # This is a basic test of LLVM ExecutionEngine functionality using compiled # Rust code built using the `rustc` crate. +ifneq ($(shell uname),FreeBSD) all: $(RUSTC) test.rs $(call RUN,test $(RUSTC)) +else +all: + +endif diff --git a/src/test/run-make/extern-fn-reachable/Makefile b/src/test/run-make/extern-fn-reachable/Makefile index 56748b1eb9b..79a9a3c640f 100644 --- a/src/test/run-make/extern-fn-reachable/Makefile +++ b/src/test/run-make/extern-fn-reachable/Makefile @@ -4,6 +4,6 @@ TARGET_RPATH_DIR:=$(TARGET_RPATH_DIR):$(TMPDIR) all: - $(RUSTC) dylib.rs -o $(TMPDIR)/libdylib.so - $(RUSTC) main.rs + $(RUSTC) dylib.rs -o $(TMPDIR)/libdylib.so -C prefer-dynamic + $(RUSTC) main.rs -C prefer-dynamic $(call RUN,main) diff --git a/src/test/run-make/extra-filename-with-temp-outputs/Makefile b/src/test/run-make/extra-filename-with-temp-outputs/Makefile index 28c22a173cc..d33c18a6f3c 100644 --- a/src/test/run-make/extra-filename-with-temp-outputs/Makefile +++ b/src/test/run-make/extra-filename-with-temp-outputs/Makefile @@ -2,5 +2,5 @@ all: $(RUSTC) -C extra-filename=bar foo.rs -C save-temps - rm $(TMPDIR)/foobar.o + rm $(TMPDIR)/foobar.0.o rm $(TMPDIR)/$(call BIN,foobar) diff --git a/src/test/run-pass/issue-14344.rs b/src/test/run-pass/issue-14344.rs new file mode 100644 index 00000000000..06b8f44ed26 --- /dev/null +++ b/src/test/run-pass/issue-14344.rs @@ -0,0 +1,20 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-14344-1.rs +// aux-build:issue-14344-2.rs + +extern crate issue_14344_1; +extern crate issue_14344_2; + +fn main() { + issue_14344_1::foo(); + issue_14344_2::bar(); +} diff --git a/src/test/run-pass/issue-25185.rs b/src/test/run-pass/issue-25185.rs new file mode 100644 index 00000000000..d8d2d5078c5 --- /dev/null +++ b/src/test/run-pass/issue-25185.rs @@ -0,0 +1,21 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-25185-1.rs +// aux-build:issue-25185-2.rs + +extern crate issue_25185_2; + +fn main() { + let x = unsafe { + issue_25185_2::rust_dbg_extern_identity_u32(1) + }; + assert_eq!(x, 1); +} |
