diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b8fea40090fab..919d8329941a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -112,14 +112,17 @@ There are large number of options provided in this config file that will alter t configuration used in the build process. Some options to note: #### `[llvm]`: +- `assertions = true` = This enables LLVM assertions, which makes LLVM misuse cause an assertion failure instead of weird misbehavior. This also slows down the compiler's runtime by ~20%. - `ccache = true` - Use ccache when building llvm #### `[build]`: - `compiler-docs = true` - Build compiler documentation #### `[rust]`: -- `debuginfo = true` - Build a compiler with debuginfo -- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust +- `debuginfo = true` - Build a compiler with debuginfo. Makes building rustc slower, but then you can use a debugger to debug `rustc`. +- `debuginfo-lines = true` - An alternative to `debuginfo = true` that doesn't let you use a debugger, but doesn't make building rustc slower and still gives you line numbers in backtraces. +- `debug-assertions = true` - Makes the log output of `debug!` work. +- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust, but makes the stage1 compiler x100 slower. For more options, the `config.toml` file contains commented out defaults, with descriptions of what each option will do. @@ -273,6 +276,27 @@ build, you'll need to build rustdoc specially, since it's not normally built in stage 1. `python x.py build --stage 1 src/libstd src/tools/rustdoc` will build rustdoc and libstd, which will allow rustdoc to be run with that toolchain.) +### Out-of-tree builds +[out-of-tree-builds]: #out-of-tree-builds + +Rust's `x.py` script fully supports out-of-tree builds - it looks for +the Rust source code from the directory `x.py` was found in, but it +reads the `config.toml` configuration file from the directory it's +run in, and places all build artifacts within a subdirectory named `build`. + +This means that if you want to do an out-of-tree build, you can just do it: +``` +$ cd my/build/dir +$ cp ~/my-config.toml config.toml # Or fill in config.toml otherwise +$ path/to/rust/x.py build +... +$ # This will use the Rust source code in `path/to/rust`, but build +$ # artifacts will now be in ./build +``` + +It's absolutely fine to have multiple build directories with different +`config.toml` configurations using the same code. + ## Pull Requests [pull-requests]: #pull-requests @@ -446,14 +470,14 @@ failed to run: ~/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo build --ma If you haven't used the `[patch]` section of `Cargo.toml` before, there is [some relevant documentation about it in the cargo docs](http://doc.crates.io/manifest.html#the-patch-section). In -addition to that, you should read the +addition to that, you should read the [Overriding dependencies](http://doc.crates.io/specifying-dependencies.html#overriding-dependencies) section of the documentation as well. Specifically, the following [section in Overriding dependencies](http://doc.crates.io/specifying-dependencies.html#testing-a-bugfix) reveals what the problem is: > Next up we need to ensure that our lock file is updated to use this new version of uuid so our project uses the locally checked out copy instead of one from crates.io. The way [patch] works is that it'll load the dependency at ../path/to/uuid and then whenever crates.io is queried for versions of uuid it'll also return the local version. -> +> > This means that the version number of the local checkout is significant and will affect whether the patch is used. Our manifest declared uuid = "1.0" which means we'll only resolve to >= 1.0.0, < 2.0.0, and Cargo's greedy resolution algorithm also means that we'll resolve to the maximum version within that range. Typically this doesn't matter as the version of the git repository will already be greater or match the maximum version published on crates.io, but it's important to keep this in mind! This says that when we updated the submodule, the version number in our diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 67ccb5cab6def..93d7e66b7b203 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -224,8 +224,10 @@ use Bound::{Excluded, Included, Unbounded}; /// types inside a `Vec`, it will not allocate space for them. *Note that in this case /// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only /// if [`mem::size_of::`]`() * capacity() > 0`. In general, `Vec`'s allocation -/// details are subtle enough that it is strongly recommended that you only -/// free memory allocated by a `Vec` by creating a new `Vec` and dropping it. +/// details are very subtle — if you intend to allocate memory using a `Vec` +/// and use it for something else (either to pass to unsafe code, or to build your +/// own memory-backed collection), be sure to deallocate this memory by using +/// `from_raw_parts` to recover the `Vec` and then dropping it. /// /// If a `Vec` *has* allocated memory, then the memory it points to is on the heap /// (as defined by the allocator Rust is configured to use by default), and its diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index 18feaccbfd0df..000d06a57a622 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit 18feaccbfd0dfbd5ab5d0a2a6eac9c04be667266 +Subproject commit 000d06a57a622eb4db4a15d0f76db48571f4d8e4 diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index b5553fb29475b..732a02e8c427d 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -114,7 +114,7 @@ macro_rules! define_bignum { /// copying it recklessly may result in the performance hit. /// Thus this is intentionally not `Copy`. /// - /// All operations available to bignums panic in the case of over/underflows. + /// All operations available to bignums panic in the case of overflows. /// The caller is responsible to use large enough bignum types. pub struct $name { /// One plus the offset to the maximum "digit" in use. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 245ca83f28f65..851c0a0dd6f75 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -98,10 +98,7 @@ pub mod diy_float; // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { - ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, - $add_with_overflow:path, - $sub_with_overflow:path, - $mul_with_overflow:path) => { + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr) => { /// Returns the smallest value that can be represented by this integer type. /// /// # Examples @@ -402,7 +399,7 @@ macro_rules! int_impl { } /// Checked integer subtraction. Computes `self - rhs`, returning - /// `None` if underflow occurred. + /// `None` if overflow occurred. /// /// # Examples /// @@ -420,7 +417,7 @@ macro_rules! int_impl { } /// Checked integer multiplication. Computes `self * rhs`, returning - /// `None` if underflow or overflow occurred. + /// `None` if overflow occurred. /// /// # Examples /// @@ -438,7 +435,7 @@ macro_rules! int_impl { } /// Checked integer division. Computes `self / rhs`, returning `None` - /// if `rhs == 0` or the operation results in underflow or overflow. + /// if `rhs == 0` or the operation results in overflow. /// /// # Examples /// @@ -460,7 +457,7 @@ macro_rules! int_impl { } /// Checked integer remainder. Computes `self % rhs`, returning `None` - /// if `rhs == 0` or the operation results in underflow or overflow. + /// if `rhs == 0` or the operation results in overflow. /// /// # Examples /// @@ -865,11 +862,11 @@ macro_rules! int_impl { #[inline] #[stable(feature = "wrapping", since = "1.7.0")] pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { - unsafe { - let (a, b) = $add_with_overflow(self as $ActualT, - rhs as $ActualT); - (a as Self, b) - } + let (a, b) = unsafe { + intrinsics::add_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } /// Calculates `self` - `rhs` @@ -891,11 +888,11 @@ macro_rules! int_impl { #[inline] #[stable(feature = "wrapping", since = "1.7.0")] pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - unsafe { - let (a, b) = $sub_with_overflow(self as $ActualT, - rhs as $ActualT); - (a as Self, b) - } + let (a, b) = unsafe { + intrinsics::sub_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } /// Calculates the multiplication of `self` and `rhs`. @@ -915,11 +912,11 @@ macro_rules! int_impl { #[inline] #[stable(feature = "wrapping", since = "1.7.0")] pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - unsafe { - let (a, b) = $mul_with_overflow(self as $ActualT, - rhs as $ActualT); - (a as Self, b) - } + let (a, b) = unsafe { + intrinsics::mul_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } /// Calculates the divisor when `self` is divided by `rhs`. @@ -1207,82 +1204,50 @@ macro_rules! int_impl { #[lang = "i8"] impl i8 { - int_impl! { i8, i8, u8, 8, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + int_impl! { i8, i8, u8, 8 } } #[lang = "i16"] impl i16 { - int_impl! { i16, i16, u16, 16, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + int_impl! { i16, i16, u16, 16 } } #[lang = "i32"] impl i32 { - int_impl! { i32, i32, u32, 32, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + int_impl! { i32, i32, u32, 32 } } #[lang = "i64"] impl i64 { - int_impl! { i64, i64, u64, 64, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + int_impl! { i64, i64, u64, 64 } } #[lang = "i128"] impl i128 { - int_impl! { i128, i128, u128, 128, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + int_impl! { i128, i128, u128, 128 } } #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { - int_impl! { isize, i16, u16, 16, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + int_impl! { isize, i16, u16, 16 } } #[cfg(target_pointer_width = "32")] #[lang = "isize"] impl isize { - int_impl! { isize, i32, u32, 32, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + int_impl! { isize, i32, u32, 32 } } #[cfg(target_pointer_width = "64")] #[lang = "isize"] impl isize { - int_impl! { isize, i64, u64, 64, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + int_impl! { isize, i64, u64, 64 } } // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ty, $BITS:expr, - $ctpop:path, - $ctlz:path, - $ctlz_nonzero:path, - $cttz:path, - $bswap:path, - $add_with_overflow:path, - $sub_with_overflow:path, - $mul_with_overflow:path) => { + ($SelfT:ty, $ActualT:ty, $BITS:expr) => { /// Returns the smallest value that can be represented by this integer type. /// /// # Examples @@ -1346,7 +1311,7 @@ macro_rules! uint_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn count_ones(self) -> u32 { - unsafe { $ctpop(self as $ActualT) as u32 } + unsafe { intrinsics::ctpop(self as $ActualT) as u32 } } /// Returns the number of zeros in the binary representation of `self`. @@ -1381,7 +1346,7 @@ macro_rules! uint_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn leading_zeros(self) -> u32 { - unsafe { $ctlz(self as $ActualT) as u32 } + unsafe { intrinsics::ctlz(self as $ActualT) as u32 } } /// Returns the number of trailing zeros in the binary representation @@ -1480,7 +1445,7 @@ macro_rules! uint_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn swap_bytes(self) -> Self { - unsafe { $bswap(self as $ActualT) as Self } + unsafe { intrinsics::bswap(self as $ActualT) as Self } } /// Converts an integer from big endian to the target's endianness. @@ -1598,7 +1563,7 @@ macro_rules! uint_impl { } /// Checked integer subtraction. Computes `self - rhs`, returning - /// `None` if underflow occurred. + /// `None` if overflow occurred. /// /// # Examples /// @@ -1616,7 +1581,7 @@ macro_rules! uint_impl { } /// Checked integer multiplication. Computes `self * rhs`, returning - /// `None` if underflow or overflow occurred. + /// `None` if overflow occurred. /// /// # Examples /// @@ -1634,7 +1599,7 @@ macro_rules! uint_impl { } /// Checked integer division. Computes `self / rhs`, returning `None` - /// if `rhs == 0` or the operation results in underflow or overflow. + /// if `rhs == 0` or the operation results in overflow. /// /// # Examples /// @@ -1654,7 +1619,7 @@ macro_rules! uint_impl { } /// Checked integer remainder. Computes `self % rhs`, returning `None` - /// if `rhs == 0` or the operation results in underflow or overflow. + /// if `rhs == 0` or the operation results in overflow. /// /// # Examples /// @@ -1984,11 +1949,11 @@ macro_rules! uint_impl { #[inline] #[stable(feature = "wrapping", since = "1.7.0")] pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { - unsafe { - let (a, b) = $add_with_overflow(self as $ActualT, - rhs as $ActualT); - (a as Self, b) - } + let (a, b) = unsafe { + intrinsics::add_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } /// Calculates `self` - `rhs` @@ -2010,11 +1975,11 @@ macro_rules! uint_impl { #[inline] #[stable(feature = "wrapping", since = "1.7.0")] pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - unsafe { - let (a, b) = $sub_with_overflow(self as $ActualT, - rhs as $ActualT); - (a as Self, b) - } + let (a, b) = unsafe { + intrinsics::sub_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } /// Calculates the multiplication of `self` and `rhs`. @@ -2034,11 +1999,11 @@ macro_rules! uint_impl { #[inline] #[stable(feature = "wrapping", since = "1.7.0")] pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - unsafe { - let (a, b) = $mul_with_overflow(self as $ActualT, - rhs as $ActualT); - (a as Self, b) - } + let (a, b) = unsafe { + intrinsics::mul_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } /// Calculates the divisor when `self` is divided by `rhs`. @@ -2223,7 +2188,7 @@ macro_rules! uint_impl { // (such as intel pre-haswell) have more efficient ctlz // intrinsics when the argument is non-zero. let p = self - 1; - let z = unsafe { $ctlz_nonzero(p) }; + let z = unsafe { intrinsics::ctlz_nonzero(p) }; <$SelfT>::max_value() >> z } @@ -2270,15 +2235,7 @@ macro_rules! uint_impl { #[lang = "u8"] impl u8 { - uint_impl! { u8, u8, 8, - intrinsics::ctpop, - intrinsics::ctlz, - intrinsics::ctlz_nonzero, - intrinsics::cttz, - intrinsics::bswap, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + uint_impl! { u8, u8, 8 } /// Checks if the value is within the ASCII range. @@ -2824,95 +2781,39 @@ impl u8 { #[lang = "u16"] impl u16 { - uint_impl! { u16, u16, 16, - intrinsics::ctpop, - intrinsics::ctlz, - intrinsics::ctlz_nonzero, - intrinsics::cttz, - intrinsics::bswap, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + uint_impl! { u16, u16, 16 } } #[lang = "u32"] impl u32 { - uint_impl! { u32, u32, 32, - intrinsics::ctpop, - intrinsics::ctlz, - intrinsics::ctlz_nonzero, - intrinsics::cttz, - intrinsics::bswap, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + uint_impl! { u32, u32, 32 } } #[lang = "u64"] impl u64 { - uint_impl! { u64, u64, 64, - intrinsics::ctpop, - intrinsics::ctlz, - intrinsics::ctlz_nonzero, - intrinsics::cttz, - intrinsics::bswap, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + uint_impl! { u64, u64, 64 } } #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, - intrinsics::ctpop, - intrinsics::ctlz, - intrinsics::ctlz_nonzero, - intrinsics::cttz, - intrinsics::bswap, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + uint_impl! { u128, u128, 128 } } #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { - uint_impl! { usize, u16, 16, - intrinsics::ctpop, - intrinsics::ctlz, - intrinsics::ctlz_nonzero, - intrinsics::cttz, - intrinsics::bswap, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + uint_impl! { usize, u16, 16 } } #[cfg(target_pointer_width = "32")] #[lang = "usize"] impl usize { - uint_impl! { usize, u32, 32, - intrinsics::ctpop, - intrinsics::ctlz, - intrinsics::ctlz_nonzero, - intrinsics::cttz, - intrinsics::bswap, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + uint_impl! { usize, u32, 32 } } #[cfg(target_pointer_width = "64")] #[lang = "usize"] impl usize { - uint_impl! { usize, u64, 64, - intrinsics::ctpop, - intrinsics::ctlz, - intrinsics::ctlz_nonzero, - intrinsics::cttz, - intrinsics::bswap, - intrinsics::add_with_overflow, - intrinsics::sub_with_overflow, - intrinsics::mul_with_overflow } + uint_impl! { usize, u64, 64 } } /// A classification of floating point numbers. diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 39cf2ec4c21d0..85bdeae442bf7 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -581,8 +581,7 @@ impl *const T { /// * Both the starting and resulting pointer must be either in bounds or one /// byte past the end of an allocated object. /// - /// * The computed offset, **in bytes**, cannot overflow or underflow an - /// `isize`. + /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// /// * The offset being in bounds cannot rely on "wrapping around" the address /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. @@ -714,8 +713,7 @@ impl *const T { /// * Both the starting and resulting pointer must be either in bounds or one /// byte past the end of an allocated object. /// - /// * The computed offset, **in bytes**, cannot overflow or underflow an - /// `isize`. + /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// /// * The offset being in bounds cannot rely on "wrapping around" the address /// space. That is, the infinite-precision sum must fit in a `usize`. @@ -1219,8 +1217,7 @@ impl *mut T { /// * Both the starting and resulting pointer must be either in bounds or one /// byte past the end of an allocated object. /// - /// * The computed offset, **in bytes**, cannot overflow or underflow an - /// `isize`. + /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// /// * The offset being in bounds cannot rely on "wrapping around" the address /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. @@ -1419,8 +1416,7 @@ impl *mut T { /// * Both the starting and resulting pointer must be either in bounds or one /// byte past the end of an allocated object. /// - /// * The computed offset, **in bytes**, cannot overflow or underflow an - /// `isize`. + /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// /// * The offset being in bounds cannot rely on "wrapping around" the address /// space. That is, the infinite-precision sum must fit in a `usize`. diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 5b1cf2dee9a83..110493bbec159 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -413,27 +413,14 @@ impl<'a> Id<'a> { /// quotes, ...) will return an empty `Err` value. pub fn new>(name: Name) -> Result, ()> { let name = name.into_cow(); - { - let mut chars = name.chars(); - match chars.next() { - Some(c) if is_letter_or_underscore(c) => {} - _ => return Err(()), - } - if !chars.all(is_constituent) { - return Err(()); - } - } - return Ok(Id { name: name }); - - fn is_letter_or_underscore(c: char) -> bool { - in_range('a', c, 'z') || in_range('A', c, 'Z') || c == '_' - } - fn is_constituent(c: char) -> bool { - is_letter_or_underscore(c) || in_range('0', c, '9') + match name.chars().next() { + Some(c) if c.is_ascii_alphabetic() || c == '_' => {} + _ => return Err(()), } - fn in_range(low: char, c: char, high: char) -> bool { - low as usize <= c as usize && c as usize <= high as usize + if !name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' ) { + return Err(()); } + return Ok(Id { name: name }); } pub fn as_slice(&'a self) -> &'a str { @@ -484,8 +471,7 @@ pub trait Labeller<'a> { /// Maps `e` to a label that will be used in the rendered output. /// The label need not be unique, and may be the empty string; the /// default is in fact the empty string. - fn edge_label(&'a self, e: &Self::Edge) -> LabelText<'a> { - let _ignored = e; + fn edge_label(&'a self, _e: &Self::Edge) -> LabelText<'a> { LabelStr("".into_cow()) } @@ -655,79 +641,58 @@ pub fn render_opts<'a, N, E, G, W>(g: &'a G, G: Labeller<'a, Node=N, Edge=E> + GraphWalk<'a, Node=N, Edge=E>, W: Write { - fn writeln(w: &mut W, arg: &[&str]) -> io::Result<()> { - for &s in arg { - w.write_all(s.as_bytes())?; - } - write!(w, "\n") - } - - fn indent(w: &mut W) -> io::Result<()> { - w.write_all(b" ") - } - - writeln(w, &["digraph ", g.graph_id().as_slice(), " {"])?; + writeln!(w, "digraph {} {{", g.graph_id().as_slice())?; for n in g.nodes().iter() { - indent(w)?; + write!(w, " ")?; let id = g.node_id(n); let escaped = &g.node_label(n).to_dot_string(); - let shape; - let mut text = vec![id.as_slice()]; + let mut text = Vec::new(); + write!(text, "{}", id.as_slice()).unwrap(); if !options.contains(&RenderOption::NoNodeLabels) { - text.push("[label="); - text.push(escaped); - text.push("]"); + write!(text, "[label={}]", escaped).unwrap(); } let style = g.node_style(n); if !options.contains(&RenderOption::NoNodeStyles) && style != Style::None { - text.push("[style=\""); - text.push(style.as_slice()); - text.push("\"]"); + write!(text, "[style=\"{}\"]", style.as_slice()).unwrap(); } if let Some(s) = g.node_shape(n) { - shape = s.to_dot_string(); - text.push("[shape="); - text.push(&shape); - text.push("]"); + write!(text, "[shape={}]", &s.to_dot_string()).unwrap(); } - text.push(";"); - writeln(w, &text)?; + writeln!(text, ";").unwrap(); + w.write_all(&text[..])?; } for e in g.edges().iter() { let escaped_label = &g.edge_label(e).to_dot_string(); - indent(w)?; + write!(w, " ")?; let source = g.source(e); let target = g.target(e); let source_id = g.node_id(&source); let target_id = g.node_id(&target); - let mut text = vec![source_id.as_slice(), " -> ", target_id.as_slice()]; + let mut text = Vec::new(); + write!(text, "{} -> {}", source_id.as_slice(), target_id.as_slice()).unwrap(); if !options.contains(&RenderOption::NoEdgeLabels) { - text.push("[label="); - text.push(escaped_label); - text.push("]"); + write!(text, "[label={}]", escaped_label).unwrap(); } let style = g.edge_style(e); if !options.contains(&RenderOption::NoEdgeStyles) && style != Style::None { - text.push("[style=\""); - text.push(style.as_slice()); - text.push("\"]"); + write!(text, "[style=\"{}\"]", style.as_slice()).unwrap(); } - text.push(";"); - writeln(w, &text)?; + writeln!(text, ";").unwrap(); + w.write_all(&text[..])?; } - writeln(w, &["}"]) + writeln!(w, "}}") } pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 7099b9511292a..2945b1ab91245 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -341,7 +341,7 @@ impl<'gcx> HashStable> for Span { std_hash::Hash::hash(&TAG_VALID_SPAN, hasher); // We truncate the stable_id hash and line and col numbers. The chances // of causing a collision this way should be minimal. - std_hash::Hash::hash(&file_lo.name, hasher); + std_hash::Hash::hash(&(file_lo.name_hash as u64), hasher); let col = (col_lo.0 as u64) & 0xFF; let line = ((line_lo as u64) & 0xFF_FF_FF) << 8; diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c25aa10eb1e73..57120d61e7c7b 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -387,7 +387,8 @@ impl<'gcx> HashStable> for FileMap { hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher) { let FileMap { - ref name, + name: _, // We hash the smaller name_hash instead of this + name_hash, name_was_remapped, unmapped_path: _, crate_of_origin, @@ -402,7 +403,7 @@ impl<'gcx> HashStable> for FileMap { ref non_narrow_chars, } = *self; - name.hash_stable(hcx, hasher); + (name_hash as u64).hash_stable(hcx, hasher); name_was_remapped.hash_stable(hcx, hasher); DefId { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 9018b9fe590b2..3bcde93fde502 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -558,24 +558,29 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } ty::TyError => { } _ => { - let def_id = self.mc.tables.type_dependent_defs()[call.hir_id].def_id(); - let call_scope = region::Scope::Node(call.hir_id.local_id); - match OverloadedCallType::from_method_id(self.tcx(), def_id) { - FnMutOverloadedCall => { - let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope)); - self.borrow_expr(callee, - call_scope_r, - ty::MutBorrow, - ClosureInvocation); - } - FnOverloadedCall => { - let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope)); - self.borrow_expr(callee, - call_scope_r, - ty::ImmBorrow, - ClosureInvocation); + if let Some(def) = self.mc.tables.type_dependent_defs().get(call.hir_id) { + let def_id = def.def_id(); + let call_scope = region::Scope::Node(call.hir_id.local_id); + match OverloadedCallType::from_method_id(self.tcx(), def_id) { + FnMutOverloadedCall => { + let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope)); + self.borrow_expr(callee, + call_scope_r, + ty::MutBorrow, + ClosureInvocation); + } + FnOverloadedCall => { + let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope)); + self.borrow_expr(callee, + call_scope_r, + ty::ImmBorrow, + ClosureInvocation); + } + FnOnceOverloadedCall => self.consume_expr(callee), } - FnOnceOverloadedCall => self.consume_expr(callee), + } else { + self.tcx().sess.delay_span_bug(call.span, + "no type-dependent def for overloaded call"); } } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 6e0372f009ece..7e80139b791d1 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -528,6 +528,25 @@ impl OutputFilenames { pub fn filestem(&self) -> String { format!("{}{}", self.out_filestem, self.extra) } + + pub fn contains_path(&self, input_path: &PathBuf) -> bool { + let input_path = input_path.canonicalize().ok(); + if input_path.is_none() { + return false + } + match self.single_output_file { + Some(ref output_path) => output_path.canonicalize().ok() == input_path, + None => { + for k in self.outputs.keys() { + let output_path = self.path(k.to_owned()); + if output_path.canonicalize().ok() == input_path { + return true; + } + } + false + } + } + } } pub fn host_triple() -> &'static str { @@ -596,6 +615,12 @@ impl Options { ).map(|(src, dst)| (src.clone(), dst.clone())).collect() ) } + + /// True if there will be an output file generated + pub fn will_create_output_file(&self) -> bool { + !self.debugging_opts.parse_only && // The file is just being parsed + !self.debugging_opts.ls // The file is just being queried + } } // The type of entry function, so diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a2692fb8f5a1e..978c6c742339c 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1484,27 +1484,25 @@ impl<'a, 'tcx> LayoutDetails { Some(niche) => niche, None => continue }; + let mut align = dl.aggregate_align; let st = variants.iter().enumerate().map(|(j, v)| { let mut st = univariant_uninterned(v, &def.repr, StructKind::AlwaysSized)?; st.variants = Variants::Single { index: j }; + + align = align.max(st.align); + Ok(st) }).collect::, _>>()?; let offset = st[i].fields.offset(field_index) + offset; - let LayoutDetails { mut size, mut align, .. } = st[i]; + let size = st[i].size; - let mut niche_align = niche.value.align(dl); let abi = if offset.bytes() == 0 && niche.value.size(dl) == size { Abi::Scalar(niche.clone()) } else { - if offset.abi_align(niche_align) != offset { - niche_align = dl.i8_align; - } Abi::Aggregate { sized: true } }; - align = align.max(niche_align); - size = size.abi_align(align); return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::NicheFilling { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9e5de8d54e9de..a288ff6316f83 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -71,6 +71,7 @@ use profile; pub fn compile_input(sess: &Session, cstore: &CStore, + input_path: &Option, input: &Input, outdir: &Option, output: &Option, @@ -142,6 +143,20 @@ pub fn compile_input(sess: &Session, }; let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); + + // Ensure the source file isn't accidentally overwritten during compilation. + match *input_path { + Some(ref input_path) => { + if outputs.contains_path(input_path) && sess.opts.will_create_output_file() { + sess.err(&format!( + "the input file \"{}\" would be overwritten by the generated executable", + input_path.display())); + return Err(CompileIncomplete::Stopped); + } + }, + None => {} + } + let crate_name = ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input); let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 29d3d31e45155..60857505c7ac5 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -232,7 +232,7 @@ pub fn run_compiler<'a>(args: &[String], let loader = file_loader.unwrap_or(box RealFileLoader); let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping())); let mut sess = session::build_session_with_codemap( - sopts, input_file_path, descriptions, codemap, emitter_dest, + sopts, input_file_path.clone(), descriptions, codemap, emitter_dest, ); rustc_trans::init(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); @@ -252,6 +252,7 @@ pub fn run_compiler<'a>(args: &[String], let control = callbacks.build_controller(&sess, &matches); (driver::compile_input(&sess, &cstore, + &input_file_path, &input, &odir, &ofile, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 81db44b055311..501f6bb0c0d82 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -349,7 +349,27 @@ impl MissingDoc { } } - let has_doc = attrs.iter().any(|a| a.is_value_str() && a.check_name("doc")); + fn has_doc(attr: &ast::Attribute) -> bool { + if !attr.check_name("doc") { + return false; + } + + if attr.is_value_str() { + return true; + } + + if let Some(list) = attr.meta_item_list() { + for meta in list { + if meta.check_name("include") { + return true; + } + } + } + + false + } + + let has_doc = attrs.iter().any(|a| has_doc(a)); if !has_doc { cx.span_lint(MISSING_DOCS, cx.tcx.sess.codemap().def_span(sp), diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 49a017535ffd1..0e9f4a8f1784b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1129,6 +1129,7 @@ impl<'a, 'tcx> CrateMetadata { lines, multibyte_chars, non_narrow_chars, + name_hash, .. } = filemap_to_import; let source_length = (end_pos - start_pos).to_usize(); @@ -1155,6 +1156,7 @@ impl<'a, 'tcx> CrateMetadata { name_was_remapped, self.cnum.as_u32(), src_hash, + name_hash, source_length, lines, multibyte_chars, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 29369f9f8bb41..5ddbb18450e2e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -28,8 +28,10 @@ use rustc::ty::codec::{self as ty_codec, TyEncoder}; use rustc::session::config::{self, CrateTypeProcMacro}; use rustc::util::nodemap::{FxHashMap, NodeSet}; +use rustc_data_structures::stable_hasher::StableHasher; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; +use std::hash::Hash; use std::io::prelude::*; use std::io::Cursor; use std::path::Path; @@ -290,6 +292,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { let mut adapted = (**filemap).clone(); adapted.name = Path::new(&working_dir).join(name).into(); + adapted.name_hash = { + let mut hasher: StableHasher = StableHasher::new(); + adapted.name.hash(&mut hasher); + hasher.finish() + }; Rc::new(adapted) } }, diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index e2640d695c6d0..b1fef274cba4b 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -377,6 +377,17 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< assert!(target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; + // Note that at this point in time the `codegen_units` here may not be in a + // deterministic order (but we know they're deterministically the same set). + // We want this merging to produce a deterministic ordering of codegen units + // from the input. + // + // Due to basically how we've implemented the merging below (merge the two + // smallest into each other) we're sure to start off with a deterministic + // order (sorted by name). This'll mean that if two cgus have the same size + // the stable sort below will keep everything nice and deterministic. + codegen_units.sort_by_key(|cgu| cgu.name().clone()); + // Merge the two smallest codegen units until the target size is reached. // Note that "size" is estimated here rather inaccurately as the number of // translation items in a given unit. This could be improved on. diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 515baa2c6698f..3be44f3095858 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3720,9 +3720,10 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { })).and_then(|did| c.impls.get(&did)); if let Some(impls) = inner_impl { out.push_str(""); - out.push_str(&format!("Methods from {:#}<Target={:#}>", - impl_.inner_impl().trait_.as_ref().unwrap(), - target)); + out.push_str(&format!("Methods from {}<Target={}>", + Escape(&format!("{:#}", + impl_.inner_impl().trait_.as_ref().unwrap())), + Escape(&format!("{:#}", target)))); out.push_str(""); let ret = impls.iter() .filter(|i| i.inner_impl().trait_.is_none()) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index abb902003706c..8e861f10dd8d4 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -263,7 +263,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, cfgs: Vec, } let res = panic::catch_unwind(AssertUnwindSafe(|| { - driver::compile_input(&sess, &cstore, &input, &out, &None, None, &control) + driver::compile_input(&sess, &cstore, &None, &input, &out, &None, None, &control) })); let compile_result = match res { @@ -533,7 +533,7 @@ impl Collector { should_panic: testing::ShouldPanic::No, allow_fail, }, - testfn: testing::DynTestFn(box move |()| { + testfn: testing::DynTestFn(box move || { let panic = io::set_panic(None); let print = io::set_print(None); match { diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 6d3fbc9d26822..8308ab48d9ceb 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -263,7 +263,7 @@ impl Seek for BufReader { /// See `std::io::Seek` for more details. /// /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` - /// where `n` minus the internal buffer length underflows an `i64`, two + /// where `n` minus the internal buffer length overflows an `i64`, two /// seeks will be performed instead of one. If the second seek returns /// `Err`, the underlying reader will be left at the same position it would /// have if you seeked to `SeekFrom::Current(0)`. diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index a74e8a21c42a6..15ddb62bab5c8 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -290,7 +290,7 @@ impl Duration { } /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] - /// if the result would be negative or if underflow occurred. + /// if the result would be negative or if overflow occurred. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2c91d60ce9d59..e49a7117192d3 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -246,6 +246,7 @@ impl CodeMap { name_was_remapped: bool, crate_of_origin: u32, src_hash: u128, + name_hash: u128, source_len: usize, mut file_local_lines: Vec, mut file_local_multibyte_chars: Vec, @@ -282,6 +283,7 @@ impl CodeMap { lines: RefCell::new(file_local_lines), multibyte_chars: RefCell::new(file_local_multibyte_chars), non_narrow_chars: RefCell::new(file_local_non_narrow_chars), + name_hash, }); files.push(filemap.clone()); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 07ea6a0908688..81baa0c3954ca 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1115,15 +1115,19 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { match File::open(&filename).and_then(|mut f| f.read_to_end(&mut buf)) { Ok(..) => {} Err(e) => { - self.cx.span_warn(at.span, - &format!("couldn't read {}: {}", - filename.display(), - e)); + self.cx.span_err(at.span, + &format!("couldn't read {}: {}", + filename.display(), + e)); } } match String::from_utf8(buf) { Ok(src) => { + // Add this input file to the code map to make it available as + // dependency information + self.cx.codemap().new_filemap_and_lines(&filename, &src); + let include_info = vec![ dummy_spanned(ast::NestedMetaItemKind::MetaItem( attr::mk_name_value_item_str("file".into(), @@ -1137,9 +1141,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { attr::mk_list_item("include".into(), include_info)))); } Err(_) => { - self.cx.span_warn(at.span, - &format!("{} wasn't a utf-8 file", - filename.display())); + self.cx.span_err(at.span, + &format!("{} wasn't a utf-8 file", + filename.display())); } } } else { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 8d5d7c81c0ea4..85f0925b98210 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -30,7 +30,7 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::cmp::{self, Ordering}; use std::fmt; -use std::hash::Hasher; +use std::hash::{Hasher, Hash}; use std::ops::{Add, Sub}; use std::path::PathBuf; use std::rc::Rc; @@ -691,6 +691,8 @@ pub struct FileMap { pub multibyte_chars: RefCell>, /// Width of characters that are not narrow in the source code pub non_narrow_chars: RefCell>, + /// A hash of the filename, used for speeding up the incr. comp. hashing. + pub name_hash: u128, } impl Encodable for FileMap { @@ -752,6 +754,9 @@ impl Encodable for FileMap { })?; s.emit_struct_field("non_narrow_chars", 8, |s| { (*self.non_narrow_chars.borrow()).encode(s) + })?; + s.emit_struct_field("name_hash", 9, |s| { + self.name_hash.encode(s) }) }) } @@ -801,6 +806,8 @@ impl Decodable for FileMap { d.read_struct_field("multibyte_chars", 7, |d| Decodable::decode(d))?; let non_narrow_chars: Vec = d.read_struct_field("non_narrow_chars", 8, |d| Decodable::decode(d))?; + let name_hash: u128 = + d.read_struct_field("name_hash", 9, |d| Decodable::decode(d))?; Ok(FileMap { name, name_was_remapped, @@ -816,7 +823,8 @@ impl Decodable for FileMap { external_src: RefCell::new(ExternalSource::AbsentOk), lines: RefCell::new(lines), multibyte_chars: RefCell::new(multibyte_chars), - non_narrow_chars: RefCell::new(non_narrow_chars) + non_narrow_chars: RefCell::new(non_narrow_chars), + name_hash, }) }) } @@ -836,9 +844,16 @@ impl FileMap { start_pos: BytePos) -> FileMap { remove_bom(&mut src); - let mut hasher: StableHasher = StableHasher::new(); - hasher.write(src.as_bytes()); - let src_hash = hasher.finish(); + let src_hash = { + let mut hasher: StableHasher = StableHasher::new(); + hasher.write(src.as_bytes()); + hasher.finish() + }; + let name_hash = { + let mut hasher: StableHasher = StableHasher::new(); + name.hash(&mut hasher); + hasher.finish() + }; let end_pos = start_pos.to_usize() + src.len(); FileMap { @@ -854,6 +869,7 @@ impl FileMap { lines: RefCell::new(Vec::new()), multibyte_chars: RefCell::new(Vec::new()), non_narrow_chars: RefCell::new(Vec::new()), + name_hash, } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index bc96a5d6740c4..0d837c470a223 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -35,6 +35,7 @@ #![deny(warnings)] #![feature(asm)] +#![feature(fnbox)] #![cfg_attr(unix, feature(libc))] #![feature(set_stdio)] #![feature(panic_unwind)] @@ -56,6 +57,7 @@ use self::OutputLocation::*; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::any::Any; +use std::boxed::FnBox; use std::cmp; use std::collections::BTreeMap; use std::env; @@ -133,16 +135,6 @@ pub trait TDynBenchFn: Send { fn run(&self, harness: &mut Bencher); } -pub trait FnBox: Send + 'static { - fn call_box(self: Box, t: T); -} - -impl FnBox for F { - fn call_box(self: Box, t: T) { - (*self)(t) - } -} - // A function that runs a test. If the function returns successfully, // the test succeeds; if the function panics then the test fails. We // may need to come up with a more clever definition of test in order @@ -150,7 +142,7 @@ impl FnBox for F { pub enum TestFn { StaticTestFn(fn()), StaticBenchFn(fn(&mut Bencher)), - DynTestFn(Box>), + DynTestFn(Box), DynBenchFn(Box), } @@ -1337,14 +1329,14 @@ pub fn convert_benchmarks_to_tests(tests: Vec) -> Vec { - DynTestFn(Box::new(move |()| { + DynTestFn(Box::new(move || { bench::run_once(|b| { __rust_begin_short_backtrace(|| bench.run(b)) }) })) } StaticBenchFn(benchfn) => { - DynTestFn(Box::new(move |()| { + DynTestFn(Box::new(move || { bench::run_once(|b| { __rust_begin_short_backtrace(|| benchfn(b)) }) @@ -1379,7 +1371,7 @@ pub fn run_test(opts: &TestOpts, fn run_test_inner(desc: TestDesc, monitor_ch: Sender, nocapture: bool, - testfn: Box>) { + testfn: Box) { struct Sink(Arc>>); impl Write for Sink { fn write(&mut self, data: &[u8]) -> io::Result { @@ -1405,9 +1397,7 @@ pub fn run_test(opts: &TestOpts, None }; - let result = catch_unwind(AssertUnwindSafe(|| { - testfn.call_box(()) - })); + let result = catch_unwind(AssertUnwindSafe(testfn)); if let Some((printio, panicio)) = oldio { io::set_print(printio); @@ -1449,14 +1439,14 @@ pub fn run_test(opts: &TestOpts, return; } DynTestFn(f) => { - let cb = move |()| { - __rust_begin_short_backtrace(|| f.call_box(())) + let cb = move || { + __rust_begin_short_backtrace(f) }; run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb)) } StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, - Box::new(move |()| __rust_begin_short_backtrace(f))), + Box::new(move || __rust_begin_short_backtrace(f))), } } @@ -1720,7 +1710,7 @@ mod tests { should_panic: ShouldPanic::No, allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| f())), + testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1738,7 +1728,7 @@ mod tests { should_panic: ShouldPanic::No, allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| f())), + testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1758,7 +1748,7 @@ mod tests { should_panic: ShouldPanic::Yes, allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| f())), + testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1778,7 +1768,7 @@ mod tests { should_panic: ShouldPanic::YesWithMessage("error message"), allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| f())), + testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1800,7 +1790,7 @@ mod tests { should_panic: ShouldPanic::YesWithMessage(expected), allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| f())), + testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1818,7 +1808,7 @@ mod tests { should_panic: ShouldPanic::Yes, allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| f())), + testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1852,7 +1842,7 @@ mod tests { should_panic: ShouldPanic::No, allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| {})), + testfn: DynTestFn(Box::new(move || {})), }, TestDescAndFn { desc: TestDesc { @@ -1861,7 +1851,7 @@ mod tests { should_panic: ShouldPanic::No, allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| {})), + testfn: DynTestFn(Box::new(move || {})), }]; let filtered = filter_tests(&opts, tests); @@ -1885,7 +1875,7 @@ mod tests { should_panic: ShouldPanic::No, allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| {})) + testfn: DynTestFn(Box::new(move || {})) }) .collect() } @@ -1967,7 +1957,7 @@ mod tests { should_panic: ShouldPanic::No, allow_fail: false, }, - testfn: DynTestFn(Box::new(move |()| testfn())), + testfn: DynTestFn(Box::new(testfn)), }; tests.push(test); } diff --git a/src/test/COMPILER_TESTS.md b/src/test/COMPILER_TESTS.md index 021f27dacbe0f..c255294e790b7 100644 --- a/src/test/COMPILER_TESTS.md +++ b/src/test/COMPILER_TESTS.md @@ -35,20 +35,24 @@ The error levels that you can have are: ## Summary of Header Commands Header commands specify something about the entire test file as a -whole, instead of just a few lines inside the test. +whole. They are normally put right after the copyright comment, e.g.: + +```Rust +// Copyright blah blah blah +// except according to those terms. + +// ignore-test This doesn't actually work +``` + +### Ignoring tests + +These are used to ignore the test in some situations, which means the test won't +be compiled or run. * `ignore-X` where `X` is a target detail or stage will ignore the test accordingly (see below) * `ignore-pretty` will not compile the pretty-printed test (this is done to test the pretty-printer, but might not always work) * `ignore-test` always ignores the test -* `ignore-lldb` and `ignore-gdb` will skip the debuginfo tests -* `min-{gdb,lldb}-version` -* `should-fail` indicates that the test should fail; used for "meta testing", - where we test the compiletest program itself to check that it will generate - errors in appropriate scenarios. This header is ignored for pretty-printer tests. -* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X. - Such tests are supposed to ensure that the compiler errors when usage of a gated - feature is attempted without the proper `#![feature(X)]` tag. - Each unstable lang feature is required to have a gate test. +* `ignore-lldb` and `ignore-gdb` will skip a debuginfo test on that debugger. Some examples of `X` in `ignore-X`: @@ -58,6 +62,22 @@ Some examples of `X` in `ignore-X`: * Pointer width: `32bit`, `64bit`. * Stage: `stage0`, `stage1`, `stage2`. +### Other Header Commands + +* `min-{gdb,lldb}-version` +* `min-llvm-version` +* `must-compile-successfully` for UI tests, indicates that the test is supposed + to compile, as opposed to the default where the test is supposed to error out. +* `compile-flags` passes extra command-line args to the compiler, + e.g. `compile-flags -g` which forces debuginfo to be enabled. +* `should-fail` indicates that the test should fail; used for "meta testing", + where we test the compiletest program itself to check that it will generate + errors in appropriate scenarios. This header is ignored for pretty-printer tests. +* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X. + Such tests are supposed to ensure that the compiler errors when usage of a gated + feature is attempted without the proper `#![feature(X)]` tag. + Each unstable lang feature is required to have a gate test. + ## Revisions Certain classes of tests support "revisions" (as of the time of this @@ -109,6 +129,12 @@ fails, we will print out the current output, but it is also saved in printed as part of the test failure message), so you can run `diff` and so forth. +Normally, the test-runner checks that UI tests fail compilation. If you want +to do a UI test for code that *compiles* (e.g. to test warnings, or if you +have a collection of tests, only some of which error out), you can use the +`// must-compile-successfully` header command to have the test runner instead +check that the test compiles successfully. + ### Editing and updating the reference files If you have changed the compiler's output intentionally, or you are diff --git a/src/test/compile-fail/external-doc-error.rs b/src/test/compile-fail/external-doc-error.rs new file mode 100644 index 0000000000000..1ae0d0bd2760a --- /dev/null +++ b/src/test/compile-fail/external-doc-error.rs @@ -0,0 +1,16 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(external_doc)] + +#[doc(include = "not-a-file.md")] //~ ERROR: couldn't read +pub struct SomeStruct; + +fn main() {} diff --git a/src/test/compile-fail/issue-46771.rs b/src/test/compile-fail/issue-46771.rs new file mode 100644 index 0000000000000..f8bcd8861f3a6 --- /dev/null +++ b/src/test/compile-fail/issue-46771.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + struct Foo; + (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `main::Foo` +} diff --git a/src/test/run-make/include_bytes_deps/Makefile b/src/test/run-make/include_bytes_deps/Makefile index f7b1d21ace281..1293695b79977 100644 --- a/src/test/run-make/include_bytes_deps/Makefile +++ b/src/test/run-make/include_bytes_deps/Makefile @@ -8,7 +8,7 @@ ifneq ($(shell uname),FreeBSD) ifndef IS_WINDOWS all: $(RUSTC) --emit dep-info main.rs - $(CGREP) "input.txt" "input.bin" < $(TMPDIR)/main.d + $(CGREP) "input.txt" "input.bin" "input.md" < $(TMPDIR)/main.d else all: diff --git a/src/test/run-make/include_bytes_deps/input.md b/src/test/run-make/include_bytes_deps/input.md new file mode 100644 index 0000000000000..2a19b7405f795 --- /dev/null +++ b/src/test/run-make/include_bytes_deps/input.md @@ -0,0 +1 @@ +# Hello, world! diff --git a/src/test/run-make/include_bytes_deps/main.rs b/src/test/run-make/include_bytes_deps/main.rs index 579b2a452a112..27ca1a46a500d 100644 --- a/src/test/run-make/include_bytes_deps/main.rs +++ b/src/test/run-make/include_bytes_deps/main.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(external_doc)] + +#[doc(include="input.md")] +pub struct SomeStruct; + pub fn main() { const INPUT_TXT: &'static str = include_str!("input.txt"); const INPUT_BIN: &'static [u8] = include_bytes!("input.bin"); diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index cfe8048638a86..f0ab1d5dc0fec 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -71,5 +71,5 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { let (sess, cstore) = basic_sess(sysroot); let control = CompileController::basic(); let input = Input::Str { name: FileName::Anon, input: code }; - let _ = compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control); + let _ = compile_input(&sess, &cstore, &None, &input, &None, &Some(output), None, &control); } diff --git a/src/test/run-make/output-filename-overwrites-input/Makefile b/src/test/run-make/output-filename-overwrites-input/Makefile new file mode 100644 index 0000000000000..0554627d67753 --- /dev/null +++ b/src/test/run-make/output-filename-overwrites-input/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +all: + cp foo.rs $(TMPDIR)/foo + $(RUSTC) $(TMPDIR)/foo 2>&1 \ + | $(CGREP) -e "the input file \".*foo\" would be overwritten by the generated executable" + $(RUSTC) foo.rs 2>&1 && $(RUSTC) -Z ls $(TMPDIR)/foo 2>&1 + cp foo.rs $(TMPDIR)/foo.rs + $(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo.rs 2>&1 \ + | $(CGREP) -e "the input file \".*foo.rs\" would be overwritten by the generated executable" diff --git a/src/test/run-make/output-filename-overwrites-input/foo.rs b/src/test/run-make/output-filename-overwrites-input/foo.rs new file mode 100644 index 0000000000000..046d27a9f0fe5 --- /dev/null +++ b/src/test/run-make/output-filename-overwrites-input/foo.rs @@ -0,0 +1,11 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() {} diff --git a/src/test/run-make/weird-output-filenames/Makefile b/src/test/run-make/weird-output-filenames/Makefile index a5543e3b2c4d0..f161fe9f8e8df 100644 --- a/src/test/run-make/weird-output-filenames/Makefile +++ b/src/test/run-make/weird-output-filenames/Makefile @@ -7,8 +7,8 @@ all: cp foo.rs $(TMPDIR)/.foo.bar $(RUSTC) $(TMPDIR)/.foo.bar 2>&1 \ | $(CGREP) -e "invalid character.*in crate name:" - cp foo.rs $(TMPDIR)/+foo+bar - $(RUSTC) $(TMPDIR)/+foo+bar 2>&1 \ + cp foo.rs $(TMPDIR)/+foo+bar.rs + $(RUSTC) $(TMPDIR)/+foo+bar.rs 2>&1 \ | $(CGREP) -e "invalid character.*in crate name:" cp foo.rs $(TMPDIR)/-foo.rs $(RUSTC) $(TMPDIR)/-foo.rs 2>&1 \ diff --git a/src/test/run-pass/packed-struct-optimized-enum.rs b/src/test/run-pass/packed-struct-optimized-enum.rs index b8a1e6f2f5400..7968ae2278ae9 100644 --- a/src/test/run-pass/packed-struct-optimized-enum.rs +++ b/src/test/run-pass/packed-struct-optimized-enum.rs @@ -19,7 +19,9 @@ impl Clone for Packed { fn sanity_check_size(one: T) { let two = [one, one]; let stride = (&two[1] as *const _ as usize) - (&two[0] as *const _ as usize); - assert_eq!(stride, std::mem::size_of_val(&one)); + let (size, align) = (std::mem::size_of::(), std::mem::align_of::()); + assert_eq!(stride, size); + assert_eq!(size % align, 0); } fn main() { @@ -32,5 +34,12 @@ fn main() { // In #46769, `Option<(Packed<&()>, bool)>` was found to have // pointer alignment, without actually being aligned in size. // E.g. on 64-bit platforms, it had alignment `8` but size `9`. - sanity_check_size(Some((Packed(&()), true))); + type PackedRefAndBool<'a> = (Packed<&'a ()>, bool); + sanity_check_size::>(Some((Packed(&()), true))); + + // Make sure we don't pay for the enum optimization in size, + // e.g. we shouldn't need extra padding after the packed data. + assert_eq!(std::mem::align_of::>(), 1); + assert_eq!(std::mem::size_of::>(), + std::mem::size_of::()); } diff --git a/src/test/rustdoc/auxiliary/external-cross.rs b/src/test/rustdoc/auxiliary/external-cross.rs index cb14fec7abe7a..767fb05313adc 100644 --- a/src/test/rustdoc/auxiliary/external-cross.rs +++ b/src/test/rustdoc/auxiliary/external-cross.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(external_doc)] +#![deny(missing_doc)] #[doc(include="external-cross-doc.md")] pub struct NeedMoreDocs; diff --git a/src/test/rustdoc/escape-deref-methods.rs b/src/test/rustdoc/escape-deref-methods.rs new file mode 100644 index 0000000000000..f31b0ddca9ada --- /dev/null +++ b/src/test/rustdoc/escape-deref-methods.rs @@ -0,0 +1,45 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +use std::ops::{Deref, DerefMut}; + +#[derive(Debug, Clone)] +pub struct Title { + name: String, +} + +#[derive(Debug, Clone)] +pub struct TitleList { + pub members: Vec, +} + +impl TitleList { + pub fn new() -> Self { + TitleList { members: Vec::new() } + } +} + +impl Deref for TitleList { + type Target = Vec<Title>; + + fn deref(&self) -> &Self::Target { + &self.members + } +} + +// @has foo/struct.TitleList.html +// @has - '//*[@class="sidebar-title"]' 'Methods from Deref<Target=Vec<Title>>' +impl DerefMut for TitleList { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.members + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 8546289fdec09..80630b5e2cf4b 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -711,7 +711,7 @@ pub fn make_test_name(config: &Config, testpaths: &TestPaths) -> test::TestName pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn { let config = config.clone(); let testpaths = testpaths.clone(); - test::DynTestFn(Box::new(move |()| runtest::run(config, &testpaths))) + test::DynTestFn(Box::new(move || runtest::run(config, &testpaths))) } /// Returns (Path to GDB, GDB Version, GDB has Rust Support)