diff options
123 files changed, 1293 insertions, 914 deletions
diff --git a/configure b/configure index 9b9de9da067..4e763f76139 100755 --- a/configure +++ b/configure @@ -106,8 +106,8 @@ probe() { T=$(command -v $P 2>&1) if [ $? -eq 0 ] then - VER0=$($P --version 2>/dev/null | head -1 \ - | sed -e 's/[^0-9]*\([vV]\?[0-9.]\+[^ ]*\).*/\1/' ) + VER0=$($P --version 2>/dev/null \ + | grep -o '[vV]\?[0-9][0-9.][a-z0-9.-]*' | head -1 ) if [ $? -eq 0 -a "x${VER0}" != "x" ] then VER="($VER0)" @@ -711,6 +711,20 @@ else probe_need CFG_GIT git fi +# Use `md5sum` on GNU platforms, or `md5 -q` on BSD +probe CFG_MD5 md5 +probe CFG_MD5SUM md5sum +if [ -n "$CFG_MD5" ] +then + CFG_HASH_COMMAND="$CFG_MD5 -q | head -c 8" +elif [ -n "$CFG_MD5SUM" ] +then + CFG_HASH_COMMAND="$CFG_MD5SUM | head -c 8" +else + err 'could not find one of: md5 md5sum' +fi +putvar CFG_HASH_COMMAND + probe CFG_CLANG clang++ probe CFG_CCACHE ccache probe CFG_GCC gcc diff --git a/mk/main.mk b/mk/main.mk index 738580cb5b5..964153e4494 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -20,7 +20,9 @@ CFG_RELEASE_NUM=1.1.0 # versions (section 9) CFG_PRERELEASE_VERSION=.1 -CFG_FILENAME_EXTRA=4e7c5e5c +# Append a version-dependent hash to each library, so we can install different +# versions in the same place +CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE) | $(CFG_HASH_COMMAND)) ifeq ($(CFG_RELEASE_CHANNEL),stable) # This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly" diff --git a/src/doc/reference.md b/src/doc/reference.md index 2ddec9ba424..21e9be59ebb 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1346,6 +1346,8 @@ vtable when the trait is used as a [trait object](#trait-objects). Traits are implemented for specific types through separate [implementations](#implementations). +Consider the following trait: + ``` # type Surface = i32; # type BoundingBox = i32; @@ -1360,6 +1362,20 @@ This defines a trait with two methods. All values that have `draw` and `bounding_box` methods called, using `value.bounding_box()` [syntax](#method-call-expressions). +Traits can include default implementations of methods, as in: + +``` +trait Foo { + fn bar(&self); + + fn baz(&self) { println!("We called baz."); } +} +``` + +Here the `baz` method has a default implementation, so types that implement +`Foo` need only implement `bar`. It is also possible for implementing types +to override a method that has a default implementation. + Type parameters can be specified for a trait to make it generic. These appear after the trait name, using the same syntax used in [generic functions](#generic-functions). @@ -1372,6 +1388,35 @@ trait Seq<T> { } ``` +It is also possible to define associated types for a trait. Consider the +following example of a `Container` trait. Notice how the type is available +for use in the method signatures: + +``` +trait Container { + type E; + fn empty() -> Self; + fn insert(&mut self, Self::E); +} +``` + +In order for a type to implement this trait, it must not only provide +implementations for every method, but it must specify the type `E`. Here's +an implementation of `Container` for the standard library type `Vec`: + +``` +# trait Container { +# type E; +# fn empty() -> Self; +# fn insert(&mut self, Self::E); +# } +impl<T> Container for Vec<T> { + type E = T; + fn empty() -> Vec<T> { Vec::new() } + fn insert(&mut self, x: T) { self.push(x); } +} +``` + Generic functions may use traits as _bounds_ on their type parameters. This will have two effects: only types that have the trait may instantiate the parameter, and within the generic function, the methods of the trait can be @@ -3470,13 +3515,23 @@ more of the closure traits: ### Trait objects -Every trait item (see [traits](#traits)) defines a type with the same name as -the trait. This type is called the _trait object_ of the trait. Trait objects -permit "late binding" of methods, dispatched using _virtual method tables_ -("vtables"). Whereas most calls to trait methods are "early bound" (statically -resolved) to specific implementations at compile time, a call to a method on an -trait objects is only resolved to a vtable entry at compile time. The actual -implementation for each vtable entry can vary on an object-by-object basis. +In Rust, a type like `&SomeTrait` or `Box<SomeTrait>` is called a _trait object_. +Each instance of a trait object includes: + + - a pointer to an instance of a type `T` that implements `SomeTrait` + - a _virtual method table_, often just called a _vtable_, which contains, for + each method of `SomeTrait` that `T` implements, a pointer to `T`'s + implementation (i.e. a function pointer). + +The purpose of trait objects is to permit "late binding" of methods. A call to +a method on a trait object is only resolved to a vtable entry at compile time. +The actual implementation for each vtable entry can vary on an object-by-object +basis. + +Note that for a trait object to be instantiated, the trait must be +_object-safe_. Object safety rules are defined in [RFC 255]. + +[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md Given a pointer-typed expression `E` of type `&T` or `Box<T>`, where `T` implements trait `R`, casting `E` to the corresponding pointer type `&R` or diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index 89f0db8dc56..9ca5de2b50a 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -175,7 +175,7 @@ data, we call the `clone()` method. In this example, `y` is no longer a referenc to the vector stored in `x`, but a copy of its first element, `"Hello"`. Now that we don’t have a reference, our `push()` works just fine. -[move]: move-semantics.html +[move]: ownership.html#move-semantics If we truly want a reference, we need the other option: ensure that our reference goes out of scope before we try to do the mutation. That looks like this: diff --git a/src/doc/trpl/dining-philosophers.md b/src/doc/trpl/dining-philosophers.md index b1bea4f819e..81280e8920c 100644 --- a/src/doc/trpl/dining-philosophers.md +++ b/src/doc/trpl/dining-philosophers.md @@ -450,7 +450,7 @@ which blocks execution until the thread has completed execution. This ensures that the threads complete their work before the program exits. If you run this program, you’ll see that the philosophers eat out of order! -We have mult-threading! +We have multi-threading! ```text Gilles Deleuze is eating. diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index b3689968b7f..dcaf698fd3c 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -181,6 +181,8 @@ match version { This function makes use of an enum, `ParseError`, to enumerate the various errors that can occur. +The [`Debug`](../std/fmt/trait.Debug.html) trait is what lets us print the enum value using the `{:?}` format operation. + # Non-recoverable errors with `panic!` In the case of an error that is unexpected and not recoverable, the `panic!` diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index e0cc45c254b..a93f622e9c5 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -42,7 +42,7 @@ loop is just a handy way to write this `loop`/`match`/`break` construct. `for` loops aren't the only thing that uses iterators, however. Writing your own iterator involves implementing the `Iterator` trait. While doing that is outside of the scope of this guide, Rust provides a number of useful iterators -to accomplish various threads. Before we talk about those, we should talk about a +to accomplish various tasks. Before we talk about those, we should talk about a Rust anti-pattern. And that's using ranges like this. Yes, we just talked about how ranges are cool. But ranges are also very diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md index 7b1cd7dc809..9622a92303f 100644 --- a/src/doc/trpl/the-stack-and-the-heap.md +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -80,7 +80,7 @@ This memory is kind of like a giant array: addresses start at zero and go up to the final number. So here’s a diagram of our first stack frame: | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 0 | x | 42 | We’ve got `x` located at address `0`, with the value `42`. @@ -88,7 +88,7 @@ We’ve got `x` located at address `0`, with the value `42`. When `foo()` is called, a new stack frame is allocated: | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 2 | z | 100 | | 1 | y | 5 | | 0 | x | 42 | @@ -107,7 +107,7 @@ value being stored. After `foo()` is over, its frame is deallocated: | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 0 | x | 42 | And then, after `main()`, even this last value goes away. Easy! @@ -142,13 +142,13 @@ fn main() { Okay, first, we call `main()`: | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 0 | x | 42 | Next up, `main()` calls `foo()`: | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 3 | c | 1 | | 2 | b | 100 | | 1 | a | 5 | @@ -157,7 +157,7 @@ Next up, `main()` calls `foo()`: And then `foo()` calls `bar()`: | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 4 | i | 6 | | 3 | c | 1 | | 2 | b | 100 | @@ -170,7 +170,7 @@ After `bar()` is over, its frame is deallocated, leaving just `foo()` and `main()`: | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 3 | c | 1 | | 2 | b | 100 | | 1 | a | 5 | @@ -179,7 +179,7 @@ After `bar()` is over, its frame is deallocated, leaving just `foo()` and And then `foo()` ends, leaving just `main()` | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 0 | x | 42 | And then we’re done. Getting the hang of it? It’s like piling up dishes: you @@ -206,7 +206,7 @@ fn main() { Here’s what happens in memory when `main()` is called: | Address | Name | Value | -+---------+------+--------+ +|---------|------|--------| | 1 | y | 42 | | 0 | x | ?????? | @@ -218,7 +218,7 @@ it allocates some memory for the heap, and puts `5` there. The memory now looks like this: | Address | Name | Value | -+-----------------+------+----------------+ +|-----------------|------|----------------| | 2<sup>30</sup> | | 5 | | ... | ... | ... | | 1 | y | 42 | @@ -243,7 +243,7 @@ layout of a program which has been running for a while now: | Address | Name | Value | -+----------------------+------+----------------------+ +|----------------------|------|----------------------| | 2<sup>30</sup> | | 5 | | (2<sup>30</sup>) - 1 | | | | (2<sup>30</sup>) - 2 | | | @@ -266,13 +266,13 @@ Rust programs use [jemalloc][jemalloc] for this purpose. Anyway, back to our example. Since this memory is on the heap, it can stay alive longer than the function which allocates the box. In this case, however, it doesn’t.[^moving] When the function is over, we need to free the stack frame -for `main()`. `Box<T>`, though, has a trick up its sleve: [Drop][drop]. The +for `main()`. `Box<T>`, though, has a trick up its sleeve: [Drop][drop]. The implementation of `Drop` for `Box` deallocates the memory that was allocated when it was created. Great! So when `x` goes away, it first frees the memory allocated on the heap: | Address | Name | Value | -+---------+------+--------+ +|---------|------|--------| | 1 | y | 42 | | 0 | x | ?????? | @@ -305,7 +305,7 @@ fn main() { When we enter `main()`, memory looks like this: | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 1 | y | 0 | | 0 | x | 5 | @@ -315,7 +315,7 @@ memory location that `x` lives at, which in this case is `0`. What about when we call `foo()`, passing `y` as an argument? | Address | Name | Value | -+---------+------+-------+ +|---------|------|-------| | 3 | z | 42 | | 2 | i | 0 | | 1 | y | 0 | @@ -367,7 +367,7 @@ fn main() { First, we call `main()`: | Address | Name | Value | -+-----------------+------+----------------+ +|-----------------|------|----------------| | 2<sup>30</sup> | | 20 | | ... | ... | ... | | 2 | j | 0 | @@ -380,7 +380,7 @@ value pointing there. Next, at the end of `main()`, `foo()` gets called: | Address | Name | Value | -+-----------------+------+----------------+ +|-----------------|------|----------------| | 2<sup>30</sup> | | 20 | | ... | ... | ... | | 5 | z | 4 | @@ -397,7 +397,7 @@ since `j` points at `h`. Next, `foo()` calls `baz()`, passing `z`: | Address | Name | Value | -+-----------------+------+----------------+ +|-----------------|------|----------------| | 2<sup>30</sup> | | 20 | | ... | ... | ... | | 7 | g | 100 | @@ -413,7 +413,7 @@ We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s over, we get rid of its stack frame: | Address | Name | Value | -+-----------------+------+----------------+ +|-----------------|------|----------------| | 2<sup>30</sup> | | 20 | | ... | ... | ... | | 5 | z | 4 | @@ -426,7 +426,7 @@ over, we get rid of its stack frame: Next, `foo()` calls `bar()` with `x` and `z`: | Address | Name | Value | -+----------------------+------+----------------------+ +|----------------------|------|----------------------| | 2<sup>30</sup> | | 20 | | (2<sup>30</sup>) - 1 | | 5 | | ... | ... | ... | @@ -449,7 +449,7 @@ case, we set up the variables as usual. At the end of `bar()`, it calls `baz()`: | Address | Name | Value | -+----------------------+------+----------------------+ +|----------------------|------|----------------------| | 2<sup>30</sup> | | 20 | | (2<sup>30</sup>) - 1 | | 5 | | ... | ... | ... | @@ -473,7 +473,7 @@ far. After `baz()` is over, we get rid of `f` and `g`: | Address | Name | Value | -+----------------------+------+----------------------+ +|----------------------|------|----------------------| | 2<sup>30</sup> | | 20 | | (2<sup>30</sup>) - 1 | | 5 | | ... | ... | ... | @@ -493,7 +493,7 @@ Next, we return from `bar()`. `d` in this case is a `Box<T>`, so it also frees what it points to: (2<sup>30</sup>) - 1. | Address | Name | Value | -+-----------------+------+----------------+ +|-----------------|------|----------------| | 2<sup>30</sup> | | 20 | | ... | ... | ... | | 5 | z | 4 | @@ -506,7 +506,7 @@ what it points to: (2<sup>30</sup>) - 1. And after that, `foo()` returns: | Address | Name | Value | -+-----------------+------+----------------+ +|-----------------|------|----------------| | 2<sup>30</sup> | | 20 | | ... | ... | ... | | 2 | j | 0 | diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 66bb84205e2..e35d81d3996 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -18,39 +18,41 @@ //! You can explicitly create a `Vec<T>` with `new()`: //! //! ``` -//! let xs: Vec<i32> = Vec::new(); +//! let v: Vec<i32> = Vec::new(); //! ``` //! //! ...or by using the `vec!` macro: //! //! ``` -//! let ys: Vec<i32> = vec![]; +//! let v: Vec<i32> = vec![]; //! -//! let zs = vec![1i32, 2, 3, 4, 5]; +//! let v = vec![1, 2, 3, 4, 5]; +//! +//! let v = vec![0; 10]; // ten zeroes //! ``` //! //! You can `push` values onto the end of a vector (which will grow the vector as needed): //! //! ``` -//! let mut xs = vec![1i32, 2]; +//! let mut v = vec![1, 2]; //! -//! xs.push(3); +//! v.push(3); //! ``` //! //! Popping values works in much the same way: //! //! ``` -//! let mut xs = vec![1i32, 2]; +//! let mut v = vec![1, 2]; //! -//! let two = xs.pop(); +//! let two = v.pop(); //! ``` //! //! Vectors also support indexing (through the `Index` and `IndexMut` traits): //! //! ``` -//! let mut xs = vec![1i32, 2, 3]; -//! let three = xs[2]; -//! xs[1] = xs[1] + 5; +//! let mut v = vec![1, 2, 3]; +//! let three = v[2]; +//! v[1] = v[1] + 5; //! ``` #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 54877c070cb..64eb75ea530 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -167,7 +167,7 @@ macro_rules! try { }) } -/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`. +/// Use the `format!` syntax to write data into a buffer of type `&mut Write`. /// See `std::fmt` for more information. /// /// # Examples diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index bb50d5110cb..e9f4860f451 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -427,8 +427,8 @@ be taken. E0271: r##" This is because of a type mismatch between the associated type of some -trait (e.g. T::Bar, where T implements trait Quux { type Bar; }) -and another type U that is required to be equal to T::Bar, but is not. +trait (e.g. `T::Bar`, where `T` implements `trait Quux { type Bar; }`) +and another type `U` that is required to be equal to `T::Bar`, but is not. Examples follow. Here is a basic example: diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 35abbc77c12..12d6fcd0303 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -30,6 +30,8 @@ #![feature(box_syntax)] #![feature(collections)] #![feature(core)] +#![feature(duration)] +#![feature(duration_span)] #![feature(fs_canonicalize)] #![feature(hash)] #![feature(into_cow)] diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 062a156637a..9a95120ee68 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -720,8 +720,7 @@ fn get_metadata_section(is_osx: bool, filename: &Path) -> Result<MetadataBlob, S let dur = Duration::span(|| { ret = Some(get_metadata_section_imp(is_osx, filename)); }); - info!("reading {:?} => {}ms", filename.file_name().unwrap(), - dur.num_milliseconds()); + info!("reading {:?} => {}", filename.file_name().unwrap(), dur); return ret.unwrap();; } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index d93d13beec8..111cf68726c 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -129,11 +129,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { .probe(v) .map(|v| v.to_type(tcx)), ty::FloatVar(v), - ty::FreshIntTy) + ty::FreshFloatTy) } ty::ty_infer(ty::FreshTy(c)) | - ty::ty_infer(ty::FreshIntTy(c)) => { + ty::ty_infer(ty::FreshIntTy(c)) | + ty::ty_infer(ty::FreshFloatTy(c)) => { if c >= self.freshen_count { tcx.sess.bug( &format!("Encountered a freshend type with id {} \ diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index cb889b76eac..8011d296263 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1773,7 +1773,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ty_err => ok_if(Vec::new()), ty::ty_infer(ty::FreshTy(_)) - | ty::ty_infer(ty::FreshIntTy(_)) => { + | ty::ty_infer(ty::FreshIntTy(_)) + | ty::ty_infer(ty::FreshFloatTy(_)) => { self.tcx().sess.bug( &format!( "asked to assemble builtin bounds of unexpected type: {}", @@ -1835,7 +1836,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ty_projection(..) | ty::ty_infer(ty::TyVar(_)) | ty::ty_infer(ty::FreshTy(_)) | - ty::ty_infer(ty::FreshIntTy(_)) => { + ty::ty_infer(ty::FreshIntTy(_)) | + ty::ty_infer(ty::FreshFloatTy(_)) => { self.tcx().sess.bug( &format!( "asked to assemble constituent types of unexpected type: {}", diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9054cd65473..e988423ac57 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1697,11 +1697,8 @@ pub enum InferTy { /// unbound type variable. This is convenient for caching etc. See /// `middle::infer::freshen` for more details. FreshTy(u32), - - // FIXME -- once integral fallback is impl'd, we should remove - // this type. It's only needed to prevent spurious errors for - // integers whose type winds up never being constrained. FreshIntTy(u32), + FreshFloatTy(u32) } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -1773,6 +1770,7 @@ impl fmt::Debug for InferTy { FloatVar(ref v) => v.fmt(f), FreshTy(v) => write!(f, "FreshTy({:?})", v), FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), + FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v) } } } @@ -3775,7 +3773,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } // Scalar and unique types are sendable, and durable - ty_infer(ty::FreshIntTy(_)) | + ty_infer(ty::FreshIntTy(_)) | ty_infer(ty::FreshFloatTy(_)) | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(..) | ty::ty_char => { TC::None @@ -4325,6 +4323,7 @@ pub fn type_is_fresh(ty: Ty) -> bool { match ty.sty { ty_infer(FreshTy(_)) => true, ty_infer(FreshIntTy(_)) => true, + ty_infer(FreshFloatTy(_)) => true, _ => false } } @@ -5026,6 +5025,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_infer(FloatVar(_)) => "floating-point variable".to_string(), ty_infer(FreshTy(_)) => "skolemized type".to_string(), ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(), + ty_infer(FreshFloatTy(_)) => "skolemized floating-point type".to_string(), ty_projection(_) => "associated type".to_string(), ty_param(ref p) => { if p.space == subst::SelfSpace { diff --git a/src/librustc/middle/ty_match.rs b/src/librustc/middle/ty_match.rs index bb00fadc39c..526ad0ec1c9 100644 --- a/src/librustc/middle/ty_match.rs +++ b/src/librustc/middle/ty_match.rs @@ -67,7 +67,8 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { match (&a.sty, &b.sty) { (_, &ty::ty_infer(ty::FreshTy(_))) | - (_, &ty::ty_infer(ty::FreshIntTy(_))) => { + (_, &ty::ty_infer(ty::FreshIntTy(_))) | + (_, &ty::ty_infer(ty::FreshFloatTy(_))) => { Ok(a) } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index d71a68e2050..5a5567c48ad 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -55,8 +55,8 @@ pub fn time<T, U, F>(do_it: bool, what: &str, u: U, f: F) -> T where }; let rv = rv.unwrap(); - println!("{}time: {}.{:03} \t{}", repeat(" ").take(old).collect::<String>(), - dur.num_seconds(), dur.num_milliseconds() % 1000, what); + println!("{}time: {} \t{}", repeat(" ").take(old).collect::<String>(), + dur, what); DEPTH.with(|slot| slot.set(old)); rv diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 32ec70c4878..cf2911ab182 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -349,7 +349,8 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx), ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"), ty::FreshTy(v) => format!("FreshTy({})", v), - ty::FreshIntTy(v) => format!("FreshIntTy({})", v) + ty::FreshIntTy(v) => format!("FreshIntTy({})", v), + ty::FreshFloatTy(v) => format!("FreshFloatTy({})", v) } } diff --git a/src/librustc_back/archive.rs b/src/librustc_back/archive.rs index 37d784692fd..cad1522ee13 100644 --- a/src/librustc_back/archive.rs +++ b/src/librustc_back/archive.rs @@ -306,6 +306,21 @@ impl<'a> ArchiveBuilder<'a> { if filename.contains(".SYMDEF") { continue } if skip(filename) { continue } + // Archives on unix systems typically do not have slashes in + // filenames as the `ar` utility generally only uses the last + // component of a path for the filename list in the archive. On + // Windows, however, archives assembled with `lib.exe` will preserve + // the full path to the file that was placed in the archive, + // including path separators. + // + // The code below is munging paths so it'll go wrong pretty quickly + // if there's some unexpected slashes in the filename, so here we + // just chop off everything but the filename component. Note that + // this can cause duplicate filenames, but that's also handled below + // as well. + let filename = Path::new(filename).file_name().unwrap() + .to_str().unwrap(); + // An archive can contain files of the same name multiple times, so // we need to be sure to not have them overwrite one another when we // extract them. Consequently we need to find a truly unique file diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 7e7af800680..15ddcbc8074 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -20,6 +20,7 @@ Imports (`use` statements) are not allowed after non-item statements, such as variable declarations and expression statements. Here is an example that demonstrates the error: + ``` fn f() { // Variable declaration before import @@ -33,6 +34,7 @@ The solution is to declare the imports at the top of the block, function, or file. Here is the previous example again, with the correct order: + ``` fn f() { use std::io::Read; @@ -47,11 +49,94 @@ about what constitutes an Item declaration and what does not: http://doc.rust-lang.org/reference.html#statements "##, +E0251: r##" +Two items of the same name cannot be imported without rebinding one of the +items under a new local name. + +An example of this error: + +``` +use foo::baz; +use bar::*; // error, do `use foo::baz as quux` instead on the previous line + +fn main() {} + +mod foo { + pub struct baz; +} + +mod bar { + pub mod baz {} +} +``` +"##, + +E0252: r##" +Two items of the same name cannot be imported without rebinding one of the +items under a new local name. + +An example of this error: + +``` +use foo::baz; +use bar::baz; // error, do `use bar::baz as quux` instead + +fn main() {} + +mod foo { + pub struct baz; +} + +mod bar { + pub mod baz {} +} +``` +"##, + +E0255: r##" +You can't import a value whose name is the same as another value defined in the +module. + +An example of this error: + +``` +use bar::foo; // error, do `use bar::foo as baz` instead + +fn foo() {} + +mod bar { + pub fn foo() {} +} + +fn main() {} +``` +"##, + +E0256: r##" +You can't import a type or module when the name of the item being imported is +the same as another type or submodule defined in the module. + +An example of this error: + +``` +use foo::Bar; // error + +type Bar = u32; + +mod foo { + pub mod Bar { } +} + +fn main() {} +``` +"##, + E0259: r##" The name chosen for an external crate conflicts with another external crate that has been imported into the current module. Wrong example: + ``` extern crate a; extern crate crate_a as a; @@ -61,6 +146,7 @@ The solution is to choose a different name that doesn't conflict with any external crate imported into the current module. Correct example: + ``` extern crate a; extern crate crate_a as other_name; @@ -71,6 +157,7 @@ E0260: r##" The name for an item declaration conflicts with an external crate's name. For instance, + ``` extern crate abc; @@ -117,14 +204,10 @@ http://doc.rust-lang.org/reference.html#types register_diagnostics! { E0157, E0153, - E0251, // a named type or value has already been imported in this module - E0252, // a named type or value has already been imported in this module E0253, // not directly importable E0254, // import conflicts with imported crate in this module - E0255, // import conflicts with value in this module - E0256, // import conflicts with type in this module - E0257, // inherent implementations are only allowed on types defined in the current module - E0258, // import conflicts with existing submodule + E0257, + E0258, E0364, // item is private E0365 // item is private } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 447230ada22..38ab0a8c5ed 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2528,8 +2528,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If anything ends up here entirely resolved, // it's an error. If anything ends up here // partially resolved, that's OK, because it may - // be a `T::CONST` that typeck will resolve to - // an inherent impl. + // be a `T::CONST` that typeck will resolve. if path_res.depth == 0 { self.resolve_error( path.span, @@ -2537,6 +2536,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { token::get_ident( path.segments.last().unwrap().identifier))); } else { + let const_name = path.segments.last().unwrap() + .identifier.name; + let traits = self.get_traits_containing_item(const_name); + self.trait_map.insert(pattern.id, traits); self.record_def(pattern.id, path_res); } } diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index d80086da203..89cda6d785f 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -520,12 +520,12 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id)); // If the variable is immutable, save the initialising expression. - let value = match mt { - ast::MutMutable => String::from_str("<mutable>"), - ast::MutImmutable => self.span.snippet(expr.span), + let (value, keyword) = match mt { + ast::MutMutable => (String::from_str("<mutable>"), keywords::Mut), + ast::MutImmutable => (self.span.snippet(expr.span), keywords::Static), }; - let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Static); + let sub_span = self.span.sub_span_after_keyword(item.span, keyword); self.fmt.static_str(item.span, sub_span, item.id, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index fb2ad444005..90df0b853a0 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -16,12 +16,10 @@ use middle::def; use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod}; use middle::subst; use middle::traits; -use middle::ty::*; -use middle::ty; +use middle::ty::{self, AsPredicate, ToPolyTraitRef}; use middle::infer; use util::ppaux::Repr; -use std::rc::Rc; use syntax::ast::DefId; use syntax::ast; use syntax::codemap::Span; @@ -39,7 +37,7 @@ pub enum MethodError { // Did not find an applicable method, but we did find various // static methods that may apply, as well as a list of // not-in-scope traits which may work. - NoMatch(Vec<CandidateSource>, Vec<ast::DefId>), + NoMatch(Vec<CandidateSource>, Vec<ast::DefId>, probe::Mode), // Multiple methods might apply. Ambiguity(Vec<CandidateSource>), @@ -62,7 +60,7 @@ type ItemIndex = usize; // just for doc purposes pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, method_name: ast::Name, - self_ty: Ty<'tcx>, + self_ty: ty::Ty<'tcx>, call_expr_id: ast::NodeId) -> bool { @@ -92,11 +90,11 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, method_name: ast::Name, - self_ty: Ty<'tcx>, - supplied_method_types: Vec<Ty<'tcx>>, + self_ty: ty::Ty<'tcx>, + supplied_method_types: Vec<ty::Ty<'tcx>>, call_expr: &'tcx ast::Expr, self_expr: &'tcx ast::Expr) - -> Result<MethodCallee<'tcx>, MethodError> + -> Result<ty::MethodCallee<'tcx>, MethodError> { debug!("lookup(method_name={}, self_ty={}, call_expr={}, self_expr={})", method_name.repr(fcx.tcx()), @@ -115,9 +113,9 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, self_expr: Option<&ast::Expr>, m_name: ast::Name, trait_def_id: DefId, - self_ty: Ty<'tcx>, - opt_input_types: Option<Vec<Ty<'tcx>>>) - -> Option<MethodCallee<'tcx>> + self_ty: ty::Ty<'tcx>, + opt_input_types: Option<Vec<ty::Ty<'tcx>>>) + -> Option<ty::MethodCallee<'tcx>> { lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id, 0, false, self_ty, opt_input_types) @@ -139,9 +137,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, trait_def_id: DefId, autoderefs: usize, unsize: bool, - self_ty: Ty<'tcx>, - opt_input_types: Option<Vec<Ty<'tcx>>>) - -> Option<MethodCallee<'tcx>> + self_ty: ty::Ty<'tcx>, + opt_input_types: Option<Vec<ty::Ty<'tcx>>>) + -> Option<ty::MethodCallee<'tcx>> { debug!("lookup_in_trait_adjusted(self_ty={}, self_expr={}, m_name={}, trait_def_id={})", self_ty.repr(fcx.tcx()), @@ -186,7 +184,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = fcx.tcx(); - let (method_num, method_ty) = trait_method(tcx, trait_def_id, m_name).unwrap(); + let (method_num, method_ty) = trait_item(tcx, trait_def_id, m_name) + .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m))) + .unwrap(); assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0); assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0); @@ -288,10 +288,10 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - let callee = MethodCallee { - origin: MethodTypeParam(MethodParam{trait_ref: trait_ref.clone(), - method_num: method_num, - impl_def_id: None}), + let callee = ty::MethodCallee { + origin: ty::MethodTypeParam(ty::MethodParam{trait_ref: trait_ref.clone(), + method_num: method_num, + impl_def_id: None}), ty: fty, substs: trait_ref.substs.clone() }; @@ -304,7 +304,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, method_name: ast::Name, - self_ty: Ty<'tcx>, + self_ty: ty::Ty<'tcx>, expr_id: ast::NodeId) -> Result<(def::Def, LastPrivate), MethodError> { @@ -322,9 +322,9 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, _ => def::FromTrait(pick.item.container().id()) }; let def_result = match pick.item { - ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance), - ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance), - ImplOrTraitItem::TypeTraitItem(..) => { + ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance), + ty::ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance), + ty::ImplOrTraitItem::TypeTraitItem(..) => { fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type"); } }; @@ -332,31 +332,30 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } -/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its -/// index (or `None`, if no such method). -fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_def_id: ast::DefId, - method_name: ast::Name) - -> Option<(usize, Rc<ty::Method<'tcx>>)> +/// Find item with name `item_name` defined in `trait_def_id` and return it, along with its +/// index (or `None`, if no such item). +fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_def_id: ast::DefId, + item_name: ast::Name) + -> Option<(usize, ty::ImplOrTraitItem<'tcx>)> { let trait_items = ty::trait_items(tcx, trait_def_id); trait_items .iter() .enumerate() - .find(|&(_, ref item)| item.name() == method_name) - .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m))) + .find(|&(_, ref item)| item.name() == item_name) + .map(|(num, item)| (num, (*item).clone())) } -fn impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, - impl_def_id: ast::DefId, - method_name: ast::Name) - -> Option<Rc<ty::Method<'tcx>>> +fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>, + impl_def_id: ast::DefId, + item_name: ast::Name) + -> Option<ty::ImplOrTraitItem<'tcx>> { let impl_items = tcx.impl_items.borrow(); let impl_items = impl_items.get(&impl_def_id).unwrap(); impl_items .iter() .map(|&did| ty::impl_or_trait_item(tcx, did.def_id())) - .find(|m| m.name() == method_name) - .and_then(|item| item.as_opt_method()) + .find(|m| m.name() == item_name) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 6171df218bb..2eca855d596 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -136,7 +136,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let steps = if mode == Mode::MethodCall { match create_steps(fcx, span, self_ty) { Some(steps) => steps, - None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())), + None => return Err(MethodError::NoMatch(Vec::new(), Vec::new(), mode)), } } else { vec![CandidateStep { @@ -866,7 +866,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } } }).collect(), - Some(Err(MethodError::NoMatch(_, others))) => { + Some(Err(MethodError::NoMatch(_, others, _))) => { assert!(others.is_empty()); vec![] } @@ -877,7 +877,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { None => vec![], }; - Err(MethodError::NoMatch(static_candidates, out_of_scope_traits)) + Err(MethodError::NoMatch(static_candidates, out_of_scope_traits, self.mode)) } fn pick_core(&mut self) -> Option<PickResult<'tcx>> { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 17658675ee2..93239df60e1 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Give useful errors and suggestions to users when a method can't be +//! Give useful errors and suggestions to users when an item can't be //! found or is otherwise invalid. use CrateCtxt; @@ -27,12 +27,13 @@ use syntax::print::pprust; use std::cell; use std::cmp::Ordering; -use super::{MethodError, CandidateSource, impl_method, trait_method}; +use super::{MethodError, CandidateSource, impl_item, trait_item}; +use super::probe::Mode; pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, rcvr_ty: Ty<'tcx>, - method_name: ast::Name, + item_name: ast::Name, rcvr_expr: Option<&ast::Expr>, error: MethodError) { @@ -42,28 +43,30 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } match error { - MethodError::NoMatch(static_sources, out_of_scope_traits) => { + MethodError::NoMatch(static_sources, out_of_scope_traits, mode) => { let cx = fcx.tcx(); - let method_ustring = method_name.user_string(cx); + let item_ustring = item_name.user_string(cx); fcx.type_error_message( span, |actual| { - format!("type `{}` does not implement any \ - method in scope named `{}`", - actual, - method_ustring) + format!("no {} named `{}` found for type `{}` \ + in the current scope", + if mode == Mode::MethodCall { "method" } + else { "associated item" }, + item_ustring, + actual) }, rcvr_ty, None); - // If the method has the name of a field, give a help note + // If the item has the name of a field, give a help note if let (&ty::ty_struct(did, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) { let fields = ty::lookup_struct_fields(cx, did); - if fields.iter().any(|f| f.name == method_name) { + if fields.iter().any(|f| f.name == item_name) { cx.sess.span_note(span, &format!("use `(s.{0})(...)` if you meant to call the \ - function stored in the `{0}` field", method_ustring)); + function stored in the `{0}` field", item_ustring)); } } @@ -72,25 +75,25 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span, "found defined static methods, maybe a `self` is missing?"); - report_candidates(fcx, span, method_name, static_sources); + report_candidates(fcx, span, item_name, static_sources); } - suggest_traits_to_import(fcx, span, rcvr_ty, method_name, + suggest_traits_to_import(fcx, span, rcvr_ty, item_name, rcvr_expr, out_of_scope_traits) } MethodError::Ambiguity(sources) => { span_err!(fcx.sess(), span, E0034, - "multiple applicable methods in scope"); + "multiple applicable items in scope"); - report_candidates(fcx, span, method_name, sources); + report_candidates(fcx, span, item_name, sources); } MethodError::ClosureAmbiguity(trait_def_id) => { let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \ invoked on this closure as we have not yet inferred what \ kind of closure it is", - method_name.user_string(fcx.tcx()), + item_name.user_string(fcx.tcx()), ty::item_path_str(fcx.tcx(), trait_def_id)); let msg = if let Some(callee) = rcvr_expr { format!("{}; use overloaded call notation instead (e.g., `{}()`)", @@ -104,7 +107,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn report_candidates(fcx: &FnCtxt, span: Span, - method_name: ast::Name, + item_name: ast::Name, mut sources: Vec<CandidateSource>) { sources.sort(); sources.dedup(); @@ -112,11 +115,11 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, for (idx, source) in sources.iter().enumerate() { match *source { CandidateSource::ImplSource(impl_did) => { - // Provide the best span we can. Use the method, if local to crate, else - // the impl, if local to crate (method may be defaulted), else the call site. - let method = impl_method(fcx.tcx(), impl_did, method_name).unwrap(); + // Provide the best span we can. Use the item, if local to crate, else + // the impl, if local to crate (item may be defaulted), else the call site. + let item = impl_item(fcx.tcx(), impl_did, item_name).unwrap(); let impl_span = fcx.tcx().map.def_id_span(impl_did, span); - let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span); + let item_span = fcx.tcx().map.def_id_span(item.def_id(), impl_span); let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty; @@ -127,16 +130,16 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, trait_ref.def_id)), }; - span_note!(fcx.sess(), method_span, + span_note!(fcx.sess(), item_span, "candidate #{} is defined in an impl{} for the type `{}`", idx + 1, insertion, impl_ty.user_string(fcx.tcx())); } CandidateSource::TraitSource(trait_did) => { - let (_, method) = trait_method(fcx.tcx(), trait_did, method_name).unwrap(); - let method_span = fcx.tcx().map.def_id_span(method.def_id, span); - span_note!(fcx.sess(), method_span, + let (_, item) = trait_item(fcx.tcx(), trait_did, item_name).unwrap(); + let item_span = fcx.tcx().map.def_id_span(item.def_id(), span); + span_note!(fcx.sess(), item_span, "candidate #{} is defined in the trait `{}`", idx + 1, ty::item_path_str(fcx.tcx(), trait_did)); @@ -152,19 +155,19 @@ pub type AllTraitsVec = Vec<TraitInfo>; fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, rcvr_ty: Ty<'tcx>, - method_name: ast::Name, + item_name: ast::Name, rcvr_expr: Option<&ast::Expr>, valid_out_of_scope_traits: Vec<ast::DefId>) { let tcx = fcx.tcx(); - let method_ustring = method_name.user_string(tcx); + let item_ustring = item_name.user_string(tcx); if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; candidates.sort(); candidates.dedup(); let msg = format!( - "methods from traits can only be called if the trait is in scope; \ + "items from traits can only be used if the trait is in scope; \ the following {traits_are} implemented but not in scope, \ perhaps add a `use` for {one_of_them}:", traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, @@ -185,7 +188,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty, rcvr_expr); // there's no implemented traits, so lets suggest some traits to - // implement, by finding ones that have the method name, and are + // implement, by finding ones that have the item name, and are // legal to implement. let mut candidates = all_traits(fcx.ccx) .filter(|info| { @@ -196,7 +199,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // implementing a trait would be legal but is rejected // here). (type_is_local || ast_util::is_local(info.def_id)) - && trait_method(tcx, info.def_id, method_name).is_some() + && trait_item(tcx, info.def_id, item_name).is_some() }) .collect::<Vec<_>>(); @@ -209,12 +212,12 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // of a type parameter: suggest adding a trait bound rather // than implementing. let msg = format!( - "methods from traits can only be called if the trait is implemented and in scope; \ - the following {traits_define} a method `{name}`, \ + "items from traits can only be used if the trait is implemented and in scope; \ + the following {traits_define} an item `{name}`, \ perhaps you need to implement {one_of_them}:", traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"}, one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, - name = method_ustring); + name = item_ustring); fcx.sess().fileline_help(span, &msg[..]); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 554f3d4b5a0..3cdbaec1528 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3082,8 +3082,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let mut checked = false; opt_place.as_ref().map(|place| match place.node { ast::ExprPath(None, ref path) => { - // FIXME(pcwalton): For now we hardcode the two permissible - // places: the exchange heap and the managed heap. + // FIXME(pcwalton): For now we hardcode the only permissible + // place: the exchange heap. let definition = lookup_full_def(tcx, path.span, place.id); let def_id = definition.def_id(); let referent_ty = fcx.expr_ty(&**subexpr); @@ -3097,7 +3097,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, if !checked { span_err!(tcx.sess, expr.span, E0066, - "only the managed heap and exchange heap are currently supported"); + "only the exchange heap is currently supported"); fcx.write_ty(id, tcx.types.err); } } @@ -3317,7 +3317,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, if let Err(_) = fcx.mk_eqty(false, infer::Misc(expr.span), result_type, ty::mk_nil(fcx.tcx())) { span_err!(tcx.sess, expr.span, E0069, - "`return;` in function returning non-nil"); + "`return;` in a function whose return type is \ + not `()`"); }, Some(ref e) => { check_expr_coercable_to_type(fcx, &**e, result_type); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7ec1299e7eb..10d23c36c80 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -19,6 +19,88 @@ methods that do not have default implementations), as well as any required trait items like associated types or constants. "##, +E0049: r##" +This error indicates that an attempted implementation of a trait method +has the wrong number of type parameters. + +For example, the trait below has a method `foo` with a type parameter `T`, +but the implementation of `foo` for the type `Bar` is missing this parameter: + +``` +trait Foo { + fn foo<T: Default>(x: T) -> Self; +} + +struct Bar; + +// error: method `foo` has 0 type parameters but its trait declaration has 1 +// type parameter +impl Foo for Bar { + fn foo(x: bool) -> Self { Bar } +} +``` +"##, + +E0050: r##" +This error indicates that an attempted implementation of a trait method +has the wrong number of function parameters. + +For example, the trait below has a method `foo` with two function parameters +(`&self` and `u8`), but the implementation of `foo` for the type `Bar` omits +the `u8` parameter: + +``` +trait Foo { + fn foo(&self, x: u8) -> bool; +} + +struct Bar; + +// error: method `foo` has 1 parameter but the declaration in trait `Foo::foo` +// has 2 +impl Foo for Bar { + fn foo(&self) -> bool { true } +} +``` +"##, + +E0053: r##" +For any given method of a trait, the mutabilities of the parameters must match +between the trait definition and the implementation. + +Here's an example where the mutability of the `self` parameter is wrong: + +``` +trait Foo { fn foo(&self); } + +struct Bar; + +impl Foo for Bar { + // error, the signature should be `fn foo(&self)` instead + fn foo(&mut self) { } +} + +fn main() {} +``` + +Here's another example, this time for a non-`self` parameter: + +``` +trait Foo { fn foo(x: &mut bool) -> bool; } + +struct Bar; + +impl Foo for Bar { + // error, the type of `x` should be `&mut bool` instead + fn foo(x: &bool) -> bool { *x } +} + +fn main() {} +``` + + +"##, + E0054: r##" It is not allowed to cast to a bool. If you are trying to cast a numeric type to a bool, you can compare it with zero instead: @@ -46,6 +128,16 @@ enum variant, one of the fields was not provided. Each field should be specified exactly once. "##, +E0066: r##" +Box placement expressions (like C++'s "placement new") do not yet support any +place expression except the exchange heap (i.e. `std::boxed::HEAP`). +Furthermore, the syntax is changing to use `in` instead of `box`. See [RFC 470] +and [RFC 809] for more details. + +[RFC 470]: https://github.com/rust-lang/rfcs/pull/470 +[RFC 809]: https://github.com/rust-lang/rfcs/pull/809 +"##, + E0067: r##" The left-hand side of an assignment operator must be an lvalue expression. An lvalue expression represents a memory location and includes item paths (ie, @@ -63,6 +155,21 @@ LinkedList::new() += 1; ``` "##, +E0069: r##" +The compiler found a function whose body contains a `return;` statement but +whose return type is not `()`. An example of this is: + +``` +// error +fn foo() -> u8 { + return; +} +``` + +Since `return;` is just like `return ();`, there is a mismatch between the +function's return type and the value being returned. +"##, + E0081: r##" Enum discriminants are used to differentiate enum variants stored in memory. This error indicates that the same value was used for two or more variants, @@ -138,6 +245,88 @@ enum Empty {} ``` "##, +E0106: r##" +This error indicates that a lifetime is missing from a type. If it is an error +inside a function signature, the problem may be with failing to adhere to the +lifetime elision rules (see below). + +Here are some simple examples of where you'll run into this error: + +``` +struct Foo { x: &bool } // error +struct Foo<'a> { x: &'a bool } // correct + +enum Bar { A(u8), B(&bool), } // error +enum Bar<'a> { A(u8), B(&'a bool), } // correct + +type MyStr = &str; // error +type MyStr<'a> = &'a str; //correct + +``` + +Lifetime elision is a special, limited kind of inference for lifetimes in +function signatures which allows you to leave out lifetimes in certain cases. +For more background on lifetime elision see [the book][book-le]. + +The lifetime elision rules require that any function signature with an elided +output lifetime must either have + + - exactly one input lifetime + - or, multiple input lifetimes, but the function must also be a method with a + `&self` or `&mut self` receiver + +In the first case, the output lifetime is inferred to be the same as the unique +input lifetime. In the second case, the lifetime is instead inferred to be the +same as the lifetime on `&self` or `&mut self`. + +Here are some examples of elision errors: + +``` +// error, no input lifetimes +fn foo() -> &str { ... } + +// error, `x` and `y` have distinct lifetimes inferred +fn bar(x: &str, y: &str) -> &str { ... } + +// error, `y`'s lifetime is inferred to be distinct from `x`'s +fn baz<'a>(x: &'a str, y: &str) -> &str { ... } +``` + +[book-le]: http://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision +"##, + +E0107: r##" +This error means that an incorrect number of lifetime parameters were provided +for a type (like a struct or enum) or trait. + +Some basic examples include: + +``` +struct Foo<'a>(&'a str); +enum Bar { A, B, C } + +struct Baz<'a> { + foo: Foo, // error: expected 1, found 0 + bar: Bar<'a>, // error: expected 0, found 1 +} +``` + +Here's an example that is currently an error, but may work in a future version +of Rust: + +``` +struct Foo<'a>(&'a str); + +trait Quux { } +impl Quux for Foo { } // error: expected 1, found 0 +``` + +Lifetime elision in implementation headers was part of the lifetime elision +RFC. It is, however, [currently unimplemented][iss15872]. + +[iss15872]: https://github.com/rust-lang/rust/issues/15872 +"##, + E0131: r##" It is not possible to define `main` with type parameters, or even with function parameters. When `main` is present, it must take no arguments and return `()`. @@ -152,6 +341,20 @@ fn(isize, *const *const u8) -> isize ``` "##, +E0166: r##" +This error means that the compiler found a return expression in a function +marked as diverging. A function diverges if it has `!` in the place of the +return type in its signature. For example: + +``` +fn foo() -> ! { return; } // error +``` + +For a function that diverges, every control path in the function must never +return, for example with a `loop` that never breaks or a call to another +diverging function (such as `panic!()`). +"##, + E0184: r##" Explicitly implementing both Drop and Copy for a type is currently disallowed. This feature can make some sense in theory, but the current implementation is @@ -167,12 +370,14 @@ methods associated with a type) are always safe because they are not implementing an unsafe trait. Removing the unsafe keyword from the inherent implementation will resolve this error. +``` struct Foo; // this will cause this error unsafe impl Foo { } // converting it to this will fix it impl Foo { } +``` "##, @@ -182,12 +387,14 @@ particular trait. Not being able to use a trait is always a safe operation, so negative implementations are always safe and never need to be marked as unsafe. +``` struct Foo; // unsafe is unnecessary unsafe impl !Clone for Foo { } // this will compile impl !Clone for Foo { } +``` "##, @@ -196,6 +403,7 @@ Safe traits should not have unsafe implementations, therefore marking an implementation for a safe trait unsafe will cause a compiler error. Removing the unsafe marker on the trait noted in the error will resolve this problem. +``` struct Foo; trait Bar { } @@ -204,6 +412,7 @@ trait Bar { } unsafe impl Bar for Foo { } // this will compile impl Bar for Foo { } +``` "##, @@ -212,6 +421,7 @@ Unsafe traits must have unsafe implementations. This error occurs when an implementation for an unsafe trait isn't marked as unsafe. This may be resolved by marking the unsafe implementation as unsafe. +``` struct Foo; unsafe trait Bar { } @@ -220,9 +430,28 @@ unsafe trait Bar { } impl Bar for Foo { } // this will compile unsafe impl Bar for Foo { } +``` "##, +E0201: r##" +It is an error to define a method--a trait method or an inherent method--more +than once. + +For example, + +``` +struct Foo(u8); + +impl Foo { + fn bar() {} + + // error: duplicate method + fn bar(&self) -> bool { self.0 > 5 } +} +``` +"##, + E0204: r##" An attempt to implement the `Copy` trait for a struct failed because one of the fields does not implement `Copy`. To fix this, you must implement `Copy` for the @@ -354,6 +583,55 @@ const B: [u32; foo()] = []; use std::{f64, u8}; const C: [u32; u8::MAX + f64::EPSILON] = []; ``` +"##, + +E0322: r##" +The `Sized` trait is a special trait built-in to the compiler for types with a +constant size known at compile-time. This trait is automatically implemented +for types as needed by the compiler, and it is currently disallowed to +explicitly implement it for a type. +"##, + +E0368: r##" +This error indicates that a binary assignment operator like `+=` or `^=` was +applied to the wrong types. + +A couple examples of this are as follows: + +``` +let mut x: u16 = 5; +x ^= true; // error, `^=` cannot be applied to types `u16` and `bool` +x += (); // error, `+=` cannot be applied to types `u16` and `()` +``` + +Another problem you might be facing is this: suppose you've overloaded the `+` +operator for some type `Foo` by implementing the `std::ops::Add` trait for +`Foo`, but you find that using `+=` does not work, as in this example: + +``` +use std::ops::Add; + +struct Foo(u32); + +impl Add for Foo { + type Output = Foo; + + fn add(self, rhs: Foo) -> Foo { + Foo(self.0 + rhs.0) + } +} + +fn main() { + let mut x: Foo = Foo(5); + x += Foo(7); // error, `+= cannot be applied to types `Foo` and `Foo` +} +``` + +This is because the binary assignment operators currently do not work off of +traits, so it is not possible to overload them. See [RFC 953] for a proposal +to change this. + +[RFC 953]: https://github.com/rust-lang/rfcs/pull/953 "## } @@ -374,17 +652,12 @@ register_diagnostics! { E0040, // explicit use of destructor method E0044, // foreign items may not have type parameters E0045, // variadic function must have C calling convention - E0049, - E0050, - E0053, E0055, // method has an incompatible type for trait E0057, // method has an incompatible type for trait E0059, E0060, E0061, - E0066, E0068, - E0069, E0070, E0071, E0072, @@ -407,8 +680,6 @@ register_diagnostics! { E0102, E0103, E0104, - E0106, - E0107, E0116, E0117, E0118, @@ -426,7 +697,6 @@ register_diagnostics! { E0159, E0163, E0164, - E0166, E0167, E0168, E0172, @@ -448,7 +718,6 @@ register_diagnostics! { E0194, E0195, // lifetime parameters or bounds on method do not match the trait declaration E0196, // cannot determine a type for this closure - E0201, // duplicate method in trait impl E0202, // associated items are not allowed in inherent impls E0203, // type parameter has more than one relaxed default bound, // and only one is supported @@ -479,7 +748,7 @@ register_diagnostics! { E0231, // only named substitution parameters are allowed E0232, // this attribute must have a value E0233, - E0234, // `for` loop expression has type which does not implement the `Iterator` trait + E0234, E0235, // structure constructor specifies a structure of type but E0236, // no lang item for range syntax E0237, // no lang item for range syntax @@ -496,7 +765,6 @@ register_diagnostics! { E0319, // trait impls for defaulted traits allowed just for structs/enums E0320, // recursive overflow during dropck E0321, // extended coherence rules for defaulted traits violated - E0322, // cannot implement Sized explicitly E0323, // implemented an associated const when another trait item expected E0324, // implemented a method when another trait item expected E0325, // implemented an associated type when another trait item expected @@ -505,7 +773,6 @@ register_diagnostics! { E0328, // cannot implement Unsize explicitly E0366, // dropck forbid specialization to concrete type or region E0367, // dropck forbid specialization to predicate not in struct/enum - E0368, // binary operation `<op>=` cannot be applied to types E0369, // binary operation `<op>` cannot be applied to types E0371, // impl Trait for Trait is illegal E0372, // impl Trait for Trait where Trait is not object safe diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 82999a47e56..126ef38b918 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -243,6 +243,17 @@ impl Error for VarError { /// Sets the environment variable `k` to the value `v` for the currently running /// process. /// +/// Note that while concurrent access to environment variables is safe in Rust, +/// some platforms only expose inherently unsafe non-threadsafe APIs for +/// inspecting the environment. As a result extra care needs to be taken when +/// auditing calls to unsafe external FFI functions to ensure that any external +/// environment accesses are properly synchronized with accesses in Rust. +/// +/// Discussion of this unsafety on Unix may be found in: +/// +/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) +/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) +/// /// # Examples /// /// ``` @@ -260,6 +271,17 @@ pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(k: K, v: V) { /// Removes an environment variable from the environment of the currently running process. /// +/// Note that while concurrent access to environment variables is safe in Rust, +/// some platforms only expose inherently unsafe non-threadsafe APIs for +/// inspecting the environment. As a result extra care needs to be taken when +/// auditing calls to unsafe external FFI functions to ensure that any external +/// environment accesses are properly synchronized with accesses in Rust. +/// +/// Discussion of this unsafety on Unix may be found in: +/// +/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) +/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) +/// /// # Examples /// /// ``` diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c0d8d8eacf7..220a0ba5755 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -28,7 +28,7 @@ //! //! The standard library is minimal, a set of battle-tested //! core types and shared abstractions for the [broader Rust -//! ecosystem][https://crates.io] to build on. +//! ecosystem](https://crates.io) to build on. //! //! The [primitive types](#primitives), though not defined in the //! standard library, are documented here, as are the predefined diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index c2964b7a4f1..8da917916e5 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -69,12 +69,12 @@ pub struct Condvar { inner: Box<StaticCondvar> } /// # Examples /// /// ``` -/// # #![feature(std_misc)] +/// # #![feature(static_condvar)] /// use std::sync::{StaticCondvar, CONDVAR_INIT}; /// /// static CVAR: StaticCondvar = CONDVAR_INIT; /// ``` -#[unstable(feature = "std_misc", +#[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future")] pub struct StaticCondvar { inner: sys::Condvar, @@ -82,7 +82,7 @@ pub struct StaticCondvar { } /// Constant initializer for a statically allocated condition variable. -#[unstable(feature = "std_misc", +#[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future")] pub const CONDVAR_INIT: StaticCondvar = StaticCondvar { inner: sys::CONDVAR_INIT, @@ -164,6 +164,30 @@ impl Condvar { /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// + /// The semantics of this function are equivalent to `wait()` except that + /// the thread will be blocked for roughly no longer than `dur`. This + /// method should not be used for precise timing due to anomalies such as + /// preemption or platform differences that may not cause the maximum + /// amount of time waited to be precisely `dur`. + /// + /// The returned boolean is `false` only if the timeout is known + /// to have elapsed. + /// + /// Like `wait`, the lock specified will be re-acquired when this function + /// returns, regardless of whether the timeout elapsed or not. + #[unstable(feature = "wait_timeout", reason = "waiting for Duration")] + pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, + dur: Duration) + -> LockResult<(MutexGuard<'a, T>, bool)> { + unsafe { + let me: &'static Condvar = &*(self as *const _); + me.inner.wait_timeout(guard, dur) + } + } + + /// Waits on this condition variable for a notification, timing out after a + /// specified duration. + /// /// The semantics of this function are equivalent to `wait_timeout` except /// that the implementation will repeatedly wait while the duration has not /// passed and the provided function returns `false`. @@ -214,7 +238,7 @@ impl StaticCondvar { /// notification. /// /// See `Condvar::wait`. - #[unstable(feature = "std_misc", + #[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future")] pub fn wait<'a, T>(&'static self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> { @@ -235,14 +259,27 @@ impl StaticCondvar { /// specified duration. /// /// See `Condvar::wait_timeout`. - #[unstable(feature = "std_misc", + #[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future")] pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32) -> LockResult<(MutexGuard<'a, T>, bool)> { + self.wait_timeout(guard, Duration::from_millis(ms as u64)) + } + + /// Waits on this condition variable for a notification, timing out after a + /// specified duration. + /// + /// See `Condvar::wait_timeout`. + #[unstable(feature = "static_condvar", + reason = "may be merged with Condvar in the future")] + pub fn wait_timeout<'a, T>(&'static self, + guard: MutexGuard<'a, T>, + timeout: Duration) + -> LockResult<(MutexGuard<'a, T>, bool)> { let (poisoned, success) = unsafe { let lock = mutex::guard_lock(&guard); self.verify(lock); - let success = self.inner.wait_timeout(lock, Duration::milliseconds(ms as i64)); + let success = self.inner.wait_timeout(lock, timeout); (mutex::guard_poison(&guard).get(), success) }; if poisoned { @@ -259,7 +296,7 @@ impl StaticCondvar { /// passed and the function returns `false`. /// /// See `Condvar::wait_timeout_with`. - #[unstable(feature = "std_misc", + #[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future")] pub fn wait_timeout_with<'a, T, F>(&'static self, guard: MutexGuard<'a, T>, @@ -267,7 +304,8 @@ impl StaticCondvar { mut f: F) -> LockResult<(MutexGuard<'a, T>, bool)> where F: FnMut(LockResult<&mut T>) -> bool { - // This could be made more efficient by pushing the implementation into sys::condvar + // This could be made more efficient by pushing the implementation into + // sys::condvar let start = SteadyTime::now(); let mut guard_result: LockResult<MutexGuard<'a, T>> = Ok(guard); while !f(guard_result @@ -277,12 +315,15 @@ impl StaticCondvar { let now = SteadyTime::now(); let consumed = &now - &start; let guard = guard_result.unwrap_or_else(|e| e.into_inner()); - let res = self.wait_timeout_ms(guard, (dur - consumed).num_milliseconds() as u32); - let (new_guard_result, no_timeout) = match res { - Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout), - Err(err) => { - let (new_guard, no_timeout) = err.into_inner(); - (Err(PoisonError::new(new_guard)), no_timeout) + let (new_guard_result, no_timeout) = if consumed > dur { + (Ok(guard), false) + } else { + match self.wait_timeout(guard, dur - consumed) { + Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout), + Err(err) => { + let (new_guard, no_timeout) = err.into_inner(); + (Err(PoisonError::new(new_guard)), no_timeout) + } } }; guard_result = new_guard_result; @@ -301,14 +342,14 @@ impl StaticCondvar { /// Wakes up one blocked thread on this condvar. /// /// See `Condvar::notify_one`. - #[unstable(feature = "std_misc", + #[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future")] pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } } /// Wakes up all blocked threads on this condvar. /// /// See `Condvar::notify_all`. - #[unstable(feature = "std_misc", + #[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future")] pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } } @@ -318,7 +359,7 @@ impl StaticCondvar { /// active users of the condvar, and this also doesn't prevent any future /// users of the condvar. This method is required to be called to not leak /// memory on all platforms. - #[unstable(feature = "std_misc", + #[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future")] pub unsafe fn destroy(&'static self) { self.inner.destroy() @@ -447,7 +488,9 @@ mod tests { static S: AtomicUsize = ATOMIC_USIZE_INIT; let g = M.lock().unwrap(); - let (g, success) = C.wait_timeout_with(g, Duration::nanoseconds(1000), |_| false).unwrap(); + let (g, success) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| { + false + }).unwrap(); assert!(!success); let (tx, rx) = channel(); @@ -471,7 +514,8 @@ mod tests { }); let mut state = 0; - let (_g, success) = C.wait_timeout_with(g, Duration::days(1), |_| { + let day = 24 * 60 * 60; + let (_g, success) = C.wait_timeout_with(g, Duration::new(day, 0), |_| { assert_eq!(state, S.load(Ordering::SeqCst)); tx.send(()).unwrap(); state += 1; diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index ed6382e000a..29a13cc6be7 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -57,25 +57,20 @@ impl Condvar { // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - if dur <= Duration::zero() { - return false; - } - - // First, figure out what time it currently is, in both system and stable time. - // pthread_cond_timedwait uses system time, but we want to report timeout based on stable - // time. + // First, figure out what time it currently is, in both system and + // stable time. pthread_cond_timedwait uses system time, but we want to + // report timeout based on stable time. let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 }; let stable_now = time::SteadyTime::now(); let r = ffi::gettimeofday(&mut sys_now, ptr::null_mut()); debug_assert_eq!(r, 0); - let seconds = dur.num_seconds() as libc::time_t; + let seconds = dur.secs() as libc::time_t; let timeout = match sys_now.tv_sec.checked_add(seconds) { Some(sec) => { libc::timespec { tv_sec: sec, - tv_nsec: (dur - Duration::seconds(dur.num_seconds())) - .num_nanoseconds().unwrap() as libc::c_long, + tv_nsec: dur.extra_nanos() as libc::c_long, } } None => { @@ -87,11 +82,12 @@ impl Condvar { }; // And wait! - let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), &timeout); + let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), + &timeout); debug_assert!(r == libc::ETIMEDOUT || r == 0); - // ETIMEDOUT is not a totally reliable method of determining timeout due to clock shifts, - // so do the check ourselves + // ETIMEDOUT is not a totally reliable method of determining timeout due + // to clock shifts, so do the check ourselves &time::SteadyTime::now() - &stable_now < dur } diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index cfab9d1c51a..0cb5a06e6b6 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -129,14 +129,9 @@ impl Thread { } pub fn sleep(dur: Duration) { - if dur < Duration::zero() { - return Thread::yield_now() - } - let seconds = dur.num_seconds(); - let ns = dur - Duration::seconds(seconds); let mut ts = libc::timespec { - tv_sec: seconds as libc::time_t, - tv_nsec: ns.num_nanoseconds().unwrap() as libc::c_long, + tv_sec: dur.secs() as libc::time_t, + tv_nsec: dur.extra_nanos() as libc::c_long, }; // If we're awoken with a signal then the return value will be -1 and diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index f59eb2c0301..16dfd3eebd0 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -10,12 +10,15 @@ pub use self::inner::SteadyTime; +const NSEC_PER_SEC: u64 = 1_000_000_000; + #[cfg(any(target_os = "macos", target_os = "ios"))] mod inner { use libc; use time::Duration; use ops::Sub; use sync::{Once, ONCE_INIT}; + use super::NSEC_PER_SEC; pub struct SteadyTime { t: u64 @@ -32,11 +35,6 @@ mod inner { t: unsafe { mach_absolute_time() }, } } - - pub fn ns(&self) -> u64 { - let info = info(); - self.t * info.numer as u64 / info.denom as u64 - } } fn info() -> &'static libc::mach_timebase_info { @@ -59,8 +57,9 @@ mod inner { fn sub(self, other: &SteadyTime) -> Duration { let info = info(); - let diff = self.t as i64 - other.t as i64; - Duration::nanoseconds(diff * info.numer as i64 / info.denom as i64) + let diff = self.t as u64 - other.t as u64; + let nanos = diff * info.numer as u64 / info.denom as u64; + Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32) } } } @@ -70,8 +69,7 @@ mod inner { use libc; use time::Duration; use ops::Sub; - - const NSEC_PER_SEC: i64 = 1_000_000_000; + use super::NSEC_PER_SEC; pub struct SteadyTime { t: libc::timespec, @@ -104,10 +102,6 @@ mod inner { } t } - - pub fn ns(&self) -> u64 { - self.t.tv_sec as u64 * NSEC_PER_SEC as u64 + self.t.tv_nsec as u64 - } } impl<'a> Sub for &'a SteadyTime { @@ -115,12 +109,12 @@ mod inner { fn sub(self, other: &SteadyTime) -> Duration { if self.t.tv_nsec >= other.t.tv_nsec { - Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) + - Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64) + Duration::new(self.t.tv_sec as u64 - other.t.tv_sec as u64, + self.t.tv_nsec as u32 - other.t.tv_nsec as u32) } else { - Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) + - Duration::nanoseconds(self.t.tv_nsec as i64 + NSEC_PER_SEC - - other.t.tv_nsec as i64) + Duration::new(self.t.tv_sec as u64 - 1 - other.t.tv_sec as u64, + self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - + other.t.tv_nsec as u32) } } } diff --git a/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs index 67552255fdb..8bb2326e4d6 100644 --- a/src/libstd/sys/windows/condvar.rs +++ b/src/libstd/sys/windows/condvar.rs @@ -42,7 +42,7 @@ impl Condvar { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { let r = ffi::SleepConditionVariableSRW(self.inner.get(), mutex::raw(mutex), - dur.num_milliseconds() as DWORD, + super::dur2timeout(dur), 0); if r == 0 { const ERROR_TIMEOUT: DWORD = 0x5B4; diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 4c30f0f8660..6b7bff2c1c6 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -20,6 +20,7 @@ use libc; use num::Zero; use os::windows::ffi::{OsStrExt, OsStringExt}; use path::PathBuf; +use time::Duration; pub mod backtrace; pub mod c; @@ -151,6 +152,27 @@ fn cvt<I: PartialEq + Zero>(i: I) -> io::Result<I> { } } +fn dur2timeout(dur: Duration) -> libc::DWORD { + // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the + // timeouts in windows APIs are typically u32 milliseconds. To translate, we + // have two pieces to take care of: + // + // * Nanosecond precision is rounded up + // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE + // (never time out). + dur.secs().checked_mul(1000).and_then(|ms| { + ms.checked_add((dur.extra_nanos() as u64) / 1_000_000) + }).and_then(|ms| { + ms.checked_add(if dur.extra_nanos() % 1_000_000 > 0 {1} else {0}) + }).map(|ms| { + if ms > <libc::DWORD>::max_value() as u64 { + libc::INFINITE + } else { + ms as libc::DWORD + } + }).unwrap_or(libc::INFINITE) +} + fn ms_to_filetime(ms: u64) -> libc::FILETIME { // A FILETIME is a count of 100 nanosecond intervals, so we multiply by // 10000 b/c there are 10000 intervals in 1 ms diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 797f45f8702..50dfee4ab10 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -80,15 +80,7 @@ impl Thread { pub fn sleep(dur: Duration) { unsafe { - if dur < Duration::zero() { - return Thread::yield_now() - } - let ms = dur.num_milliseconds(); - // if we have a fractional number of milliseconds then add an extra - // millisecond to sleep for - let extra = dur - Duration::milliseconds(ms); - let ms = ms + if extra.is_zero() {0} else {1}; - c::Sleep(ms as DWORD); + c::Sleep(super::dur2timeout(dur)) } } } diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 209460df10b..e64df54a0fa 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -12,7 +12,7 @@ use ops::Sub; use time::Duration; use sync::{Once, ONCE_INIT}; -const NANOS_PER_SEC: i64 = 1_000_000_000; +const NANOS_PER_SEC: u64 = 1_000_000_000; pub struct SteadyTime { t: libc::LARGE_INTEGER, @@ -24,10 +24,6 @@ impl SteadyTime { unsafe { libc::QueryPerformanceCounter(&mut t.t); } t } - - pub fn ns(&self) -> u64 { - mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64 - } } fn frequency() -> libc::LARGE_INTEGER { @@ -46,15 +42,16 @@ impl<'a> Sub for &'a SteadyTime { type Output = Duration; fn sub(self, other: &SteadyTime) -> Duration { - let diff = self.t as i64 - other.t as i64; - Duration::nanoseconds(mul_div_i64(diff, NANOS_PER_SEC, frequency() as i64)) + let diff = self.t as u64 - other.t as u64; + let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64); + Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32) } } // Computes (value*numer)/denom without overflow, as long as both // (numer*denom) and the overall result fit into i64 (which is the case // for our time conversions). -fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { +fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 { let q = value / denom; let r = value % denom; // Decompose value as (value/denom*denom + value%denom), @@ -65,9 +62,6 @@ fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { #[test] fn test_muldiv() { - assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); - assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), -1_000_000_000_001_000); - assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 1_000_000_000_001_000); - assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), -1_000_000_000_001_000); - assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 1_000_000_000_001_000); + assert_eq!(mul_div_u64( 1_000_000_000_001, 1_000_000_000, 1_000_000), + 1_000_000_000_001_000); } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index f480147b93e..7c8cb5b01c1 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -482,7 +482,23 @@ pub fn catch_panic<F, R>(f: F) -> Result<R> /// spurious wakeup. #[stable(feature = "rust1", since = "1.0.0")] pub fn sleep_ms(ms: u32) { - imp::Thread::sleep(Duration::milliseconds(ms as i64)) + sleep(Duration::from_millis(ms as u64)) +} + +/// Puts the current thread to sleep for the specified amount of time. +/// +/// The thread may sleep longer than the duration specified due to scheduling +/// specifics or platform-dependent functionality. +/// +/// # Platform behavior +/// +/// On Unix platforms this function will not return early due to a +/// signal being received or a spurious wakeup. Platforms which do not support +/// nanosecond precision for sleeping will have `dur` rounded up to the nearest +/// granularity of time they can sleep for. +#[unstable(feature = "thread_sleep", reason = "waiting on Duration")] +pub fn sleep(dur: Duration) { + imp::Thread::sleep(dur) } /// Blocks unless or until the current thread's token is made available (may wake spuriously). @@ -508,18 +524,38 @@ pub fn park() { /// the specified duration has been reached (may wake spuriously). /// /// The semantics of this function are equivalent to `park()` except that the -/// thread will be blocked for roughly no longer than *duration*. This method +/// thread will be blocked for roughly no longer than *ms*. This method /// should not be used for precise timing due to anomalies such as /// preemption or platform differences that may not cause the maximum -/// amount of time waited to be precisely *duration* long. +/// amount of time waited to be precisely *ms* long. /// /// See the module doc for more detail. #[stable(feature = "rust1", since = "1.0.0")] pub fn park_timeout_ms(ms: u32) { + park_timeout(Duration::from_millis(ms as u64)) +} + +/// Blocks unless or until the current thread's token is made available or +/// the specified duration has been reached (may wake spuriously). +/// +/// The semantics of this function are equivalent to `park()` except that the +/// thread will be blocked for roughly no longer than *dur*. This method +/// should not be used for precise timing due to anomalies such as +/// preemption or platform differences that may not cause the maximum +/// amount of time waited to be precisely *dur* long. +/// +/// See the module doc for more detail. +/// +/// # Platform behavior +/// +/// Platforms which do not support nanosecond precision for sleeping will have +/// `dur` rounded up to the nearest granularity of time they can sleep for. +#[unstable(feature = "park_timeout", reason = "waiting on Duration")] +pub fn park_timeout(dur: Duration) { let thread = current(); let mut guard = thread.inner.lock.lock().unwrap(); if !*guard { - let (g, _) = thread.inner.cvar.wait_timeout_ms(guard, ms).unwrap(); + let (g, _) = thread.inner.cvar.wait_timeout(guard, dur).unwrap(); guard = g; } *guard = false; diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 636a0dd697a..8001df29d1f 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -10,589 +10,265 @@ //! Temporal quantification -#![unstable(feature = "std_misc")] +#![unstable(feature = "duration", reason = "recently added API per RFC 1040")] use prelude::v1::*; -use {fmt, i64}; -use ops::{Add, Sub, Mul, Div, Neg}; - -/// The number of nanoseconds in a microsecond. -const NANOS_PER_MICRO: i32 = 1000; -/// The number of nanoseconds in a millisecond. -const NANOS_PER_MILLI: i32 = 1000_000; -/// The number of nanoseconds in seconds. -const NANOS_PER_SEC: i32 = 1_000_000_000; -/// The number of microseconds per second. -const MICROS_PER_SEC: i64 = 1000_000; -/// The number of milliseconds per second. -const MILLIS_PER_SEC: i64 = 1000; -/// The number of seconds in a minute. -const SECS_PER_MINUTE: i64 = 60; -/// The number of seconds in an hour. -const SECS_PER_HOUR: i64 = 3600; -/// The number of (non-leap) seconds in days. -const SECS_PER_DAY: i64 = 86400; -/// The number of (non-leap) seconds in a week. -const SECS_PER_WEEK: i64 = 604800; - -macro_rules! try_opt { - ($e:expr) => (match $e { Some(v) => v, None => return None }) -} - - -/// ISO 8601 time duration with nanosecond precision. -/// This also allows for the negative duration; see individual methods for details. -#[unstable(feature = "std_misc")] +use fmt; +use ops::{Add, Sub, Mul, Div}; +use sys::time::SteadyTime; + +const NANOS_PER_SEC: u32 = 1_000_000_000; +const NANOS_PER_MILLI: u32 = 1_000_000; +const MILLIS_PER_SEC: u64 = 1_000; + +/// A duration type to represent a span of time, typically used for system +/// timeouts. +/// +/// Each duration is composed of a number of seconds and nanosecond precision. +/// APIs binding a system timeout will typically round up the nanosecond +/// precision if the underlying system does not support that level of precision. +/// +/// Durations implement many common traits, including `Add`, `Sub`, and other +/// ops traits. Currently a duration may only be inspected for its number of +/// seconds and its nanosecond precision. +/// +/// # Examples +/// +/// ``` +/// #![feature(duration)] +/// use std::time::Duration; +/// +/// let five_seconds = Duration::new(5, 0); +/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5); +/// +/// assert_eq!(five_seconds_and_five_nanos.secs(), 5); +/// assert_eq!(five_seconds_and_five_nanos.extra_nanos(), 5); +/// +/// let ten_millis = Duration::from_millis(10); +/// ``` #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct Duration { - secs: i64, - nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC + secs: u64, + nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC } -/// The minimum possible `Duration`: `i64::MIN` milliseconds. -#[unstable(feature = "std_misc")] -pub const MIN: Duration = Duration { - secs: i64::MIN / MILLIS_PER_SEC - 1, - nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI -}; - -/// The maximum possible `Duration`: `i64::MAX` milliseconds. -#[unstable(feature = "std_misc")] -pub const MAX: Duration = Duration { - secs: i64::MAX / MILLIS_PER_SEC, - nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI -}; - impl Duration { - /// Makes a new `Duration` with given number of weeks. - /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn weeks(weeks: i64) -> Duration { - let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of days. - /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn days(days: i64) -> Duration { - let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of hours. - /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn hours(hours: i64) -> Duration { - let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of minutes. - /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn minutes(minutes: i64) -> Duration { - let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of seconds. - /// Panics when the duration is more than `i64::MAX` milliseconds - /// or less than `i64::MIN` milliseconds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn seconds(seconds: i64) -> Duration { - let d = Duration { secs: seconds, nanos: 0 }; - if d < MIN || d > MAX { - panic!("Duration::seconds out of bounds"); - } - d - } - - /// Makes a new `Duration` with given number of milliseconds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn milliseconds(milliseconds: i64) -> Duration { - let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC); - let nanos = millis as i32 * NANOS_PER_MILLI; + /// Crates a new `Duration` from the specified number of seconds and + /// additional nanosecond precision. + /// + /// If the nanoseconds is greater than 1 billion (the number of nanoseconds + /// in a second), then it will carry over into the seconds provided. + pub fn new(secs: u64, nanos: u32) -> Duration { + let secs = secs + (nanos / NANOS_PER_SEC) as u64; + let nanos = nanos % NANOS_PER_SEC; Duration { secs: secs, nanos: nanos } } - /// Makes a new `Duration` with given number of microseconds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn microseconds(microseconds: i64) -> Duration { - let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - let nanos = micros as i32 * NANOS_PER_MICRO; - Duration { secs: secs, nanos: nanos } - } - - /// Makes a new `Duration` with given number of nanoseconds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn nanoseconds(nanos: i64) -> Duration { - let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64); - Duration { secs: secs, nanos: nanos as i32 } - } - /// Runs a closure, returning the duration of time it took to run the /// closure. - #[unstable(feature = "std_misc")] + #[unstable(feature = "duration_span", + reason = "unsure if this is the right API or whether it should \ + wait for a more general \"moment in time\" \ + abstraction")] pub fn span<F>(f: F) -> Duration where F: FnOnce() { - let before = super::precise_time_ns(); + let start = SteadyTime::now(); f(); - Duration::nanoseconds((super::precise_time_ns() - before) as i64) - } - - /// Returns the total number of whole weeks in the duration. - #[inline] - #[unstable(feature = "std_misc")] - pub fn num_weeks(&self) -> i64 { - self.num_days() / 7 - } - - /// Returns the total number of whole days in the duration. - #[unstable(feature = "std_misc")] - pub fn num_days(&self) -> i64 { - self.num_seconds() / SECS_PER_DAY - } - - /// Returns the total number of whole hours in the duration. - #[inline] - #[unstable(feature = "std_misc")] - pub fn num_hours(&self) -> i64 { - self.num_seconds() / SECS_PER_HOUR - } - - /// Returns the total number of whole minutes in the duration. - #[inline] - #[unstable(feature = "std_misc")] - pub fn num_minutes(&self) -> i64 { - self.num_seconds() / SECS_PER_MINUTE - } - - /// Returns the total number of whole seconds in the duration. - #[unstable(feature = "std_misc")] - pub fn num_seconds(&self) -> i64 { - // If secs is negative, nanos should be subtracted from the duration. - if self.secs < 0 && self.nanos > 0 { - self.secs + 1 - } else { - self.secs - } - } - - /// Returns the number of nanoseconds such that - /// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of - /// nanoseconds in the duration. - fn nanos_mod_sec(&self) -> i32 { - if self.secs < 0 && self.nanos > 0 { - self.nanos - NANOS_PER_SEC - } else { - self.nanos - } - } - - /// Returns the total number of whole milliseconds in the duration, - #[unstable(feature = "std_misc")] - pub fn num_milliseconds(&self) -> i64 { - // A proper Duration will not overflow, because MIN and MAX are defined - // such that the range is exactly i64 milliseconds. - let secs_part = self.num_seconds() * MILLIS_PER_SEC; - let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI; - secs_part + nanos_part as i64 - } - - /// Returns the total number of whole microseconds in the duration, - /// or `None` on overflow (exceeding 2^63 microseconds in either direction). - #[unstable(feature = "std_misc")] - pub fn num_microseconds(&self) -> Option<i64> { - let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC)); - let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO; - secs_part.checked_add(nanos_part as i64) + &SteadyTime::now() - &start } - /// Returns the total number of whole nanoseconds in the duration, - /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction). - #[unstable(feature = "std_misc")] - pub fn num_nanoseconds(&self) -> Option<i64> { - let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64)); - let nanos_part = self.nanos_mod_sec(); - secs_part.checked_add(nanos_part as i64) + /// Creates a new `Duration` from the specified number of seconds. + pub fn from_secs(secs: u64) -> Duration { + Duration { secs: secs, nanos: 0 } } - /// Add two durations, returning `None` if overflow occurred. - #[unstable(feature = "std_misc")] - pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> { - let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs = try_opt!(secs.checked_add(1)); - } - let d = Duration { secs: secs, nanos: nanos }; - // Even if d is within the bounds of i64 seconds, - // it might still overflow i64 milliseconds. - if d < MIN || d > MAX { None } else { Some(d) } - } - - /// Subtract two durations, returning `None` if overflow occurred. - #[unstable(feature = "std_misc")] - pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> { - let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); - let mut nanos = self.nanos - rhs.nanos; - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs = try_opt!(secs.checked_sub(1)); - } - let d = Duration { secs: secs, nanos: nanos }; - // Even if d is within the bounds of i64 seconds, - // it might still overflow i64 milliseconds. - if d < MIN || d > MAX { None } else { Some(d) } - } - - /// The minimum possible `Duration`: `i64::MIN` milliseconds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn min_value() -> Duration { MIN } - - /// The maximum possible `Duration`: `i64::MAX` milliseconds. - #[inline] - #[unstable(feature = "std_misc")] - pub fn max_value() -> Duration { MAX } - - /// A duration where the stored seconds and nanoseconds are equal to zero. - #[inline] - #[unstable(feature = "std_misc")] - pub fn zero() -> Duration { - Duration { secs: 0, nanos: 0 } - } - - /// Returns `true` if the duration equals `Duration::zero()`. - #[inline] - #[unstable(feature = "std_misc")] - pub fn is_zero(&self) -> bool { - self.secs == 0 && self.nanos == 0 + /// Creates a new `Duration` from the specified number of milliseconds. + pub fn from_millis(millis: u64) -> Duration { + let secs = millis / MILLIS_PER_SEC; + let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI; + Duration { secs: secs, nanos: nanos } } -} -#[unstable(feature = "std_misc")] -impl Neg for Duration { - type Output = Duration; + /// Returns the number of whole seconds represented by this duration. + /// + /// The extra precision represented by this duration is ignored (e.g. extra + /// nanoseconds are not represented in the returned value). + pub fn secs(&self) -> u64 { self.secs } - #[inline] - fn neg(self) -> Duration { - if self.nanos == 0 { - Duration { secs: -self.secs, nanos: 0 } - } else { - Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos } - } - } + /// Returns the nanosecond precision represented by this duration. + /// + /// This method does **not** return the length of the duration when + /// represented by nanoseconds. The returned number always represents a + /// fractional portion of a second (e.g. it is less than one billion). + pub fn extra_nanos(&self) -> u32 { self.nanos } } -#[unstable(feature = "std_misc")] impl Add for Duration { type Output = Duration; fn add(self, rhs: Duration) -> Duration { - let mut secs = self.secs + rhs.secs; + let mut secs = self.secs.checked_add(rhs.secs) + .expect("overflow when adding durations"); let mut nanos = self.nanos + rhs.nanos; if nanos >= NANOS_PER_SEC { nanos -= NANOS_PER_SEC; - secs += 1; + secs = secs.checked_add(1).expect("overflow when adding durations"); } + debug_assert!(nanos < NANOS_PER_SEC); Duration { secs: secs, nanos: nanos } } } -#[unstable(feature = "std_misc")] impl Sub for Duration { type Output = Duration; fn sub(self, rhs: Duration) -> Duration { - let mut secs = self.secs - rhs.secs; - let mut nanos = self.nanos - rhs.nanos; - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs -= 1; - } + let mut secs = self.secs.checked_sub(rhs.secs) + .expect("overflow when subtracting durations"); + let nanos = if self.nanos >= rhs.nanos { + self.nanos - rhs.nanos + } else { + secs = secs.checked_sub(1) + .expect("overflow when subtracting durations"); + self.nanos + NANOS_PER_SEC - rhs.nanos + }; + debug_assert!(nanos < NANOS_PER_SEC); Duration { secs: secs, nanos: nanos } } } -#[unstable(feature = "std_misc")] -impl Mul<i32> for Duration { +impl Mul<u32> for Duration { type Output = Duration; - fn mul(self, rhs: i32) -> Duration { - // Multiply nanoseconds as i64, because it cannot overflow that way. - let total_nanos = self.nanos as i64 * rhs as i64; - let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64); - let secs = self.secs * rhs as i64 + extra_secs; - Duration { secs: secs, nanos: nanos as i32 } + fn mul(self, rhs: u32) -> Duration { + // Multiply nanoseconds as u64, because it cannot overflow that way. + let total_nanos = self.nanos as u64 * rhs as u64; + let extra_secs = total_nanos / (NANOS_PER_SEC as u64); + let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; + let secs = self.secs.checked_mul(rhs as u64) + .and_then(|s| s.checked_add(extra_secs)) + .expect("overflow when multiplying duration"); + debug_assert!(nanos < NANOS_PER_SEC); + Duration { secs: secs, nanos: nanos } } } -#[unstable(feature = "std_misc")] -impl Div<i32> for Duration { +impl Div<u32> for Duration { type Output = Duration; - fn div(self, rhs: i32) -> Duration { - let mut secs = self.secs / rhs as i64; - let carry = self.secs - secs * rhs as i64; - let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64; - let mut nanos = self.nanos / rhs + extra_nanos as i32; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs += 1; - } - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs -= 1; - } + fn div(self, rhs: u32) -> Duration { + let secs = self.secs / (rhs as u64); + let carry = self.secs - secs * (rhs as u64); + let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); + let nanos = self.nanos / rhs + (extra_nanos as u32); + debug_assert!(nanos < NANOS_PER_SEC); Duration { secs: secs, nanos: nanos } } } -#[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Duration { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // technically speaking, negative duration is not valid ISO 8601, - // but we need to print it anyway. - let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") }; - - let days = abs.secs / SECS_PER_DAY; - let secs = abs.secs - days * SECS_PER_DAY; - let hasdate = days != 0; - let hastime = (secs != 0 || abs.nanos != 0) || !hasdate; - - try!(write!(f, "{}P", sign)); - - if hasdate { - try!(write!(f, "{}D", days)); - } - if hastime { - if abs.nanos == 0 { - try!(write!(f, "T{}S", secs)); - } else if abs.nanos % NANOS_PER_MILLI == 0 { - try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI)); - } else if abs.nanos % NANOS_PER_MICRO == 0 { - try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO)); - } else { - try!(write!(f, "T{}.{:09}S", secs, abs.nanos)); - } + match (self.secs, self.nanos) { + (s, 0) => write!(f, "{}s", s), + (0, n) if n % NANOS_PER_MILLI == 0 => write!(f, "{}ms", + n / NANOS_PER_MILLI), + (0, n) if n % 1_000 == 0 => write!(f, "{}µs", n / 1_000), + (0, n) => write!(f, "{}ns", n), + (s, n) => write!(f, "{}.{}s", s, + format!("{:09}", n).trim_right_matches('0')) } - Ok(()) - } -} - -// Copied from libnum -#[inline] -fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { - (div_floor_64(this, other), mod_floor_64(this, other)) -} - -#[inline] -fn div_floor_64(this: i64, other: i64) -> i64 { - match div_rem_64(this, other) { - (d, r) if (r > 0 && other < 0) - || (r < 0 && other > 0) => d - 1, - (d, _) => d, - } -} - -#[inline] -fn mod_floor_64(this: i64, other: i64) -> i64 { - match this % other { - r if (r > 0 && other < 0) - || (r < 0 && other > 0) => r + other, - r => r, } } -#[inline] -fn div_rem_64(this: i64, other: i64) -> (i64, i64) { - (this / other, this % other) -} - #[cfg(test)] mod tests { - use super::{Duration, MIN, MAX}; - use {i32, i64}; - use option::Option::{Some, None}; - use string::ToString; + use prelude::v1::*; + use super::Duration; #[test] - fn test_duration() { - assert!(Duration::seconds(1) != Duration::zero()); - assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3)); - assert_eq!(Duration::seconds(86399) + Duration::seconds(4), - Duration::days(1) + Duration::seconds(3)); - assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000)); - assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000)); - assert_eq!(Duration::days(2) + Duration::seconds(86399) + - Duration::nanoseconds(1234567890), - Duration::days(3) + Duration::nanoseconds(234567890)); - assert_eq!(-Duration::days(3), Duration::days(-3)); - assert_eq!(-(Duration::days(3) + Duration::seconds(70)), - Duration::days(-4) + Duration::seconds(86400-70)); + fn creation() { + assert!(Duration::from_secs(1) != Duration::from_secs(0)); + assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), + Duration::from_secs(3)); + assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), + Duration::new(4, 10 * 1_000_000)); + assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); } #[test] - fn test_duration_num_days() { - assert_eq!(Duration::zero().num_days(), 0); - assert_eq!(Duration::days(1).num_days(), 1); - assert_eq!(Duration::days(-1).num_days(), -1); - assert_eq!(Duration::seconds(86399).num_days(), 0); - assert_eq!(Duration::seconds(86401).num_days(), 1); - assert_eq!(Duration::seconds(-86399).num_days(), 0); - assert_eq!(Duration::seconds(-86401).num_days(), -1); - assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64); - assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64); + fn secs() { + assert_eq!(Duration::new(0, 0).secs(), 0); + assert_eq!(Duration::from_secs(1).secs(), 1); + assert_eq!(Duration::from_millis(999).secs(), 0); + assert_eq!(Duration::from_millis(1001).secs(), 1); } #[test] - fn test_duration_num_seconds() { - assert_eq!(Duration::zero().num_seconds(), 0); - assert_eq!(Duration::seconds(1).num_seconds(), 1); - assert_eq!(Duration::seconds(-1).num_seconds(), -1); - assert_eq!(Duration::milliseconds(999).num_seconds(), 0); - assert_eq!(Duration::milliseconds(1001).num_seconds(), 1); - assert_eq!(Duration::milliseconds(-999).num_seconds(), 0); - assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1); + fn nanos() { + assert_eq!(Duration::new(0, 0).extra_nanos(), 0); + assert_eq!(Duration::new(0, 5).extra_nanos(), 5); + assert_eq!(Duration::new(0, 1_000_000_001).extra_nanos(), 1); + assert_eq!(Duration::from_secs(1).extra_nanos(), 0); + assert_eq!(Duration::from_millis(999).extra_nanos(), 999 * 1_000_000); + assert_eq!(Duration::from_millis(1001).extra_nanos(), 1 * 1_000_000); } #[test] - fn test_duration_num_milliseconds() { - assert_eq!(Duration::zero().num_milliseconds(), 0); - assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1); - assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1); - assert_eq!(Duration::microseconds(999).num_milliseconds(), 0); - assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1); - assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0); - assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1); - assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX); - assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN); - assert_eq!(MAX.num_milliseconds(), i64::MAX); - assert_eq!(MIN.num_milliseconds(), i64::MIN); + fn add() { + assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), + Duration::new(1, 1)); } #[test] - fn test_duration_num_microseconds() { - assert_eq!(Duration::zero().num_microseconds(), Some(0)); - assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1)); - assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1)); - assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1)); - assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1)); - assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX)); - assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN)); - assert_eq!(MAX.num_microseconds(), None); - assert_eq!(MIN.num_microseconds(), None); - - // overflow checks - const MICROS_PER_DAY: i64 = 86400_000_000; - assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(), - Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)); - assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(), - Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY)); - assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); - assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None); + fn sub() { + assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), + Duration::new(0, 1)); + assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), + Duration::new(0, 999_999_999)); } - #[test] - fn test_duration_num_nanoseconds() { - assert_eq!(Duration::zero().num_nanoseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1)); - assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1)); - assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX)); - assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN)); - assert_eq!(MAX.num_nanoseconds(), None); - assert_eq!(MIN.num_nanoseconds(), None); - - // overflow checks - const NANOS_PER_DAY: i64 = 86400_000_000_000; - assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(), - Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)); - assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(), - Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY)); - assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); - assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None); + #[test] #[should_panic] + fn sub_bad1() { + Duration::new(0, 0) - Duration::new(0, 1); } - #[test] - fn test_duration_checked_ops() { - assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)), - Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999))); - assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000)) - .is_none()); - - assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)), - Some(Duration::milliseconds(i64::MIN))); - assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1)) - .is_none()); + #[test] #[should_panic] + fn sub_bad2() { + Duration::new(0, 0) - Duration::new(1, 0); } #[test] - fn test_duration_mul() { - assert_eq!(Duration::zero() * i32::MAX, Duration::zero()); - assert_eq!(Duration::zero() * i32::MIN, Duration::zero()); - assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero()); - assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1)); - assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1)); - assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1)); - assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1)); - assert_eq!(Duration::nanoseconds(30) * 333_333_333, - Duration::seconds(10) - Duration::nanoseconds(10)); - assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3, - Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3)); - assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3)); - assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3)); + fn mul() { + assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001) * 4000, + Duration::new(2000, 4000)); } #[test] - fn test_duration_div() { - assert_eq!(Duration::zero() / i32::MAX, Duration::zero()); - assert_eq!(Duration::zero() / i32::MIN, Duration::zero()); - assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789)); - assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789)); - assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789)); - assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789)); - assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333)); - assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333)); - assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500)); - assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500)); - assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500)); - assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333)); - assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333)); + fn div() { + assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); + assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); + assert_eq!(Duration::new(99, 999_999_000) / 100, + Duration::new(0, 999_999_990)); } #[test] - fn test_duration_fmt() { - assert_eq!(Duration::zero().to_string(), "PT0S"); - assert_eq!(Duration::days(42).to_string(), "P42D"); - assert_eq!(Duration::days(-42).to_string(), "-P42D"); - assert_eq!(Duration::seconds(42).to_string(), "PT42S"); - assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S"); - assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S"); - assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S"); - assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(), - "P7DT6.543S"); - assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S"); - assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S"); - - // the format specifier should have no effect on `Duration` - assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)), - "P1DT2.345S"); + fn display() { + assert_eq!(Duration::new(0, 2).to_string(), "2ns"); + assert_eq!(Duration::new(0, 2_000_000).to_string(), "2ms"); + assert_eq!(Duration::new(2, 0).to_string(), "2s"); + assert_eq!(Duration::new(2, 2).to_string(), "2.000000002s"); + assert_eq!(Duration::new(2, 2_000_000).to_string(), + "2.002s"); + assert_eq!(Duration::new(0, 2_000_002).to_string(), + "2000002ns"); + assert_eq!(Duration::new(2, 2_000_002).to_string(), + "2.002000002s"); } } diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs index 4d9bb8050d3..d535b195519 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time/mod.rs @@ -10,17 +10,8 @@ //! Temporal quantification. -#![unstable(feature = "std_misc")] - -use sys::time::SteadyTime; +#![unstable(feature = "time")] pub use self::duration::Duration; -pub mod duration; - -/// Returns the current value of a high-resolution performance counter -/// in nanoseconds since an unspecified epoch. -// NB: this is intentionally not public, this is not ready to stabilize its api. -fn precise_time_ns() -> u64 { - SteadyTime::now().ns() -} +mod duration; diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 348bf6f51bb..c692babfacc 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -235,7 +235,9 @@ pub enum MacroFormat { /// e.g. #[derive(...)] <item> MacroAttribute, /// e.g. `format!()` - MacroBang + MacroBang, + /// Expansion performed by the compiler (libsyntax::expand). + CompilerExpansion, } #[derive(Clone, Hash, Debug)] diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index aa649b4d99a..0097bab2fea 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -506,7 +506,7 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) { Some(_) => { try!(print_diagnostic(dst, &ss[..], Help, - &format!("pass `--explain {}` to see a detailed \ + &format!("run `rustc --explain {}` to see a detailed \ explanation", code), None)); } None => () @@ -770,12 +770,15 @@ fn print_macro_backtrace(w: &mut EmitterWriter, |span| cm.span_to_string(span)); let (pre, post) = match ei.callee.format { codemap::MacroAttribute => ("#[", "]"), - codemap::MacroBang => ("", "!") + codemap::MacroBang => ("", "!"), + codemap::CompilerExpansion => ("", ""), }; try!(print_diagnostic(w, &ss, Note, - &format!("in expansion of {}{}{}", pre, - ei.callee.name, - post), None)); + &format!("in expansion of {}{}{}", + pre, + ei.callee.name, + post), + None)); let ss = cm.span_to_string(ei.call_site); try!(print_diagnostic(w, &ss, Note, "expansion site", None)); Ok(Some(ei.call_site)) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d71557bd737..fae0b56ce3d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -19,7 +19,7 @@ use ext::build::AstBuilder; use attr; use attr::AttrMetaMethods; use codemap; -use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; +use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, CompilerExpansion}; use ext::base::*; use feature_gate::{self, Features}; use fold; @@ -34,6 +34,18 @@ use visit::Visitor; use std_inject; pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { + fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc: &str) { + fld.cx.bt_push(ExpnInfo { + call_site: span, + callee: NameAndSpan { + name: expansion_desc.to_string(), + format: CompilerExpansion, + allow_internal_unstable: true, + span: None, + }, + }); + } + e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. @@ -77,6 +89,8 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { // } // } + push_compiler_expansion(fld, span, "while let expansion"); + // `<pat> => <body>` let pat_arm = { let body_expr = fld.cx.expr_block(body); @@ -98,7 +112,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { // `[opt_ident]: loop { ... }` let loop_block = fld.cx.block_expr(match_expr); let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); - fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)) + let result = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)); + fld.cx.bt_pop(); + result } // Desugar ExprIfLet @@ -112,6 +128,8 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { // _ => [<elseopt> | ()] // } + push_compiler_expansion(fld, span, "if let expansion"); + // `<pat> => <body>` let pat_arm = { let body_expr = fld.cx.expr_block(body); @@ -173,13 +191,16 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { ast::MatchSource::IfLetDesugar { contains_else_clause: contains_else_clause, })); - fld.fold_expr(match_expr) + let result = fld.fold_expr(match_expr); + fld.cx.bt_pop(); + result } // Desugar support for ExprIfLet in the ExprIf else position ast::ExprIf(cond, blk, elseopt) => { let elseopt = elseopt.map(|els| els.and_then(|els| match els.node { ast::ExprIfLet(..) => { + push_compiler_expansion(fld, span, "if let expansion"); // wrap the if-let expr in a block let span = els.span; let blk = P(ast::Block { @@ -189,7 +210,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { rules: ast::DefaultBlock, span: span }); - fld.cx.expr_block(blk) + let result = fld.cx.expr_block(blk); + fld.cx.bt_pop(); + result } _ => P(els) })); @@ -221,6 +244,10 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { // result // } + push_compiler_expansion(fld, span, "for loop expansion"); + + let span = fld.new_span(span); + // expand <head> let head = fld.fold_expr(head); @@ -235,10 +262,11 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { rename_fld.fold_ident(ident) }; - let pat_span = pat.span; - // `:;std::option::Option::Some(<pat>) => <body>` + let pat_span = fld.new_span(pat.span); + // `::std::option::Option::Some(<pat>) => <body>` let pat_arm = { let body_expr = fld.cx.expr_block(body); + let pat = noop_fold_pat(pat, fld); let some_pat = fld.cx.pat_some(pat_span, pat); fld.cx.arm(pat_span, vec![some_pat], body_expr) @@ -304,20 +332,25 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { // `{ let result = ...; result }` let result_ident = token::gensym_ident("result"); - fld.cx.expr_block( + let result = fld.cx.expr_block( fld.cx.block_all( span, vec![fld.cx.stmt_let(span, false, result_ident, match_expr)], - Some(fld.cx.expr_ident(span, result_ident)))) + Some(fld.cx.expr_ident(span, result_ident)))); + fld.cx.bt_pop(); + result } ast::ExprClosure(capture_clause, fn_decl, block) => { + push_compiler_expansion(fld, span, "closure expansion"); let (rewritten_fn_decl, rewritten_block) = expand_and_rename_fn_decl_and_block(fn_decl, block, fld); let new_node = ast::ExprClosure(capture_clause, rewritten_fn_decl, rewritten_block); - P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)}) + let result = P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)}); + fld.cx.bt_pop(); + result } _ => { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 00ef8760985..b1615486153 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -43,6 +43,8 @@ #![feature(std_misc)] #![feature(libc)] #![feature(set_stdio)] +#![feature(duration)] +#![feature(duration_span)] extern crate getopts; extern crate serialize; @@ -1069,7 +1071,7 @@ impl Bencher { } pub fn ns_elapsed(&mut self) -> u64 { - self.dur.num_nanoseconds().unwrap() as u64 + self.dur.secs() * 1_000_000_000 + (self.dur.extra_nanos() as u64) } pub fn ns_per_iter(&mut self) -> u64 { @@ -1105,7 +1107,7 @@ impl Bencher { // (i.e. larger error bars). if n == 0 { n = 1; } - let mut total_run = Duration::nanoseconds(0); + let mut total_run = Duration::new(0, 0); let samples : &mut [f64] = &mut [0.0_f64; 50]; loop { let mut summ = None; @@ -1134,7 +1136,7 @@ impl Bencher { // If we've run for 100ms and seem to have converged to a // stable median. - if loop_run.num_milliseconds() > 100 && + if loop_run > Duration::from_millis(100) && summ.median_abs_dev_pct < 1.0 && summ.median - summ5.median < summ5.median_abs_dev { return summ5; @@ -1142,7 +1144,7 @@ impl Bencher { total_run = total_run + loop_run; // Longest we ever run for is 3s. - if total_run.num_seconds() > 3 { + if total_run > Duration::from_secs(3) { return summ5; } @@ -1166,7 +1168,7 @@ pub mod bench { pub fn benchmark<F>(f: F) -> BenchSamples where F: FnMut(&mut Bencher) { let mut bs = Bencher { iterations: 0, - dur: Duration::nanoseconds(0), + dur: Duration::new(0, 0), bytes: 0 }; @@ -1185,7 +1187,7 @@ pub mod bench { pub fn run_once<F>(f: F) where F: FnOnce(&mut Bencher) { let mut bs = Bencher { iterations: 0, - dur: Duration::nanoseconds(0), + dur: Duration::new(0, 0), bytes: 0 }; bs.bench_n(1, f); diff --git a/src/rustbook/build.rs b/src/rustbook/build.rs index f96704ee128..47bdc9335c4 100644 --- a/src/rustbook/build.rs +++ b/src/rustbook/build.rs @@ -183,6 +183,12 @@ impl Subcommand for Build { tgt = PathBuf::from(&env::args().nth(3).unwrap()); } + // `_book` directory may already exist from previous runs. Check and + // delete it if it exists. + for entry in try!(fs::read_dir(&cwd)) { + let path = try!(entry).path(); + if path == tgt { try!(fs::remove_dir_all(&tgt)) } + } try!(fs::create_dir(&tgt)); try!(File::create(&tgt.join("rust-book.css")).and_then(|mut f| { diff --git a/src/test/auxiliary/issue-9906.rs b/src/test/auxiliary/issue-9906.rs index 0da0b9fa47d..5eb48985bf9 100644 --- a/src/test/auxiliary/issue-9906.rs +++ b/src/test/auxiliary/issue-9906.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:issue-9906.rs - pub use other::FooBar; pub use other::foo; diff --git a/src/test/auxiliary/issue_16723_multiple_items_syntax_ext.rs b/src/test/auxiliary/issue_16723_multiple_items_syntax_ext.rs index 58dee1216ee..7be5c3cf47c 100644 --- a/src/test/auxiliary/issue_16723_multiple_items_syntax_ext.rs +++ b/src/test/auxiliary/issue_16723_multiple_items_syntax_ext.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-stage1 // force-host #![feature(plugin_registrar, quote, rustc_private)] diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 8f3e939f1f4..af61b0aa0cd 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(std_misc, rand)] +#![feature(std_misc, rand, duration, duration_span)] use std::collections::{BTreeMap, HashMap, HashSet}; use std::env; diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index aeedaa288fe..eebf6feaffa 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -10,7 +10,7 @@ // ignore-pretty very bad with line comments -#![feature(unboxed_closures, rand, std_misc, collections)] +#![feature(unboxed_closures, rand, std_misc, collections, duration, duration_span)] extern crate collections; extern crate rand; @@ -167,13 +167,13 @@ fn write_results(label: &str, results: &Results) { fn empty_results() -> Results { Results { - sequential_ints: Duration::seconds(0), - random_ints: Duration::seconds(0), - delete_ints: Duration::seconds(0), + sequential_ints: Duration::new(0, 0), + random_ints: Duration::new(0, 0), + delete_ints: Duration::new(0, 0), - sequential_strings: Duration::seconds(0), - random_strings: Duration::seconds(0), - delete_strings: Duration::seconds(0), + sequential_strings: Duration::new(0, 0), + random_strings: Duration::new(0, 0), + delete_strings: Duration::new(0, 0), } } diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 19f83c7817c..6e85abb8e14 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -10,7 +10,7 @@ // Microbenchmarks for various functions in std and extra -#![feature(rand, collections, std_misc)] +#![feature(rand, collections, std_misc, duration, duration_span)] use std::iter::repeat; use std::mem::swap; @@ -52,7 +52,7 @@ fn maybe_run_test<F>(argv: &[String], name: String, test: F) where F: FnOnce() { let dur = Duration::span(test); - println!("{}:\t\t{} ms", name, dur.num_milliseconds()); + println!("{}:\t\t{}", name, dur); } fn shift_push() { diff --git a/src/test/bench/msgsend-pipes-shared.rs b/src/test/bench/msgsend-pipes-shared.rs index c7748d59c6a..2b7e204423e 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -18,7 +18,7 @@ // different scalability characteristics compared to the select // version. -#![feature(std_misc)] +#![feature(duration, duration_span)] use std::sync::mpsc::{channel, Sender, Receiver}; use std::env; @@ -88,9 +88,9 @@ fn run(args: &[String]) { }); let result = result.unwrap(); print!("Count is {}\n", result); - print!("Test took {} ms\n", dur.num_milliseconds()); - let thruput = ((size / workers * workers) as f64) / (dur.num_milliseconds() as f64); - print!("Throughput={} per sec\n", thruput / 1000.0); + print!("Test took {}\n", dur); + let thruput = ((size / workers * workers) as f64) / (dur.secs() as f64); + print!("Throughput={} per sec\n", thruput); assert_eq!(result, num_bytes * size); } diff --git a/src/test/bench/msgsend-pipes.rs b/src/test/bench/msgsend-pipes.rs index b6a6e06088a..5a541420d2a 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -14,7 +14,7 @@ // // I *think* it's the same, more or less. -#![feature(std_misc)] +#![feature(duration, duration_span)] use std::sync::mpsc::{channel, Sender, Receiver}; use std::env; @@ -95,9 +95,9 @@ fn run(args: &[String]) { }); let result = result.unwrap(); print!("Count is {}\n", result); - print!("Test took {} ms\n", dur.num_milliseconds()); - let thruput = ((size / workers * workers) as f64) / (dur.num_milliseconds() as f64); - print!("Throughput={} per sec\n", thruput / 1000.0); + print!("Test took {}\n", dur); + let thruput = ((size / workers * workers) as f64) / (dur.secs() as f64); + print!("Throughput={} per sec\n", thruput); assert_eq!(result, num_bytes * size); } diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index 07174de88a3..93e3394097b 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -17,7 +17,7 @@ // no-pretty-expanded FIXME #15189 -#![feature(std_misc)] +#![feature(duration, duration_span, std_misc)] use std::env; use std::sync::{Arc, Future, Mutex, Condvar}; @@ -107,9 +107,9 @@ fn main() { // all done, report stats. let num_msgs = num_tasks * msg_per_task; - let rate = (num_msgs as f64) / (dur.num_milliseconds() as f64); + let rate = (num_msgs as f64) / (dur.secs() as f64); - println!("Sent {} messages in {} ms", num_msgs, dur.num_milliseconds()); - println!(" {} messages / second", rate / 1000.0); - println!(" {} μs / message", 1000000. / rate / 1000.0); + println!("Sent {} messages in {}", num_msgs, dur); + println!(" {} messages / second", rate); + println!(" {} μs / message", 1000000. / rate); } diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index ed20f4b6362..2d5aae30ae8 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -18,7 +18,7 @@ */ -#![feature(std_misc, rustc_private)] +#![feature(duration, duration_span, rustc_private)] extern crate getopts; diff --git a/src/test/bench/std-smallintmap.rs b/src/test/bench/std-smallintmap.rs index dd56b18c144..d7e556a124f 100644 --- a/src/test/bench/std-smallintmap.rs +++ b/src/test/bench/std-smallintmap.rs @@ -10,7 +10,7 @@ // Microbenchmark for the smallintmap library -#![feature(collections, std_misc)] +#![feature(collections, duration, duration_span)] use std::collections::VecMap; use std::env; @@ -40,8 +40,8 @@ fn main() { let max = args[1].parse::<usize>().unwrap(); let rep = args[2].parse::<usize>().unwrap(); - let mut checkf = Duration::seconds(0); - let mut appendf = Duration::seconds(0); + let mut checkf = Duration::new(0, 0); + let mut appendf = Duration::new(0, 0); for _ in 0..rep { let mut map = VecMap::new(); @@ -55,7 +55,7 @@ fn main() { let maxf = max as f64; println!("insert(): {} seconds\n", checkf); - println!(" : {} op/ms\n", maxf / checkf.num_milliseconds() as f64); + println!(" : {} op/s\n", maxf / checkf.secs() as f64); println!("get() : {} seconds\n", appendf); - println!(" : {} op/ms\n", maxf / appendf.num_milliseconds() as f64); + println!(" : {} op/s\n", maxf / appendf.secs() as f64); } diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index e091dbfb00e..babae4d149f 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(box_syntax, std_misc, collections)] +#![feature(box_syntax, duration, duration_span, collections)] use std::env; use std::thread; diff --git a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs index 022a6b4f2f7..b3dbcb743a1 100644 --- a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs +++ b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs @@ -11,7 +11,6 @@ // Test that macro reexports item are gated by `macro_reexport` feature gate. // aux-build:macro_reexport_1.rs -// ignore-stage1 #![crate_type = "dylib"] diff --git a/src/test/compile-fail-fulldeps/gated-plugin.rs b/src/test/compile-fail-fulldeps/gated-plugin.rs index 9fa93063ea3..4e80ca46c0a 100644 --- a/src/test/compile-fail-fulldeps/gated-plugin.rs +++ b/src/test/compile-fail-fulldeps/gated-plugin.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:macro_crate_test.rs -// ignore-stage1 #![plugin(macro_crate_test)] //~^ ERROR compiler plugins are experimental and possibly buggy diff --git a/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs b/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs index 361840a1618..8ac03606720 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs +++ b/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:macro_crate_test.rs -// ignore-stage1 #[macro_use] #[no_link] extern crate macro_crate_test; diff --git a/src/test/compile-fail-fulldeps/macro-crate-rlib.rs b/src/test/compile-fail-fulldeps/macro-crate-rlib.rs index 396b1c1de3a..5b34d8e3adb 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-rlib.rs +++ b/src/test/compile-fail-fulldeps/macro-crate-rlib.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:rlib_crate_test.rs -// ignore-stage1 // ignore-tidy-linelength // ignore-cross-compile gives a different error message diff --git a/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs b/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs index ba8e20069c1..b0cd4220532 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs +++ b/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:macro_crate_test.rs -// ignore-stage1 #[macro_use] #[no_link] extern crate macro_crate_test; diff --git a/src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs b/src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs index c5169b61a2b..edbb77fe390 100644 --- a/src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs +++ b/src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:macro_crate_test.rs -// ignore-stage1 // ignore-cross-compile // // macro_crate_test will not compile on a cross-compiled target because diff --git a/src/test/compile-fail/associated-const-ambiguity-report.rs b/src/test/compile-fail/associated-const-ambiguity-report.rs new file mode 100644 index 00000000000..22292a6da9d --- /dev/null +++ b/src/test/compile-fail/associated-const-ambiguity-report.rs @@ -0,0 +1,33 @@ +// 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. + +#![feature(associated_consts)] + +trait Foo { + const ID: i32; +} + +trait Bar { + const ID: i32; +} + +impl Foo for i32 { + const ID: i32 = 1; +} + +impl Bar for i32 { + const ID: i32 = 3; +} + +const X: i32 = <i32>::ID; //~ ERROR E0034 + +fn main() { + assert_eq!(1, X); +} diff --git a/src/test/compile-fail/auto-ref-slice-plus-ref.rs b/src/test/compile-fail/auto-ref-slice-plus-ref.rs index ad3f467a454..f0f0bdfb38e 100644 --- a/src/test/compile-fail/auto-ref-slice-plus-ref.rs +++ b/src/test/compile-fail/auto-ref-slice-plus-ref.rs @@ -15,11 +15,11 @@ fn main() { // vectors to slices then automatically create a self reference. let mut a = vec!(0); - a.test_mut(); //~ ERROR does not implement any method in scope named `test_mut` - a.test(); //~ ERROR does not implement any method in scope named `test` + a.test_mut(); //~ ERROR no method named `test_mut` found + a.test(); //~ ERROR no method named `test` found - ([1]).test(); //~ ERROR does not implement any method in scope named `test` - (&[1]).test(); //~ ERROR does not implement any method in scope named `test` + ([1]).test(); //~ ERROR no method named `test` found + (&[1]).test(); //~ ERROR no method named `test` found } trait MyIter { diff --git a/src/test/compile-fail/class-cast-to-trait.rs b/src/test/compile-fail/class-cast-to-trait.rs index 31e09e877c7..af83b0ecbf2 100644 --- a/src/test/compile-fail/class-cast-to-trait.rs +++ b/src/test/compile-fail/class-cast-to-trait.rs @@ -60,5 +60,5 @@ fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { fn main() { let nyan: Box<noisy> = box cat(0, 2, "nyan".to_string()) as Box<noisy>; - nyan.eat(); //~ ERROR does not implement any method in scope named `eat` + nyan.eat(); //~ ERROR no method named `eat` found } diff --git a/src/test/compile-fail/coherence_inherent.rs b/src/test/compile-fail/coherence_inherent.rs index 2c3fbc827aa..087b8c14e35 100644 --- a/src/test/compile-fail/coherence_inherent.rs +++ b/src/test/compile-fail/coherence_inherent.rs @@ -38,7 +38,7 @@ mod NoImport { use Lib::TheStruct; fn call_the_fn(s: &TheStruct) { - s.the_fn(); //~ ERROR does not implement any method in scope named `the_fn` + s.the_fn(); //~ ERROR no method named `the_fn` found } } diff --git a/src/test/compile-fail/coherence_inherent_cc.rs b/src/test/compile-fail/coherence_inherent_cc.rs index 4eb9864bc9c..442c4c89de4 100644 --- a/src/test/compile-fail/coherence_inherent_cc.rs +++ b/src/test/compile-fail/coherence_inherent_cc.rs @@ -30,7 +30,7 @@ mod NoImport { use coherence_inherent_cc_lib::TheStruct; fn call_the_fn(s: &TheStruct) { - s.the_fn(); //~ ERROR does not implement any method in scope named `the_fn` + s.the_fn(); //~ ERROR no method named `the_fn` found } } diff --git a/src/test/compile-fail/copy-a-resource.rs b/src/test/compile-fail/copy-a-resource.rs index 98402591e72..70633c92e64 100644 --- a/src/test/compile-fail/copy-a-resource.rs +++ b/src/test/compile-fail/copy-a-resource.rs @@ -26,6 +26,6 @@ fn foo(i:isize) -> foo { fn main() { let x = foo(10); let _y = x.clone(); - //~^ ERROR does not implement any method in scope + //~^ ERROR no method named `clone` found println!("{:?}", x); } diff --git a/src/test/compile-fail/empty-macro-use.rs b/src/test/compile-fail/empty-macro-use.rs index fbf6287db94..d8cf23d1ff0 100644 --- a/src/test/compile-fail/empty-macro-use.rs +++ b/src/test/compile-fail/empty-macro-use.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use()] extern crate two_macros; diff --git a/src/test/compile-fail/for-expn-2.rs b/src/test/compile-fail/for-expn-2.rs new file mode 100644 index 00000000000..6b1dbf9d2d0 --- /dev/null +++ b/src/test/compile-fail/for-expn-2.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. + +// Test that we get an expansion stack for `for` loops. + +// error-pattern:in expansion of for loop expansion + +fn main() { + for t in &foo { + } +} diff --git a/src/test/compile-fail/for-expn.rs b/src/test/compile-fail/for-expn.rs new file mode 100644 index 00000000000..43776d75a47 --- /dev/null +++ b/src/test/compile-fail/for-expn.rs @@ -0,0 +1,19 @@ +// 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. + +// Test that an error on a sub-expresson in a for loop has the correct span. + +fn main() { + // Odd formatting to make sure we get the right span. + for t in & + foo //~ ERROR unresolved name `foo` + { + } +} diff --git a/src/test/compile-fail/issue-10465.rs b/src/test/compile-fail/issue-10465.rs index a5e374a7a8b..ed91e935407 100644 --- a/src/test/compile-fail/issue-10465.rs +++ b/src/test/compile-fail/issue-10465.rs @@ -24,7 +24,7 @@ pub mod b { use b::B; fn foo(b: &B) { - b.foo(); //~ ERROR: does not implement any method in scope named + b.foo(); //~ ERROR: no method named `foo` found } } diff --git a/src/test/compile-fail/issue-13853.rs b/src/test/compile-fail/issue-13853.rs index 251da2c6b3e..f5d158d64e1 100644 --- a/src/test/compile-fail/issue-13853.rs +++ b/src/test/compile-fail/issue-13853.rs @@ -31,7 +31,7 @@ impl Node for Stuff { } fn iterate<N: Node, G: Graph<N>>(graph: &G) { - for node in graph.iter() { //~ ERROR does not implement any method in scope named + for node in graph.iter() { //~ ERROR no method named `iter` found node.zomg(); //~ error: the type of this value must be known in this context } } diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs index 92e0dd3ad0e..003c6644f7f 100644 --- a/src/test/compile-fail/issue-14084.rs +++ b/src/test/compile-fail/issue-14084.rs @@ -12,5 +12,5 @@ fn main() { box ( () ) 0; - //~^ ERROR: only the managed heap and exchange heap are currently supported + //~^ ERROR: only the exchange heap is currently supported } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index f87a0d774fa..43e9ca5fa6e 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -14,6 +14,6 @@ struct Obj<F> where F: FnMut() -> u32 { fn main() { let o = Obj { closure: || 42 }; - o.closure(); //~ ERROR does not implement any method in scope named `closure` + o.closure(); //~ ERROR no method named `closure` found //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field } diff --git a/src/test/compile-fail/issue-1871.rs b/src/test/compile-fail/issue-1871.rs index 423d87861cb..e4d132c8641 100644 --- a/src/test/compile-fail/issue-1871.rs +++ b/src/test/compile-fail/issue-1871.rs @@ -14,7 +14,7 @@ fn main() { let f = 42; let _g = if f < 5 { - f.honk() //~ ERROR does not implement any method in scope named `honk` + f.honk() //~ ERROR no method named `honk` found } else { () diff --git a/src/test/compile-fail/issue-19521.rs b/src/test/compile-fail/issue-19521.rs index 61cff598b2a..58a95e9da2b 100644 --- a/src/test/compile-fail/issue-19521.rs +++ b/src/test/compile-fail/issue-19521.rs @@ -11,5 +11,5 @@ #![feature(unboxed_closures)] fn main() { - "".homura()(); //~ ERROR does not implement any method + "".homura()(); //~ ERROR no method named `homura` found } diff --git a/src/test/compile-fail/issue-19692.rs b/src/test/compile-fail/issue-19692.rs index 7b84ba0343a..88ae0f835d0 100644 --- a/src/test/compile-fail/issue-19692.rs +++ b/src/test/compile-fail/issue-19692.rs @@ -11,7 +11,7 @@ struct Homura; fn akemi(homura: Homura) { - let Some(ref madoka) = Some(homura.kaname()); //~ ERROR does not implement any method + let Some(ref madoka) = Some(homura.kaname()); //~ ERROR no method named `kaname` found madoka.clone(); //~ ERROR the type of this value must be known in this context } diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index ea305c96af4..bb170ef7d00 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -22,5 +22,5 @@ impl<A> vec_monad<A> for Vec<A> { } fn main() { ["hi"].bind(|x| [x] ); - //~^ ERROR type `[&str; 1]` does not implement any method in scope named `bind` + //~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope } diff --git a/src/test/compile-fail/issue-22645.rs b/src/test/compile-fail/issue-22645.rs new file mode 100644 index 00000000000..8677934fd64 --- /dev/null +++ b/src/test/compile-fail/issue-22645.rs @@ -0,0 +1,29 @@ +// 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. + +use std::ops::Add; + +trait Scalar {} +impl Scalar for f64 {} + +struct Bob; + +impl<RHS: Scalar> Add <RHS> for Bob { + type Output = Bob; + fn add(self, rhs : RHS) -> Bob {} +} + +fn main() { + let b = Bob + 3.5; + b + 3 //~ ERROR: is not implemented + //~^ ERROR: is not implemented + //~^^ ERROR: is not implemented + //~^^^ ERROR: mismatched types +} diff --git a/src/test/compile-fail/issue-24352.rs b/src/test/compile-fail/issue-24352.rs new file mode 100644 index 00000000000..0fbc634826b --- /dev/null +++ b/src/test/compile-fail/issue-24352.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. + +fn main() { + 1.0f64 - 1.0; + 1.0f64 - 1 //~ ERROR: is not implemented + //~^ ERROR: is not implemented +} diff --git a/src/test/compile-fail/issue-2823.rs b/src/test/compile-fail/issue-2823.rs index 1996cb737fc..631bcb7bd9e 100644 --- a/src/test/compile-fail/issue-2823.rs +++ b/src/test/compile-fail/issue-2823.rs @@ -20,5 +20,5 @@ impl Drop for C { fn main() { let c = C{ x: 2}; - let _d = c.clone(); //~ ERROR does not implement any method in scope + let _d = c.clone(); //~ ERROR no method named `clone` found } diff --git a/src/test/compile-fail/issue-3563.rs b/src/test/compile-fail/issue-3563.rs index 0e1cc18dba9..29c1c584eed 100644 --- a/src/test/compile-fail/issue-3563.rs +++ b/src/test/compile-fail/issue-3563.rs @@ -11,7 +11,7 @@ trait A { fn a(&self) { || self.b() - //~^ ERROR type `&Self` does not implement any method in scope named `b` + //~^ ERROR no method named `b` found for type `&Self` in the current scope //~| ERROR mismatched types //~| expected `()` //~| found closure diff --git a/src/test/compile-fail/issue-3702-2.rs b/src/test/compile-fail/issue-3702-2.rs index 026ee89c0b2..325f05841f4 100644 --- a/src/test/compile-fail/issue-3702-2.rs +++ b/src/test/compile-fail/issue-3702-2.rs @@ -23,7 +23,7 @@ trait Add { impl Add for isize { fn to_int(&self) -> isize { *self } fn add_dynamic(&self, other: &Add) -> isize { - self.to_int() + other.to_int() //~ ERROR multiple applicable methods in scope + self.to_int() + other.to_int() //~ ERROR multiple applicable items in scope } } diff --git a/src/test/compile-fail/issue-3707.rs b/src/test/compile-fail/issue-3707.rs index 0d57a8a50cc..ad56b125b08 100644 --- a/src/test/compile-fail/issue-3707.rs +++ b/src/test/compile-fail/issue-3707.rs @@ -17,7 +17,7 @@ impl Obj { return 1+1 == 2 } pub fn chirp(&self) { - self.boom(); //~ ERROR `&Obj` does not implement any method in scope named `boom` + self.boom(); //~ ERROR no method named `boom` found for type `&Obj` in the current scope } } diff --git a/src/test/compile-fail/issue-5153.rs b/src/test/compile-fail/issue-5153.rs index c10c7cba455..da32408e199 100644 --- a/src/test/compile-fail/issue-5153.rs +++ b/src/test/compile-fail/issue-5153.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: type `&Foo` does not implement any method in scope named `foo` - trait Foo { fn foo(self: Box<Self>); } @@ -20,4 +18,5 @@ impl Foo for isize { fn main() { (&5 as &Foo).foo(); + //~^ ERROR: no method named `foo` found for type `&Foo` in the current scope } diff --git a/src/test/compile-fail/issue-7575.rs b/src/test/compile-fail/issue-7575.rs index 6b320f400a8..6c7196527ef 100644 --- a/src/test/compile-fail/issue-7575.rs +++ b/src/test/compile-fail/issue-7575.rs @@ -71,15 +71,15 @@ impl ManyImplTrait for Myisize {} fn no_param_bound(u: usize, m: Myisize) -> usize { u.f8(42) + u.f9(342) + m.fff(42) - //~^ ERROR type `usize` does not implement any method in scope named `f9` + //~^ ERROR no method named `f9` found for type `usize` in the current scope //~^^ NOTE found defined static methods, maybe a `self` is missing? - //~^^^ ERROR type `Myisize` does not implement any method in scope named `fff` + //~^^^ ERROR no method named `fff` found for type `Myisize` in the current scope //~^^^^ NOTE found defined static methods, maybe a `self` is missing? } fn param_bound<T: ManyImplTrait>(t: T) -> bool { t.is_str() - //~^ ERROR type `T` does not implement any method in scope named `is_str` + //~^ ERROR no method named `is_str` found for type `T` in the current scope //~^^ NOTE found defined static methods, maybe a `self` is missing? } diff --git a/src/test/compile-fail/issue-7950.rs b/src/test/compile-fail/issue-7950.rs index 01b90f5680f..003329a2d7d 100644 --- a/src/test/compile-fail/issue-7950.rs +++ b/src/test/compile-fail/issue-7950.rs @@ -13,5 +13,5 @@ struct Foo; fn main() { - Foo::bar(); //~ ERROR type `Foo` does not implement any method in scope named `bar` + Foo::bar(); //~ ERROR no associated item named `bar` found for type `Foo` in the current scope } diff --git a/src/test/compile-fail/macro-backtrace-invalid-internals.rs b/src/test/compile-fail/macro-backtrace-invalid-internals.rs index df906d72356..34aa1c75872 100644 --- a/src/test/compile-fail/macro-backtrace-invalid-internals.rs +++ b/src/test/compile-fail/macro-backtrace-invalid-internals.rs @@ -12,7 +12,7 @@ macro_rules! fake_method_stmt { //~ NOTE in expansion of () => { - 1.fake() //~ ERROR does not implement any method + 1.fake() //~ ERROR no method named `fake` found } } @@ -30,7 +30,7 @@ macro_rules! fake_anon_field_stmt { //~ NOTE in expansion of macro_rules! fake_method_expr { //~ NOTE in expansion of () => { - 1.fake() //~ ERROR does not implement any method + 1.fake() //~ ERROR no method named `fake` found } } diff --git a/src/test/compile-fail/macro-crate-nonterminal-non-root.rs b/src/test/compile-fail/macro-crate-nonterminal-non-root.rs index 67aaf05c310..76211b88bd7 100644 --- a/src/test/compile-fail/macro-crate-nonterminal-non-root.rs +++ b/src/test/compile-fail/macro-crate-nonterminal-non-root.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:macro_crate_nonterminal.rs -// ignore-stage1 mod foo { #[macro_use] diff --git a/src/test/compile-fail/macro-no-implicit-reexport.rs b/src/test/compile-fail/macro-no-implicit-reexport.rs index e8d9f444cef..cd6640f8b6d 100644 --- a/src/test/compile-fail/macro-no-implicit-reexport.rs +++ b/src/test/compile-fail/macro-no-implicit-reexport.rs @@ -10,7 +10,6 @@ // aux-build:macro_reexport_1.rs // aux-build:macro_non_reexport_2.rs -// ignore-stage1 #[macro_use] #[no_link] extern crate macro_non_reexport_2; diff --git a/src/test/compile-fail/macro-reexport-not-locally-visible.rs b/src/test/compile-fail/macro-reexport-not-locally-visible.rs index 26de51a7cf8..ca334d9fd2d 100644 --- a/src/test/compile-fail/macro-reexport-not-locally-visible.rs +++ b/src/test/compile-fail/macro-reexport-not-locally-visible.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:macro_reexport_1.rs -// ignore-stage1 #![feature(macro_reexport)] diff --git a/src/test/compile-fail/macro-reexport-undef.rs b/src/test/compile-fail/macro-reexport-undef.rs index e9b3ceff83d..8fa6b32905c 100644 --- a/src/test/compile-fail/macro-reexport-undef.rs +++ b/src/test/compile-fail/macro-reexport-undef.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use(macro_two)] #[macro_reexport(no_way)] //~ ERROR reexported macro not found diff --git a/src/test/compile-fail/macro-use-undef.rs b/src/test/compile-fail/macro-use-undef.rs index a5a350bd30e..dd725aae95e 100644 --- a/src/test/compile-fail/macro-use-undef.rs +++ b/src/test/compile-fail/macro-use-undef.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use(macro_two, no_way)] //~ ERROR imported macro not found extern crate two_macros; diff --git a/src/test/compile-fail/macro-use-wrong-name.rs b/src/test/compile-fail/macro-use-wrong-name.rs index 4e0486f0db7..4dc65434dc7 100644 --- a/src/test/compile-fail/macro-use-wrong-name.rs +++ b/src/test/compile-fail/macro-use-wrong-name.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use(macro_one)] extern crate two_macros; diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/compile-fail/method-call-err-msg.rs index 2f82441762f..3434cf96fce 100644 --- a/src/test/compile-fail/method-call-err-msg.rs +++ b/src/test/compile-fail/method-call-err-msg.rs @@ -25,6 +25,6 @@ fn main() { let y = Foo; y.zero() - .take() //~ ERROR type `Foo` does not implement any method in scope named `take` + .take() //~ ERROR no method named `take` found for type `Foo` in the current scope .one(0); } diff --git a/src/test/compile-fail/method-suggestion-no-duplication.rs b/src/test/compile-fail/method-suggestion-no-duplication.rs index 1d0c4254eda..e6f3c8ab317 100644 --- a/src/test/compile-fail/method-suggestion-no-duplication.rs +++ b/src/test/compile-fail/method-suggestion-no-duplication.rs @@ -16,7 +16,7 @@ fn foo<F>(f: F) where F: FnMut(Foo) {} fn main() { foo(|s| s.is_empty()); - //~^ ERROR does not implement any method + //~^ ERROR no method named `is_empty` found //~^^ HELP #1: `core::slice::SliceExt` //~^^^ HELP #2: `core::str::StrExt` } diff --git a/src/test/compile-fail/missing-macro-use.rs b/src/test/compile-fail/missing-macro-use.rs index 0153d71fb26..bbce9c21287 100644 --- a/src/test/compile-fail/missing-macro-use.rs +++ b/src/test/compile-fail/missing-macro-use.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 extern crate two_macros; diff --git a/src/test/compile-fail/no-method-suggested-traits.rs b/src/test/compile-fail/no-method-suggested-traits.rs index 21f8a982806..08c848a09ab 100644 --- a/src/test/compile-fail/no-method-suggested-traits.rs +++ b/src/test/compile-fail/no-method-suggested-traits.rs @@ -33,36 +33,36 @@ fn main() { 1u32.method(); //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them - //~^^ ERROR does not implement + //~^^ ERROR no method named //~^^^ HELP `foo::Bar` //~^^^^ HELP `no_method_suggested_traits::foo::PubPub` std::rc::Rc::new(&mut Box::new(&1u32)).method(); //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them - //~^^ ERROR does not implement + //~^^ ERROR no method named //~^^^ HELP `foo::Bar` //~^^^^ HELP `no_method_suggested_traits::foo::PubPub` 'a'.method(); - //~^ ERROR does not implement + //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: //~^^^ HELP `foo::Bar` std::rc::Rc::new(&mut Box::new(&'a')).method(); - //~^ ERROR does not implement + //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: //~^^^ HELP `foo::Bar` 1i32.method(); - //~^ ERROR does not implement + //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: //~^^^ HELP `no_method_suggested_traits::foo::PubPub` std::rc::Rc::new(&mut Box::new(&1i32)).method(); - //~^ ERROR does not implement + //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: //~^^^ HELP `no_method_suggested_traits::foo::PubPub` Foo.method(); - //~^ ERROR does not implement - //~^^ HELP following traits define a method `method`, perhaps you need to implement one of them + //~^ ERROR no method named + //~^^ HELP following traits define an item `method`, perhaps you need to implement one of them //~^^^ HELP `foo::Bar` //~^^^^ HELP `no_method_suggested_traits::foo::PubPub` //~^^^^^ HELP `no_method_suggested_traits::reexport::Reexported` @@ -70,8 +70,8 @@ fn main() { //~^^^^^^^ HELP `no_method_suggested_traits::qux::PrivPub` //~^^^^^^^^ HELP `no_method_suggested_traits::quz::PrivPriv` std::rc::Rc::new(&mut Box::new(&Foo)).method(); - //~^ ERROR does not implement - //~^^ HELP following traits define a method `method`, perhaps you need to implement one of them + //~^ ERROR no method named + //~^^ HELP following traits define an item `method`, perhaps you need to implement one of them //~^^^ HELP `foo::Bar` //~^^^^ HELP `no_method_suggested_traits::foo::PubPub` //~^^^^^ HELP `no_method_suggested_traits::reexport::Reexported` @@ -80,55 +80,55 @@ fn main() { //~^^^^^^^^ HELP `no_method_suggested_traits::quz::PrivPriv` 1u64.method2(); - //~^ ERROR does not implement - //~^^ HELP the following trait defines a method `method2`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP the following trait defines an item `method2`, perhaps you need to implement it //~^^^ HELP `foo::Bar` std::rc::Rc::new(&mut Box::new(&1u64)).method2(); - //~^ ERROR does not implement - //~^^ HELP the following trait defines a method `method2`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP the following trait defines an item `method2`, perhaps you need to implement it //~^^^ HELP `foo::Bar` no_method_suggested_traits::Foo.method2(); - //~^ ERROR does not implement - //~^^ HELP following trait defines a method `method2`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP following trait defines an item `method2`, perhaps you need to implement it //~^^^ HELP `foo::Bar` std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2(); - //~^ ERROR does not implement - //~^^ HELP following trait defines a method `method2`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP following trait defines an item `method2`, perhaps you need to implement it //~^^^ HELP `foo::Bar` no_method_suggested_traits::Bar::X.method2(); - //~^ ERROR does not implement - //~^^ HELP following trait defines a method `method2`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP following trait defines an item `method2`, perhaps you need to implement it //~^^^ HELP `foo::Bar` std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2(); - //~^ ERROR does not implement - //~^^ HELP following trait defines a method `method2`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP following trait defines an item `method2`, perhaps you need to implement it //~^^^ HELP `foo::Bar` Foo.method3(); - //~^ ERROR does not implement - //~^^ HELP following trait defines a method `method3`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP following trait defines an item `method3`, perhaps you need to implement it //~^^^ HELP `no_method_suggested_traits::foo::PubPub` std::rc::Rc::new(&mut Box::new(&Foo)).method3(); - //~^ ERROR does not implement - //~^^ HELP following trait defines a method `method3`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP following trait defines an item `method3`, perhaps you need to implement it //~^^^ HELP `no_method_suggested_traits::foo::PubPub` Bar::X.method3(); - //~^ ERROR does not implement - //~^^ HELP following trait defines a method `method3`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP following trait defines an item `method3`, perhaps you need to implement it //~^^^ HELP `no_method_suggested_traits::foo::PubPub` std::rc::Rc::new(&mut Box::new(&Bar::X)).method3(); - //~^ ERROR does not implement - //~^^ HELP following trait defines a method `method3`, perhaps you need to implement it + //~^ ERROR no method named + //~^^ HELP following trait defines an item `method3`, perhaps you need to implement it //~^^^ HELP `no_method_suggested_traits::foo::PubPub` // should have no help: - 1_usize.method3(); //~ ERROR does not implement - std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); //~ ERROR does not implement - no_method_suggested_traits::Foo.method3(); //~ ERROR does not implement + 1_usize.method3(); //~ ERROR no method named + std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); //~ ERROR no method named + no_method_suggested_traits::Foo.method3(); //~ ERROR no method named std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3(); - //~^ ERROR does not implement - no_method_suggested_traits::Bar::X.method3(); //~ ERROR does not implement + //~^ ERROR no method named + no_method_suggested_traits::Bar::X.method3(); //~ ERROR no method named std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3(); - //~^ ERROR does not implement + //~^ ERROR no method named } diff --git a/src/test/compile-fail/non-copyable-void.rs b/src/test/compile-fail/non-copyable-void.rs index 40b641519b0..fd245f38a0c 100644 --- a/src/test/compile-fail/non-copyable-void.rs +++ b/src/test/compile-fail/non-copyable-void.rs @@ -15,6 +15,6 @@ fn main() { let y : *const libc::c_void = x as *const libc::c_void; unsafe { let _z = (*y).clone(); - //~^ ERROR does not implement any method in scope + //~^ ERROR no method named `clone` found } } diff --git a/src/test/compile-fail/noncopyable-class.rs b/src/test/compile-fail/noncopyable-class.rs index df135c3a8e3..f5712b0c957 100644 --- a/src/test/compile-fail/noncopyable-class.rs +++ b/src/test/compile-fail/noncopyable-class.rs @@ -41,6 +41,6 @@ fn foo(i:isize) -> foo { fn main() { let x = foo(10); - let _y = x.clone(); //~ ERROR does not implement any method in scope + let _y = x.clone(); //~ ERROR no method named `clone` found println!("{:?}", x); } diff --git a/src/test/compile-fail/object-pointer-types.rs b/src/test/compile-fail/object-pointer-types.rs index 84e7f98a40d..98c14cee942 100644 --- a/src/test/compile-fail/object-pointer-types.rs +++ b/src/test/compile-fail/object-pointer-types.rs @@ -19,19 +19,19 @@ trait Foo { fn borrowed_receiver(x: &Foo) { x.borrowed(); x.borrowed_mut(); // See [1] - x.owned(); //~ ERROR does not implement any method + x.owned(); //~ ERROR no method named `owned` found } fn borrowed_mut_receiver(x: &mut Foo) { x.borrowed(); x.borrowed_mut(); - x.owned(); //~ ERROR does not implement any method + x.owned(); //~ ERROR no method named `owned` found } fn owned_receiver(x: Box<Foo>) { x.borrowed(); x.borrowed_mut(); // See [1] - x.managed(); //~ ERROR does not implement any method + x.managed(); //~ ERROR no method named `managed` found x.owned(); } diff --git a/src/test/compile-fail/ret-non-nil.rs b/src/test/compile-fail/ret-non-nil.rs index 4ee3cf4abac..6be98fbd827 100644 --- a/src/test/compile-fail/ret-non-nil.rs +++ b/src/test/compile-fail/ret-non-nil.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: `return;` in function returning non-nil +// error-pattern: `return;` in a function whose return type is not `()` fn f() { return; } diff --git a/src/test/compile-fail/trait-impl-1.rs b/src/test/compile-fail/trait-impl-1.rs index dadcbd5bce7..e682d3c81e7 100644 --- a/src/test/compile-fail/trait-impl-1.rs +++ b/src/test/compile-fail/trait-impl-1.rs @@ -22,5 +22,5 @@ impl T for i32 {} fn main() { let x = &42i32; - x.foo(); //~ERROR: type `&i32` does not implement any method in scope named `foo` + x.foo(); //~ERROR: no method named `foo` found for type `&i32` in the current scope } diff --git a/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs index 1a52e22419e..1c133fbfcdb 100644 --- a/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs @@ -14,5 +14,5 @@ fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f } fn main() { let mut_ = to_fn_mut(|x| x); - mut_.call((0, )); //~ ERROR does not implement any method in scope named `call` + mut_.call((0, )); //~ ERROR no method named `call` found } diff --git a/src/test/compile-fail/unique-object-noncopyable.rs b/src/test/compile-fail/unique-object-noncopyable.rs index 5074d00ca15..c44718c4fc9 100644 --- a/src/test/compile-fail/unique-object-noncopyable.rs +++ b/src/test/compile-fail/unique-object-noncopyable.rs @@ -31,5 +31,5 @@ impl Foo for Bar { fn main() { let x = box Bar { x: 10 }; let y: Box<Foo> = x as Box<Foo>; - let _z = y.clone(); //~ ERROR does not implement any method in scope + let _z = y.clone(); //~ ERROR no method named `clone` found } diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs index 2ec10d08bb4..d971940db38 100644 --- a/src/test/compile-fail/unique-pinned-nocopy.rs +++ b/src/test/compile-fail/unique-pinned-nocopy.rs @@ -20,6 +20,6 @@ impl Drop for r { fn main() { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let i = Box::new(r { b: true }); - let _j = i.clone(); //~ ERROR not implement + let _j = i.clone(); //~ ERROR no method named `clone` found println!("{:?}", i); } diff --git a/src/test/run-pass-fulldeps/issue-13560.rs b/src/test/run-pass-fulldeps/issue-13560.rs index fc9f241af7f..88be7fe1212 100644 --- a/src/test/run-pass-fulldeps/issue-13560.rs +++ b/src/test/run-pass-fulldeps/issue-13560.rs @@ -11,7 +11,6 @@ // aux-build:issue-13560-1.rs // aux-build:issue-13560-2.rs // aux-build:issue-13560-3.rs -// ignore-stage1 // ignore-musl // Regression test for issue #13560, the test itself is all in the dependent diff --git a/src/test/run-pass/associated-const-match-patterns.rs b/src/test/run-pass/associated-const-match-patterns.rs index eeaacbf9dcc..62e90d7a6e2 100644 --- a/src/test/run-pass/associated-const-match-patterns.rs +++ b/src/test/run-pass/associated-const-match-patterns.rs @@ -42,6 +42,10 @@ fn main() { }); // Trait impl assert!(match Bar::Var1 { + Foo::THEBAR => true, + _ => false, + }); + assert!(match Bar::Var1 { <Foo>::THEBAR => true, _ => false, }); diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index df7cedd1c29..83ce0db365f 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -16,7 +16,7 @@ // instead of in std. #![reexport_test_harness_main = "test_main"] -#![feature(libc, std_misc)] +#![feature(libc, std_misc, duration)] extern crate libc; diff --git a/src/test/run-pass/issue-23825.rs b/src/test/run-pass/issue-23825.rs new file mode 100644 index 00000000000..1b857d94c72 --- /dev/null +++ b/src/test/run-pass/issue-23825.rs @@ -0,0 +1,30 @@ +// 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. + +trait Stringify { + fn to_string(&self) -> String; +} + +impl Stringify for u32 { + fn to_string(&self) -> String { format!("u32: {}", *self) } +} + +impl Stringify for f32 { + fn to_string(&self) -> String { format!("f32: {}", *self) } +} + +fn print<T: Stringify>(x: T) -> String { + x.to_string() +} + +fn main() { + assert_eq!(&print(5), "u32: 5"); + assert_eq!(&print(5.0), "f32: 5"); +} diff --git a/src/test/run-pass/macro-crate-nonterminal-renamed.rs b/src/test/run-pass/macro-crate-nonterminal-renamed.rs index ed7b1cbacad..93f5899e3ac 100644 --- a/src/test/run-pass/macro-crate-nonterminal-renamed.rs +++ b/src/test/run-pass/macro-crate-nonterminal-renamed.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:macro_crate_nonterminal.rs -// ignore-stage1 #[macro_use] extern crate macro_crate_nonterminal as new_name; diff --git a/src/test/run-pass/macro-crate-nonterminal.rs b/src/test/run-pass/macro-crate-nonterminal.rs index 9882f806a9e..28f9393ab7a 100644 --- a/src/test/run-pass/macro-crate-nonterminal.rs +++ b/src/test/run-pass/macro-crate-nonterminal.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:macro_crate_nonterminal.rs -// ignore-stage1 #[macro_use] extern crate macro_crate_nonterminal; diff --git a/src/test/run-pass/macro-export-inner-module.rs b/src/test/run-pass/macro-export-inner-module.rs index 1c7b2530b90..e39f81e49d7 100644 --- a/src/test/run-pass/macro-export-inner-module.rs +++ b/src/test/run-pass/macro-export-inner-module.rs @@ -9,7 +9,6 @@ // except according to those terms. //aux-build:macro_export_inner_module.rs -//ignore-stage1 #[macro_use] #[no_link] extern crate macro_export_inner_module; diff --git a/src/test/run-pass/macro-reexport-no-intermediate-use.rs b/src/test/run-pass/macro-reexport-no-intermediate-use.rs index dba623876b0..de7df1ec021 100644 --- a/src/test/run-pass/macro-reexport-no-intermediate-use.rs +++ b/src/test/run-pass/macro-reexport-no-intermediate-use.rs @@ -10,7 +10,6 @@ // aux-build:macro_reexport_1.rs // aux-build:macro_reexport_2_no_use.rs -// ignore-stage1 #[macro_use] #[no_link] extern crate macro_reexport_2_no_use; diff --git a/src/test/run-pass/macro-reexport.rs b/src/test/run-pass/macro-reexport.rs index a6af8c45c24..b8926eca9e9 100644 --- a/src/test/run-pass/macro-reexport.rs +++ b/src/test/run-pass/macro-reexport.rs @@ -10,7 +10,6 @@ // aux-build:macro_reexport_1.rs // aux-build:macro_reexport_2.rs -// ignore-stage1 #[macro_use] #[no_link] extern crate macro_reexport_2; diff --git a/src/test/run-pass/macro-use-all-and-none.rs b/src/test/run-pass/macro-use-all-and-none.rs index b46910290a8..60e1d6287f1 100644 --- a/src/test/run-pass/macro-use-all-and-none.rs +++ b/src/test/run-pass/macro-use-all-and-none.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use] #[macro_use()] diff --git a/src/test/run-pass/macro-use-all.rs b/src/test/run-pass/macro-use-all.rs index cf72d2c6230..ca9c0e23e7c 100644 --- a/src/test/run-pass/macro-use-all.rs +++ b/src/test/run-pass/macro-use-all.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use] extern crate two_macros; diff --git a/src/test/run-pass/macro-use-both.rs b/src/test/run-pass/macro-use-both.rs index 4b0814bef04..7e0a374ef15 100644 --- a/src/test/run-pass/macro-use-both.rs +++ b/src/test/run-pass/macro-use-both.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use(macro_one, macro_two)] extern crate two_macros; diff --git a/src/test/run-pass/macro-use-one.rs b/src/test/run-pass/macro-use-one.rs index 7911fec94da..6a30b3e55ba 100644 --- a/src/test/run-pass/macro-use-one.rs +++ b/src/test/run-pass/macro-use-one.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use(macro_two)] extern crate two_macros; diff --git a/src/test/run-pass/std-sync-right-kind-impls.rs b/src/test/run-pass/std-sync-right-kind-impls.rs index 058777bb05e..36314c5e14a 100644 --- a/src/test/run-pass/std-sync-right-kind-impls.rs +++ b/src/test/run-pass/std-sync-right-kind-impls.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(std_misc, alloc)] +#![feature(std_misc, alloc, static_condvar)] use std::sync; diff --git a/src/test/run-pass/two-macro-use.rs b/src/test/run-pass/two-macro-use.rs index 51c0b75e8fb..5df9d0222b4 100644 --- a/src/test/run-pass/two-macro-use.rs +++ b/src/test/run-pass/two-macro-use.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:two_macros.rs -// ignore-stage1 #[macro_use(macro_one)] #[macro_use(macro_two)] |
