diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2724e47938439..a4656dd415bbd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,60 +1,156 @@ -## How to submit a bug report +# Contributing to Rust -If you're just reporting a bug, please see: +Thank you for your interest in contributing to Rust! There are many ways to +contribute, and we appreciate all of them. This document is a bit long, so here's +links to the major sections: -http://doc.rust-lang.org/complement-bugreport.html +* [Feature Requests](#feature-requests) +* [Bug Reports](#bug-reports) +* [Pull Requests](#pull-requests) +* [Writing Documentation](#writing-documentation) +* [Issue Triage](#issue-triage) +* [Out-of-tree Contributions](#out-of-tree-contributions) -## Submitting an issue +If you have questions, please make a post on [internals.rust-lang.org][internals] or +hop on [#rust-internals][pound-rust-internals]. -Please submit issues here for bug reports or implementation details. For feature -requests, language changes, or major changes to the libraries, please submit an -issue against the [RFCs repository](https://github.com/rust-lang/rfcs). +As a reminder, all contributors are expected to follow our [Code of Conduct](coc). -## Pull request procedure +[pound-rust-internals]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals +[internals]: http://internals.rust-lang.org +[coc]: http://www.rust-lang.org/conduct.html -Pull requests should be targeted at Rust's `master` branch. -Before pushing to your Github repo and issuing the pull request, -please do two things: +## Feature Requests -1. [Rebase](http://git-scm.com/book/en/Git-Branching-Rebasing) your - local changes against the `master` branch. Resolve any conflicts - that arise. +To request a change to the way that the Rust language works, please open an +issue in the [RFCs repository](https://github.com/rust-lang/rfcs/issues/new) +rather than this one. New features and other significant language changes +must go through the RFC process. -2. Run the full Rust test suite with the `make check` command. You're - not off the hook even if you just stick to documentation; code - examples in the docs are tested as well! Although for simple - wording or grammar fixes, this is probably unnecessary. +## Bug Reports -Pull requests will be treated as "review requests", and we will give -feedback we expect to see corrected on -[style](http://aturon.github.io/) and -substance before pulling. Changes contributed via pull request should -focus on a single issue at a time, like any other. We will not accept -pull-requests that try to "sneak" unrelated changes in. +While bugs are unfortunate, they're a reality in software. We can't fix what we +don't know about, so please report liberally. If you're not sure if something +is a bug or not, feel free to file a bug anyway. -Normally, all pull requests must include regression tests (see -[Note-testsuite](https://github.com/rust-lang/rust/wiki/Note-testsuite)) -that test your change. Occasionally, a change will be very difficult -to test for. In those cases, please include a note in your commit -message explaining why. +If you have the chance, before reporting a bug, please [search existing +issues](https://github.com/rust-lang/rust/search?q=&type=Issues&utf8=%E2%9C%93), +as it's possible that someone else has already reported your error. This doesn't +always work, and sometimes it's hard to know what to search for, so consider this +extra credit. We won't mind if you accidentally file a duplicate report. -In the licensing header at the beginning of any files you change, -please make sure the listed date range includes the current year. For -example, if it's 2014, and you change a Rust file that was created in -2010, it should begin: +Opening an issue is as easy as following [this +link](https://github.com/rust-lang/rust/issues/new) and filling out the fields. +Here's a template that you can use to file a bug, though it's not necessary to +use it exactly: -``` -// Copyright 2010-2014 The Rust Project Developers. + + + I tried this code: + + + + I expected to see this happen: + + Instead, this happened: + + ## Meta + + `rustc --version --verbose`: + + Backtrace: + +All three components are important: what you did, what you expected, what +happened instead. Please include the output of `rustc --version --verbose`, +which includes important information about what platform you're on, what +version of Rust you're using, etc. + +Sometimes, a backtrace is helpful, and so including that is nice. To get +a backtrace, set the `RUST_BACKTRACE` environment variable. The easiest way +to do this is to invoke `rustc` like this: + +```bash +$ RUST_BACKTRACE=1 rustc ... ``` -# Coordination and communication +## Pull Requests -Get feedback from other developers on -[internals.rust-lang.org][internals], and -[#rust-internals][pound-rust-internals]. +Pull requests are the primary mechanism we use to change Rust. GitHub itself +has some [great documentation][pull-requests] on using the Pull Request +feature. We use the 'fork and pull' model described there. -[pound-rust-internals]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals -[internals]: http://internals.rust-lang.org +[pull-requests]: https://help.github.com/articles/using-pull-requests/ + +Please make pull requests against the `master` branch. + +All pull requests are reviewed by another person. We have a bot, +@rust-highfive, that will automatically assign a random person to review your request. + +If you want to request that a specific person reviews your pull request, +you can add an `r?` to the message. For example, Steve usually reviews +documentation changes. So if you were to make a documentation change, add + + r? @steveklabnik + +to the end of the message, and @rust-highfive will assign @steveklabnik instead +of a random person. This is entirely optional. + +After someone has reviewed your pull request, they will leave an annotation +on the pull request with an `r+`. It will look something like this: + + @bors: r+ 38fe8d2 + +This tells @bors, our lovable integration bot, that your pull request has +been approved. The PR then enters the [merge queue][merge-queue], where @bors +will run all the tests on every platform we support. If it all works out, +@bors will merge your code into `master` and close the pull request. + +[merge-queue]: http://buildbot.rust-lang.org/homu/queue/rust + +## Writing Documentation + +Documentation improvements are very welcome. The source of `doc.rust-lang.org` +is located in `src/doc` in the tree, and standard API documentation is generated +from the source code itself. + +Documentation pull requests function in the same as other pull requests, though +you may see a slightly different form of `r+`: + + @bors: r+ 38fe8d2 rollup + +That additional `rollup` tells @bors that this change is eligible for a 'rollup'. +To save @bors some work, and to get small changes through more quickly, when +@bors attempts to merge a commit that's rollup-eligible, it will also merge +the other rollup-eligible patches too, and they'll get tested and merged at +the same time. + +## Issue Triage + +Sometimes, an issue will stay open, even though the bug has been fixed. And +sometimes, the original bug may go stale because something has changed in the +meantime. + +It can be helpful to go through older bug reports and make sure that they are +still valid. Load up an older issue, double check that it's still true, and +leave a comment letting us know if it is or is not. The [least recently updated sort][lru] is good for finding issues like this. + +[lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc + +## Out-of-tree Contributions + +There are a number of other ways to contribute to Rust that don't deal with +this repository. + +Answer questions in [#rust][pound-rust], or on [users.rust-lang.org][users], +or on [StackOverflow][so]. + +Participate in the [RFC process](https://github.com/rust-lang/rfcs). + +Find a [requested community library][community-library], build it, and publish +it to [Crates.io](http://crates.io). Easier said than done, but very, very +valuable! -For more details, please refer to -[Note-development-policy](https://github.com/rust-lang/rust/wiki/Note-development-policy). +[pound-rust]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust +[users]: http://users.rust-lang.org/ +[so]: http://stackoverflow.com/questions/tagged/rust +[community-library]: https://github.com/rust-lang/rfcs/labels/A-community-library diff --git a/README.md b/README.md index 9d7c939ff9de8..065c4ed7c7bcb 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Read ["Installing Rust"][install] from [The Book][trpl]. * GNU `make` 3.81 or later * `curl` * `git` + 2. Download and build Rust: You can either download a [tarball] or build directly from the [repo]. @@ -97,19 +98,21 @@ There is a lot more documentation in the [wiki]. [wiki]: https://github.com/rust-lang/rust/wiki -## Getting help and getting involved +## Getting help The Rust community congregates in a few places: * [StackOverflow] - Direct questions about using the language here. * [users.rust-lang.org] - General discussion, broader questions. -* [internals.rust-lang.org] - For development of the Rust language itself. * [/r/rust] - News and general discussion. [StackOverflow]: http://stackoverflow.com/questions/tagged/rust [/r/rust]: http://reddit.com/r/rust [users.rust-lang.org]: http://users.rust-lang.org/ -[internals.rust-lang.org]: http://internals.rust-lang.org/ + +## Contributing + +To contribute to Rust, please see [CONTRIBUTING.md](CONTRIBUTING.md). ## License diff --git a/mk/docs.mk b/mk/docs.mk index 799871e2bd596..743032f676d21 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -25,7 +25,7 @@ # L10N_LANGS are the languages for which the docs have been # translated. ###################################################################### -DOCS := index intro tutorial complement-bugreport \ +DOCS := index intro tutorial \ complement-lang-faq complement-design-faq complement-project-faq \ rustdoc reference grammar @@ -73,7 +73,7 @@ RUSTBOOK = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(RUSTBOOK_EXE) D := $(S)src/doc -DOC_TARGETS := trpl +DOC_TARGETS := trpl style COMPILER_DOC_TARGETS := DOC_L10N_TARGETS := @@ -275,3 +275,9 @@ trpl: doc/book/index.html doc/book/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md) | doc/ $(Q)rm -rf doc/book $(Q)$(RUSTBOOK) build $(S)src/doc/trpl doc/book + +style: doc/style/index.html + +doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/ + $(Q)rm -rf doc/style + $(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 6c1308a01c4a1..86710d50d8a06 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -13,8 +13,8 @@ #![feature(box_syntax)] #![feature(collections)] #![feature(int_uint)] -#![feature(io)] -#![feature(path)] +#![feature(old_io)] +#![feature(old_path)] #![feature(rustc_private)] #![feature(unboxed_closures)] #![feature(std_misc)] diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 54c011832d1dc..658c0cb3f4e83 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -35,7 +35,7 @@ use std::env; use std::iter::repeat; use std::str; use std::string::String; -use std::thread::Thread; +use std::thread; use std::time::Duration; use test::MetricMap; @@ -458,7 +458,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { loop { //waiting 1 second for gdbserver start timer::sleep(Duration::milliseconds(1000)); - let result = Thread::scoped(move || { + let result = thread::spawn(move || { tcp::TcpStream::connect("127.0.0.1:5039").unwrap(); }).join(); if result.is_err() { diff --git a/src/doc/complement-bugreport.md b/src/doc/complement-bugreport.md deleted file mode 100644 index 1a28cd682e70c..0000000000000 --- a/src/doc/complement-bugreport.md +++ /dev/null @@ -1,61 +0,0 @@ -% How to submit a Rust bug report - -# I think I found a bug in the compiler! - -If you see this message: `error: internal compiler error: unexpected panic`, -then you have definitely found a bug in the compiler. It's also possible that -your code is not well-typed, but if you saw this message, it's still a bug in -error reporting. - -If you see a message about an LLVM assertion failure, then you have also -definitely found a bug in the compiler. In both of these cases, it's not your -fault and you should report a bug! - -If you see a compiler error message that you think is meant for users to see, -but it confuses you, *that's a bug too*. If it wasn't clear to you, then it's -an error message we want to improve, so please report it so that we can try -to make it better. - -# How do I know the bug I found isn't a bug that already exists in the issue tracker? - -If you don't have enough time for a search, then don't worry about that. Just submit -the bug. If it's a duplicate, somebody will notice that and close it during triage. - -If you have the time for it, it would be useful to type the text of the error -message you got [into the issue tracker search box](https://github.com/rust-lang/rust/issues) -to see if there's an existing bug that resembles your problem. If there is, -and it's an open bug, you can comment on that issue and say you are also affected. -This will encourage the devs to fix it. But again, don't let this stop you from -submitting a bug. We'd rather have to do the work of closing duplicates than -miss out on valid bug reports. - -# What information should I include in a bug report? - -It generally helps our diagnosis to include your specific OS (for example: Mac OS X 10.8.3, -Windows 7, Ubuntu 12.04) and your hardware architecture (for example: i686, x86_64). -It's also helpful to provide the exact version and host by copying the output of -re-running the erroneous rustc command with the `--version --verbose` flags, which will -produce something like this: - -```text -rustc 0.12.0 (ba4081a5a 2014-10-07 13:44:41 -0700) -binary: rustc -commit-hash: ba4081a5a8573875fed17545846f6f6902c8ba8d -commit-date: 2014-10-07 13:44:41 -0700 -host: i686-apple-darwin -release: 0.12.0 -``` - -Finally, if you can also provide a backtrace, that'd be great. You can get a -backtrace by setting the `RUST_BACKTRACE` environment variable to `1`, like -this: - -```bash -$ RUST_BACKTRACE=1 rustc ... -``` - -# I submitted a bug, but nobody has commented on it! - -This is sad, but does happen sometimes, since we're short-staffed. If you submit a -bug and you haven't received a comment on it within 3 business days, it's entirely -reasonable to ask about the status of the bug in #rust on irc.mozilla.org. diff --git a/src/doc/reference.md b/src/doc/reference.md index 11b2afc1c8822..00ed5d4562b11 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2398,6 +2398,10 @@ The currently implemented features of the reference compiler are: ways insufficient for concatenating identifiers, and may be removed entirely for something more wholesome. +* `custom_attribute` - Allows the usage of attributes unknown to the compiler + so that new attributes can be added in a bacwards compatible + manner (RFC 572). + * `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics are inherently unstable and no promise about them is made. @@ -2458,6 +2462,9 @@ The currently implemented features of the reference compiler are: implemented very poorly and will likely change significantly with a proper implementation. +* `rustc_attrs` - Gates internal `#[rustc_*]` attributes which may be + for internal use only or have meaning added to them in the future. + * `rustc_diagnostic_macros`- A mysterious feature, used in the implementation of rustc, not meant for mortals. diff --git a/src/doc/style/README.md b/src/doc/style/README.md new file mode 100644 index 0000000000000..9b328b5d393c5 --- /dev/null +++ b/src/doc/style/README.md @@ -0,0 +1,64 @@ +% Style Guidelines + +This document collects the emerging principles, conventions, abstractions, and +best practices for writing Rust code. + +Since Rust is evolving at a rapid pace, these guidelines are +preliminary. The hope is that writing them down explicitly will help +drive discussion, consensus and adoption. + +Whenever feasible, guidelines provide specific examples from Rust's standard +libraries. + +### Guideline statuses + +Every guideline has a status: + +* **[FIXME]**: Marks places where there is more work to be done. In + some cases, that just means going through the RFC process. + +* **[FIXME #NNNNN]**: Like **[FIXME]**, but links to the issue tracker. + +* **[RFC #NNNN]**: Marks accepted guidelines, linking to the rust-lang + RFC establishing them. + +### Guideline stabilization + +One purpose of these guidelines is to reach decisions on a number of +cross-cutting API and stylistic choices. Discussion and development of +the guidelines will happen primarily on http://discuss.rust-lang.org/, +using the Guidelines category. Discussion can also occur on the +[guidelines issue tracker](https://github.com/rust-lang/rust-guidelines). + +Guidelines that are under development or discussion will be marked with the +status **[FIXME]**, with a link to the issue tracker when appropriate. + +Once a concrete guideline is ready to be proposed, it should be filed +as an [FIXME: needs RFC](https://github.com/rust-lang/rfcs). If the RFC is +accepted, the official guidelines will be updated to match, and will +include the tag **[RFC #NNNN]** linking to the RFC document. + +### What's in this document + +This document is broken into four parts: + +* **[Style](style/README.md)** provides a set of rules governing naming conventions, + whitespace, and other stylistic issues. + +* **[Guidelines by Rust feature](features/README.md)** places the focus on each of + Rust's features, starting from expressions and working the way out toward + crates, dispensing guidelines relevant to each. + +* **Topical guidelines and patterns**. The rest of the document proceeds by + cross-cutting topic, starting with + [Ownership and resources](ownership/README.md). + +* **[APIs for a changing Rust](changing/README.md)** + discusses the forward-compatibility hazards, especially those that interact + with the pre-1.0 library stabilization process. + +> **[FIXME]** Add cross-references throughout this document to the tutorial, +> reference manual, and other guides. + +> **[FIXME]** What are some _non_-goals, _non_-principles, or _anti_-patterns that +> we should document? diff --git a/src/doc/style/SUMMARY.md b/src/doc/style/SUMMARY.md new file mode 100644 index 0000000000000..41bc08f229e7c --- /dev/null +++ b/src/doc/style/SUMMARY.md @@ -0,0 +1,54 @@ +# Summary + +* [Style](style/README.md) + * [Whitespace](style/whitespace.md) + * [Comments](style/comments.md) + * [Braces, semicolons, commas](style/braces.md) + * [Naming](style/naming/README.md) + * [Ownership variants](style/naming/ownership.md) + * [Containers/wrappers](style/naming/containers.md) + * [Conversions](style/naming/conversions.md) + * [Iterators](style/naming/iterators.md) + * [Imports](style/imports.md) + * [Organization](style/organization.md) +* [Guidelines by Rust feature](features/README.md) + * [Let binding](features/let.md) + * [Pattern matching](features/match.md) + * [Loops](features/loops.md) + * [Functions and methods](features/functions-and-methods/README.md) + * [Input](features/functions-and-methods/input.md) + * [Output](features/functions-and-methods/output.md) + * [For convenience](features/functions-and-methods/convenience.md) + * [Types](features/types/README.md) + * [Conversions](features/types/conversions.md) + * [The newtype pattern](features/types/newtype.md) + * [Traits](features/traits/README.md) + * [For generics](features/traits/generics.md) + * [For objects](features/traits/objects.md) + * [For overloading](features/traits/overloading.md) + * [For extensions](features/traits/extensions.md) + * [For reuse](features/traits/reuse.md) + * [Common traits](features/traits/common.md) + * [Modules](features/modules.md) + * [Crates](features/crates.md) +* [Ownership and resources](ownership/README.md) + * [Constructors](ownership/constructors.md) + * [Builders](ownership/builders.md) + * [Destructors](ownership/destructors.md) + * [RAII](ownership/raii.md) + * [Cells and smart pointers](ownership/cell-smart.md) +* [Errors](errors/README.md) + * [Signaling](errors/signaling.md) + * [Handling](errors/handling.md) + * [Propagation](errors/propagation.md) + * [Ergonomics](errors/ergonomics.md) +* [Safety and guarantees](safety/README.md) + * [Using unsafe](safety/unsafe.md) + * [Library guarantees](safety/lib-guarantees.md) +* [Testing](testing/README.md) + * [Unit testing](testing/unit.md) +* [FFI, platform-specific code](platform.md) +* [APIs for a changing Rust](changing/README.md) + * [Pre-1.0 changes](changing/pre-1-0.md) + * [Post-1.0 changes](changing/post-1-0.md) + * [Timing unclear](changing/unclear.md) diff --git a/src/doc/style/changing/README.md b/src/doc/style/changing/README.md new file mode 100644 index 0000000000000..38e76f6970c81 --- /dev/null +++ b/src/doc/style/changing/README.md @@ -0,0 +1,5 @@ +% API design for a changing Rust + +A number of planned Rust features will drastically affect the API design +story. This section collects some of the biggest features with concrete examples +of how the API will change. diff --git a/src/doc/style/changing/post-1-0.md b/src/doc/style/changing/post-1-0.md new file mode 100644 index 0000000000000..7ac1c837c071f --- /dev/null +++ b/src/doc/style/changing/post-1-0.md @@ -0,0 +1,12 @@ +% Post-1.0 changes + +### Higher-kinded types + +* A trait encompassing both `Iterable` for some fixed `T` and + `FromIterator` for _all_ `U` (where HKT comes in). The train + could provide e.g. a default `map` method producing the same kind of + the container, but with a new type parameter. + +* **Monadic-generic programming**? Can we add this without deprecating + huge swaths of the API (including `Option::map`, `option::collect`, + `result::collect`, `try!` etc. diff --git a/src/doc/style/changing/pre-1-0.md b/src/doc/style/changing/pre-1-0.md new file mode 100644 index 0000000000000..adadfe31a59d1 --- /dev/null +++ b/src/doc/style/changing/pre-1-0.md @@ -0,0 +1,17 @@ +% Pre-1.0 changes + +### `std` facade + +We should revisit some APIs in `libstd` now that the facade effort is complete. + +For example, the treatment of environment variables in the new +`Command` API is waiting on access to hashtables before being +approved. + +### Trait reform + +Potential for standard conversion traits (`to`, `into`, `as`). + +Probably many other opportunities here. + +### Unboxed closures diff --git a/src/doc/style/changing/unclear.md b/src/doc/style/changing/unclear.md new file mode 100644 index 0000000000000..e4b8a98e1a162 --- /dev/null +++ b/src/doc/style/changing/unclear.md @@ -0,0 +1,28 @@ +% Changes with unclear timing + +### Associated items + +* Many traits that currently take type parameters should instead use associated + types; this will _drastically_ simplify signatures in some cases. + +* Associated constants would be useful in a few places, e.g. traits for + numerics, traits for paths. + +### Anonymous, unboxed return types (aka `impl Trait` types) + +* See https://github.com/rust-lang/rfcs/pull/105 + +* Could affect API design in several places, e.g. the `Iterator` trait. + +### Default type parameters + +We are already using this in a few places (e.g. `HashMap`), but it's +feature-gated. + +### Compile-time function evaluation (CTFE) + +https://github.com/mozilla/rust/issues/11621 + +### Improved constant folding + +https://github.com/rust-lang/rust/issues/7834 diff --git a/src/doc/style/errors/README.md b/src/doc/style/errors/README.md new file mode 100644 index 0000000000000..444da26ff8fed --- /dev/null +++ b/src/doc/style/errors/README.md @@ -0,0 +1,3 @@ +% Errors + +> **[FIXME]** Add some general text here. diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md new file mode 100644 index 0000000000000..33f1e82b187e7 --- /dev/null +++ b/src/doc/style/errors/ergonomics.md @@ -0,0 +1,66 @@ +% Ergonomic error handling + +Error propagation with raw `Result`s can require tedious matching and +repackaging. This tedium is largely alleviated by the `try!` macro, +and can be completely removed (in some cases) by the "`Result`-`impl`" +pattern. + +### The `try!` macro + +Prefer + +```rust +use std::io::{File, Open, Write, IoError}; + +struct Info { + name: String, + age: int, + rating: int +} + +fn write_info(info: &Info) -> Result<(), IoError> { + let mut file = File::open_mode(&Path::new("my_best_friends.txt"), + Open, Write); + // Early return on error + try!(file.write_line(format!("name: {}", info.name).as_slice())); + try!(file.write_line(format!("age: {}", info.age).as_slice())); + try!(file.write_line(format!("rating: {}", info.rating).as_slice())); + return Ok(()); +} +``` + +over + +```rust +use std::io::{File, Open, Write, IoError}; + +struct Info { + name: String, + age: int, + rating: int +} + +fn write_info(info: &Info) -> Result<(), IoError> { + let mut file = File::open_mode(&Path::new("my_best_friends.txt"), + Open, Write); + // Early return on error + match file.write_line(format!("name: {}", info.name).as_slice()) { + Ok(_) => (), + Err(e) => return Err(e) + } + match file.write_line(format!("age: {}", info.age).as_slice()) { + Ok(_) => (), + Err(e) => return Err(e) + } + return file.write_line(format!("rating: {}", info.rating).as_slice()); +} +``` + +See +[the `result` module documentation](http://static.rust-lang.org/doc/master/std/result/index.html#the-try!-macro) +for more details. + +### The `Result`-`impl` pattern [FIXME] + +> **[FIXME]** Document the way that the `io` module uses trait impls +> on `IoResult` to painlessly propagate errors. diff --git a/src/doc/style/errors/handling.md b/src/doc/style/errors/handling.md new file mode 100644 index 0000000000000..cc5b5b475769c --- /dev/null +++ b/src/doc/style/errors/handling.md @@ -0,0 +1,7 @@ +% Handling errors + +### Use task isolation to cope with failure. [FIXME] + +> **[FIXME]** Explain how to isolate tasks and detect task failure for recovery. + +### Consuming `Result` [FIXME] diff --git a/src/doc/style/errors/propagation.md b/src/doc/style/errors/propagation.md new file mode 100644 index 0000000000000..0a347cd577b90 --- /dev/null +++ b/src/doc/style/errors/propagation.md @@ -0,0 +1,8 @@ +% Propagation + +> **[FIXME]** We need guidelines on how to layer error information up a stack of +> abstractions. + +### Error interoperation [FIXME] + +> **[FIXME]** Document the `FromError` infrastructure. diff --git a/src/doc/style/errors/signaling.md b/src/doc/style/errors/signaling.md new file mode 100644 index 0000000000000..95db4f8afa03c --- /dev/null +++ b/src/doc/style/errors/signaling.md @@ -0,0 +1,125 @@ +% Signaling errors [RFC #236] + +> The guidelines below were approved by [RFC #236](https://github.com/rust-lang/rfcs/pull/236). + +Errors fall into one of three categories: + +* Catastrophic errors, e.g. out-of-memory. +* Contract violations, e.g. wrong input encoding, index out of bounds. +* Obstructions, e.g. file not found, parse error. + +The basic principle of the convention is that: + +* Catastrophic errors and programming errors (bugs) can and should only be +recovered at a *coarse grain*, i.e. a task boundary. +* Obstructions preventing an operation should be reported at a maximally *fine +grain* -- to the immediate invoker of the operation. + +## Catastrophic errors + +An error is _catastrophic_ if there is no meaningful way for the current task to +continue after the error occurs. + +Catastrophic errors are _extremely_ rare, especially outside of `libstd`. + +**Canonical examples**: out of memory, stack overflow. + +### For catastrophic errors, panic + +For errors like stack overflow, Rust currently aborts the process, but +could in principle panic, which (in the best case) would allow +reporting and recovery from a supervisory task. + +## Contract violations + +An API may define a contract that goes beyond the type checking enforced by the +compiler. For example, slices support an indexing operation, with the contract +that the supplied index must be in bounds. + +Contracts can be complex and involve more than a single function invocation. For +example, the `RefCell` type requires that `borrow_mut` not be called until all +existing borrows have been relinquished. + +### For contract violations, panic + +A contract violation is always a bug, and for bugs we follow the Erlang +philosophy of "let it crash": we assume that software *will* have bugs, and we +design coarse-grained task boundaries to report, and perhaps recover, from these +bugs. + +### Contract design + +One subtle aspect of these guidelines is that the contract for a function is +chosen by an API designer -- and so the designer also determines what counts as +a violation. + +This RFC does not attempt to give hard-and-fast rules for designing +contracts. However, here are some rough guidelines: + +* Prefer expressing contracts through static types whenever possible. + +* It *must* be possible to write code that uses the API without violating the + contract. + +* Contracts are most justified when violations are *inarguably* bugs -- but this + is surprisingly rare. + +* Consider whether the API client could benefit from the contract-checking + logic. The checks may be expensive. Or there may be useful programming + patterns where the client does not want to check inputs before hand, but would + rather attempt the operation and then find out whether the inputs were invalid. + +* When a contract violation is the *only* kind of error a function may encounter + -- i.e., there are no obstructions to its success other than "bad" inputs -- + using `Result` or `Option` instead is especially warranted. Clients can then use + `unwrap` to assert that they have passed valid input, or re-use the error + checking done by the API for their own purposes. + +* When in doubt, use loose contracts and instead return a `Result` or `Option`. + +## Obstructions + +An operation is *obstructed* if it cannot be completed for some reason, even +though the operation's contract has been satisfied. Obstructed operations may +have (documented!) side effects -- they are not required to roll back after +encountering an obstruction. However, they should leave the data structures in +a "coherent" state (satisfying their invariants, continuing to guarantee safety, +etc.). + +Obstructions may involve external conditions (e.g., I/O), or they may involve +aspects of the input that are not covered by the contract. + +**Canonical examples**: file not found, parse error. + +### For obstructions, use `Result` + +The +[`Result` type](http://static.rust-lang.org/doc/master/std/result/index.html) +represents either a success (yielding `T`) or failure (yielding `E`). By +returning a `Result`, a function allows its clients to discover and react to +obstructions in a fine-grained way. + +#### What about `Option`? + +The `Option` type should not be used for "obstructed" operations; it +should only be used when a `None` return value could be considered a +"successful" execution of the operation. + +This is of course a somewhat subjective question, but a good litmus +test is: would a reasonable client ever ignore the result? The +`Result` type provides a lint that ensures the result is actually +inspected, while `Option` does not, and this difference of behavior +can help when deciding between the two types. + +Another litmus test: can the operation be understood as asking a +question (possibly with sideeffects)? Operations like `pop` on a +vector can be viewed as asking for the contents of the first element, +with the side effect of removing it if it exists -- with an `Option` +return value. + +## Do not provide both `Result` and `panic!` variants. + +An API should not provide both `Result`-producing and `panic`king versions of an +operation. It should provide just the `Result` version, allowing clients to use +`try!` or `unwrap` instead as needed. This is part of the general pattern of +cutting down on redundant variants by instead using method chaining. diff --git a/src/doc/style/features/README.md b/src/doc/style/features/README.md new file mode 100644 index 0000000000000..09657503d20d1 --- /dev/null +++ b/src/doc/style/features/README.md @@ -0,0 +1,9 @@ +% Guidelines by language feature + +Rust provides a unique combination of language features, some new and some +old. This section gives guidance on when and how to use Rust's features, and +brings attention to some of the tradeoffs between different features. + +Notably missing from this section is an in-depth discussion of Rust's pointer +types (both built-in and in the library). The topic of pointers is discussed at +length in a [separate section on ownership](../ownership/README.md). diff --git a/src/doc/style/features/crates.md b/src/doc/style/features/crates.md new file mode 100644 index 0000000000000..4748b05f17f74 --- /dev/null +++ b/src/doc/style/features/crates.md @@ -0,0 +1,6 @@ +% Crates + +> **[FIXME]** What general guidelines should we provide for crate design? + +> Possible topics: facades; per-crate preludes (to be imported as globs); +> "lib.rs" diff --git a/src/doc/style/features/functions-and-methods/README.md b/src/doc/style/features/functions-and-methods/README.md new file mode 100644 index 0000000000000..2dcfc382d0baf --- /dev/null +++ b/src/doc/style/features/functions-and-methods/README.md @@ -0,0 +1,43 @@ +% Functions and methods + +### Prefer methods to functions if there is a clear receiver. **[FIXME: needs RFC]** + +Prefer + +```rust +impl Foo { + pub fn frob(&self, w: widget) { ... } +} +``` + +over + +```rust +pub fn frob(foo: &Foo, w: widget) { ... } +``` + +for any operation that is clearly associated with a particular +type. + +Methods have numerous advantages over functions: +* They do not need to be imported or qualified to be used: all you + need is a value of the appropriate type. +* Their invocation performs autoborrowing (including mutable borrows). +* They make it easy to answer the question "what can I do with a value + of type `T`" (especially when using rustdoc). +* They provide `self` notation, which is more concise and often more + clearly conveys ownership distinctions. + +> **[FIXME]** Revisit these guidelines with +> [UFCS](https://github.com/nick29581/rfcs/blob/ufcs/0000-ufcs.md) and +> conventions developing around it. + + + +### Guidelines for inherent methods. **[FIXME]** + +> **[FIXME]** We need guidelines for when to provide inherent methods on a type, +> versus methods through a trait or functions. + +> **NOTE**: Rules for method resolution around inherent methods are in flux, +> which may impact the guidelines. diff --git a/src/doc/style/features/functions-and-methods/convenience.md b/src/doc/style/features/functions-and-methods/convenience.md new file mode 100644 index 0000000000000..69fd3772a761f --- /dev/null +++ b/src/doc/style/features/functions-and-methods/convenience.md @@ -0,0 +1,43 @@ +% Convenience methods + +### Provide small, coherent sets of convenience methods. **[FIXME: needs RFC]** + +_Convenience methods_ wrap up existing functionality in a more convenient +way. The work done by a convenience method varies widely: + +* _Re-providing functions as methods_. For example, the `std::path::Path` type + provides methods like `stat` on `Path`s that simply invoke the corresponding + function in `std::io::fs`. +* _Skipping through conversions_. For example, the `str` type provides a + `.len()` convenience method which is also expressible as `.as_bytes().len()`. + Sometimes the conversion is more complex: the `str` module also provides + `from_chars`, which encapsulates a simple use of iterators. +* _Encapsulating common arguments_. For example, vectors of `&str`s + provide a `connect` as well as a special case, `concat`, that is expressible + using `connect` with a fixed separator of `""`. +* _Providing more efficient special cases_. The `connect` and `concat` example + also applies here: singling out `concat` as a special case allows for a more + efficient implementation. + + Note, however, that the `connect` method actually detects the special case + internally and invokes `concat`. Usually, it is not necessary to add a public + convenience method just for efficiency gains; there should also be a + _conceptual_ reason to add it, e.g. because it is such a common special case. + +It is tempting to add convenience methods in a one-off, haphazard way as +common use patterns emerge. Avoid this temptation, and instead _design_ small, +coherent sets of convenience methods that are easy to remember: + +* _Small_: Avoid combinatorial explosions of convenience methods. For example, + instead of adding `_str` variants of methods that provide a `str` output, + instead ensure that the normal output type of methods is easily convertible to + `str`. +* _Coherent_: Look for small groups of convenience methods that make sense to + include together. For example, the `Path` API mentioned above includes a small + selection of the most common filesystem operations that take a `Path` + argument. If one convenience method strongly suggests the existence of others, + consider adding the whole group. +* _Memorable_: It is not worth saving a few characters of typing if you have to + look up the name of a convenience method every time you use it. Add + convenience methods with names that are obvious and easy to remember, and add + them for the most common or painful use cases. diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md new file mode 100644 index 0000000000000..b0912ea0203dc --- /dev/null +++ b/src/doc/style/features/functions-and-methods/input.md @@ -0,0 +1,201 @@ +% Input to functions and methods + +### Let the client decide when to copy and where to place data. [FIXME: needs RFC] + +#### Copying: + +Prefer + +```rust +fn foo(b: Bar) { + // use b as owned, directly +} +``` + +over + +```rust +fn foo(b: &Bar) { + let b = b.clone(); + // use b as owned after cloning +} +``` + +If a function requires ownership of a value of unknown type `T`, but does not +otherwise need to make copies, the function should take ownership of the +argument (pass by value `T`) rather than using `.clone()`. That way, the caller +can decide whether to relinquish ownership or to `clone`. + +Similarly, the `Copy` trait bound should only be demanded it when absolutely +needed, not as a way of signaling that copies should be cheap to make. + +#### Placement: + +Prefer + +```rust +fn foo(b: Bar) -> Bar { ... } +``` + +over + +```rust +fn foo(b: Box) -> Box { ... } +``` + +for concrete types `Bar` (as opposed to trait objects). This way, the caller can +decide whether to place data on the stack or heap. No overhead is imposed by +letting the caller determine the placement. + +### Minimize assumptions about parameters. [FIXME: needs RFC] + +The fewer assumptions a function makes about its inputs, the more widely usable +it becomes. + +#### Minimizing assumptions through generics: + +Prefer + +```rust +fn foo>(c: T) { ... } +``` + +over any of + +```rust +fn foo(c: &[int]) { ... } +fn foo(c: &Vec) { ... } +fn foo(c: &SomeOtherCollection) { ... } +``` + +if the function only needs to iterate over the data. + +More generally, consider using generics to pinpoint the assumptions a function +needs to make about its arguments. + +On the other hand, generics can make it more difficult to read and understand a +function's signature. Aim for "natural" parameter types that a neither overly +concrete nor overly abstract. See the discussion on +[traits](../../traits/README.md) for more guidance. + + +#### Minimizing ownership assumptions: + +Prefer either of + +```rust +fn foo(b: &Bar) { ... } +fn foo(b: &mut Bar) { ... } +``` + +over + +```rust +fn foo(b: Bar) { ... } +``` + +That is, prefer borrowing arguments rather than transferring ownership, unless +ownership is actually needed. + +### Prefer compound return types to out-parameters. [FIXME: needs RFC] + +Prefer + +```rust +fn foo() -> (Bar, Bar) +``` + +over + +```rust +fn foo(output: &mut Bar) -> Bar +``` + +for returning multiple `Bar` values. + +Compound return types like tuples and structs are efficiently compiled +and do not require heap allocation. If a function needs to return +multiple values, it should do so via one of these types. + +The primary exception: sometimes a function is meant to modify data +that the caller already owns, for example to re-use a buffer: + +```rust +fn read(&mut self, buf: &mut [u8]) -> IoResult +``` + +(From the [Reader trait](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html#tymethod.read).) + +### Consider validating arguments, statically or dynamically. [FIXME: needs RFC] + +_Note: this material is closely related to + [library-level guarantees](../../safety/lib-guarantees.md)._ + +Rust APIs do _not_ generally follow the +[robustness principle](http://en.wikipedia.org/wiki/Robustness_principle): "be +conservative in what you send; be liberal in what you accept". + +Instead, Rust code should _enforce_ the validity of input whenever practical. + +Enforcement can be achieved through the following mechanisms (listed +in order of preference). + +#### Static enforcement: + +Choose an argument type that rules out bad inputs. + +For example, prefer + +```rust +fn foo(a: ascii::Ascii) { ... } +``` + +over + +```rust +fn foo(a: u8) { ... } +``` + +Note that +[`ascii::Ascii`](http://static.rust-lang.org/doc/master/std/ascii/struct.Ascii.html) +is a _wrapper_ around `u8` that guarantees the highest bit is zero; see +[newtype patterns]() for more details on creating typesafe wrappers. + +Static enforcement usually comes at little run-time cost: it pushes the +costs to the boundaries (e.g. when a `u8` is first converted into an +`Ascii`). It also catches bugs early, during compilation, rather than through +run-time failures. + +On the other hand, some properties are difficult or impossible to +express using types. + +#### Dynamic enforcement: + +Validate the input as it is processed (or ahead of time, if necessary). Dynamic +checking is often easier to implement than static checking, but has several +downsides: + +1. Runtime overhead (unless checking can be done as part of processing the input). +2. Delayed detection of bugs. +3. Introduces failure cases, either via `fail!` or `Result`/`Option` types (see + the [error handling guidelines](../../errors/README.md)), which must then be + dealt with by client code. + +#### Dynamic enforcement with `debug_assert!`: + +Same as dynamic enforcement, but with the possibility of easily turning off +expensive checks for production builds. + +#### Dynamic enforcement with opt-out: + +Same as dynamic enforcement, but adds sibling functions that opt out of the +checking. + +The convention is to mark these opt-out functions with a suffix like +`_unchecked` or by placing them in a `raw` submodule. + +The unchecked functions can be used judiciously in cases where (1) performance +dictates avoiding checks and (2) the client is otherwise confident that the +inputs are valid. + +> **[FIXME]** Should opt-out functions be marked `unsafe`? diff --git a/src/doc/style/features/functions-and-methods/output.md b/src/doc/style/features/functions-and-methods/output.md new file mode 100644 index 0000000000000..a83e2b76bcb7f --- /dev/null +++ b/src/doc/style/features/functions-and-methods/output.md @@ -0,0 +1,56 @@ +% Output from functions and methods + +### Don't overpromise. [FIXME] + +> **[FIXME]** Add discussion of overly-specific return types, +> e.g. returning a compound iterator type rather than hiding it behind +> a use of newtype. + +### Let clients choose what to throw away. [FIXME: needs RFC] + +#### Return useful intermediate results: + +Many functions that answer a question also compute interesting related data. If +this data is potentially of interest to the client, consider exposing it in the +API. + +Prefer + +```rust +struct SearchResult { + found: bool, // item in container? + expected_index: uint // what would the item's index be? +} + +fn binary_search(&self, k: Key) -> SearchResult +``` +or + +```rust +fn binary_search(&self, k: Key) -> (bool, uint) +``` + +over + +```rust +fn binary_search(&self, k: Key) -> bool +``` + +#### Yield back ownership: + +Prefer + +```rust +fn from_utf8_owned(vv: Vec) -> Result> +``` + +over + +```rust +fn from_utf8_owned(vv: Vec) -> Option +``` + +The `from_utf8_owned` function gains ownership of a vector. In the successful +case, the function consumes its input, returning an owned string without +allocating or copying. In the unsuccessful case, however, the function returns +back ownership of the original slice. diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md new file mode 100644 index 0000000000000..87117a20d7a49 --- /dev/null +++ b/src/doc/style/features/let.md @@ -0,0 +1,103 @@ +% Let binding + +### Always separately bind RAII guards. [FIXME: needs RFC] + +Prefer + +```rust +fn use_mutex(m: sync::mutex::Mutex) { + let guard = m.lock(); + do_work(guard); + drop(guard); // unlock the lock + // do other work +} +``` + +over + +```rust +fn use_mutex(m: sync::mutex::Mutex) { + do_work(m.lock()); + // do other work +} +``` + +As explained in the [RAII guide](../ownership/raii.md), RAII guards are values +that represent ownership of some resource and whose destructor releases the +resource. Because the lifetime of guards are significant, they should always be +explicitly `let`-bound to make the lifetime clear. Consider using an explicit +`drop` to release the resource early. + +### Prefer conditional expressions to deferred initialization. [FIXME: needs RFC] + +Prefer + +```rust +let foo = match bar { + Baz => 0, + Quux => 1 +}; +``` + +over + +```rust +let foo; +match bar { + Baz => { + foo = 0; + } + Quux => { + foo = 1; + } +} +``` + +unless the conditions for initialization are too complex to fit into a simple +conditional expression. + +### Use type annotations for clarification; prefer explicit generics when inference fails. [FIXME: needs RFC] + +Prefer + +```rust +s.iter().map(|x| x * 2) + .collect::>() +``` + +over + +```rust +let v: Vec<_> = s.iter().map(|x| x * 2) + .collect(); +``` + +When the type of a value might be unclear to the _reader_ of the code, consider +explicitly annotating it in a `let`. + +On the other hand, when the type is unclear to the _compiler_, prefer to specify +the type by explicit generics instantiation, which is usually more clear. + +### Shadowing [FIXME] + +> **[FIXME]** Repeatedly shadowing a binding is somewhat common in Rust code. We +> need to articulate a guideline on when it is appropriate/useful and when not. + +### Prefer immutable bindings. [FIXME: needs RFC] + +Use `mut` bindings to signal the span during which a value is mutated: + +```rust +let mut v = Vec::new(); +// push things onto v +let v = v; +// use v immutably henceforth +``` + +### Prefer to bind all `struct` or tuple fields. [FIXME: needs RFC] + +When consuming a `struct` or tuple via a `let`, bind all of the fields rather +than using `..` to elide the ones you don't need. The benefit is that when +fields are added, the compiler will pinpoint all of the places where that type +of value was consumed, which will often need to be adjusted to take the new +field properly into account. diff --git a/src/doc/style/features/loops.md b/src/doc/style/features/loops.md new file mode 100644 index 0000000000000..b144825f98183 --- /dev/null +++ b/src/doc/style/features/loops.md @@ -0,0 +1,13 @@ +% Loops + +### Prefer `for` to `while`. [FIXME: needs RFC] + +A `for` loop is preferable to a `while` loop, unless the loop counts in a +non-uniform way (making it difficult to express using `for`). + +### Guidelines for `loop`. [FIXME] + +> **[FIXME]** When is `loop` recommended? Some possibilities: +> * For optimistic retry algorithms +> * For servers +> * To avoid mutating local variables sometimes needed to fit `while` diff --git a/src/doc/style/features/match.md b/src/doc/style/features/match.md new file mode 100644 index 0000000000000..131e0fad79a92 --- /dev/null +++ b/src/doc/style/features/match.md @@ -0,0 +1,26 @@ +% Pattern matching + +### Dereference `match` targets when possible. [FIXME: needs RFC] + +Prefer + +~~~~ +match *foo { + X(...) => ... + Y(...) => ... +} +~~~~ + +over + +~~~~ +match foo { + box X(...) => ... + box Y(...) => ... +} +~~~~ + + + + + diff --git a/src/doc/style/features/modules.md b/src/doc/style/features/modules.md new file mode 100644 index 0000000000000..04aae226f72b5 --- /dev/null +++ b/src/doc/style/features/modules.md @@ -0,0 +1,133 @@ +% Modules + +> **[FIXME]** What general guidelines should we provide for module design? + +> We should discuss visibility, nesting, `mod.rs`, and any interesting patterns +> around modules. + +### Headers [FIXME: needs RFC] + +Organize module headers as follows: + 1. [Imports](../style/imports.md). + 1. `mod` declarations. + 1. `pub mod` declarations. + +### Avoid `path` directives. [FIXME: needs RFC] + +Avoid using `#[path="..."]` directives; make the file system and +module hierarchy match, instead. + +### Use the module hirearchy to organize APIs into coherent sections. [FIXME] + +> **[FIXME]** Flesh this out with examples; explain what a "coherent +> section" is with examples. +> +> The module hirearchy defines both the public and internal API of your module. +> Breaking related functionality into submodules makes it understandable to both +> users and contributors to the module. + +### Place modules in their own file. [FIXME: needs RFC] + +> **[FIXME]** +> - "<100 lines" is arbitrary, but it's a clearer recommendation +> than "~1 page" or similar suggestions that vary by screen size, etc. + +For all except very short modules (<100 lines) and [tests](../testing/README.md), +place the module `foo` in a separate file, as in: + +```rust +pub mod foo; + +// in foo.rs or foo/mod.rs +pub fn bar() { println!("..."); } +/* ... */ +``` + +rather than declaring it inline: + +```rust +pub mod foo { + pub fn bar() { println!("..."); } + /* ... */ +} +``` + +#### Use subdirectories for modules with children. [FIXME: needs RFC] + +For modules that themselves have submodules, place the module in a separate +directory (e.g., `bar/mod.rs` for a module `bar`) rather than the same directory. + +Note the structure of +[`std::io`](http://doc.rust-lang.org/std/io/). Many of the submodules lack +children, like +[`io::fs`](http://doc.rust-lang.org/std/io/fs/) +and +[`io::stdio`](http://doc.rust-lang.org/std/io/stdio/). +On the other hand, +[`io::net`](http://doc.rust-lang.org/std/io/net/) +contains submodules, so it lives in a separate directory: + +``` +io/mod.rs + io/extensions.rs + io/fs.rs + io/net/mod.rs + io/net/addrinfo.rs + io/net/ip.rs + io/net/tcp.rs + io/net/udp.rs + io/net/unix.rs + io/pipe.rs + ... +``` + +While it is possible to define all of `io` within a single directory, +mirroring the module hirearchy in the directory structure makes +submodules of `io::net` easier to find. + +### Consider top-level definitions or reexports. [FIXME: needs RFC] + +For modules with submodules, +define or [reexport](http://doc.rust-lang.org/std/io/#reexports) commonly used +definitions at the top level: + +* Functionality relevant to the module itself or to many of its + children should be defined in `mod.rs`. +* Functionality specific to a submodule should live in that + submodule. Reexport at the top level for the most important or + common definitions. + +For example, +[`IoError`](http://doc.rust-lang.org/std/io/struct.IoError.html) +is defined in `io/mod.rs`, since it pertains to the entirety of `io`, +while +[`TcpStream`](http://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html) +is defined in `io/net/tcp.rs` and reexported in the `io` module. + +### Use internal module hirearchies for organization. [FIXME: needs RFC] + +> **[FIXME]** +> - Referencing internal modules from the standard library is subject to +> becoming outdated. + +Internal module hirearchies (i.e., private submodules) may be used to +hide implementation details that are not part of the module's API. + +For example, in [`std::io`](http://doc.rust-lang.org/std/io/), `mod mem` +provides implementations for +[`BufReader`](http://doc.rust-lang.org/std/io/struct.BufReader.html) +and +[`BufWriter`](http://doc.rust-lang.org/std/io/struct.BufWriter.html), +but these are re-exported in `io/mod.rs` at the top level of the module: + +```rust +// libstd/io/mod.rs + +pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter}; +/* ... */ +mod mem; +``` + +This hides the detail that there even exists a `mod mem` in `io`, and +helps keep code organized while offering freedom to change the +implementation. diff --git a/src/doc/style/features/traits/README.md b/src/doc/style/features/traits/README.md new file mode 100644 index 0000000000000..1893db24466fa --- /dev/null +++ b/src/doc/style/features/traits/README.md @@ -0,0 +1,22 @@ +% Traits + +Traits are probably Rust's most complex feature, supporting a wide range of use +cases and design tradeoffs. Patterns of trait usage are still emerging. + +### Know whether a trait will be used as an object. [FIXME: needs RFC] + +Trait objects have some [significant limitations](objects.md): methods +invoked through a trait object cannot use generics, and cannot use +`Self` except in receiver position. + +When designing a trait, decide early on whether the trait will be used +as an [object](objects.md) or as a [bound on generics](generics.md); +the tradeoffs are discussed in each of the linked sections. + +If a trait is meant to be used as an object, its methods should take +and return trait objects rather than use generics. + + +### Default methods [FIXME] + +> **[FIXME]** Guidelines for default methods. diff --git a/src/doc/style/features/traits/common.md b/src/doc/style/features/traits/common.md new file mode 100644 index 0000000000000..48c37eabcaaa1 --- /dev/null +++ b/src/doc/style/features/traits/common.md @@ -0,0 +1,71 @@ +% Common traits + +### Eagerly implement common traits. [FIXME: needs RFC] + +Rust's trait system does not allow _orphans_: roughly, every `impl` must live +either in the crate that defines the trait or the implementing +type. Consequently, crates that define new types should eagerly implement all +applicable, common traits. + +To see why, consider the following situation: + +* Crate `std` defines trait `Show`. +* Crate `url` defines type `Url`, without implementing `Show`. +* Crate `webapp` imports from both `std` and `url`, + +There is no way for `webapp` to add `Show` to `url`, since it defines neither. +(Note: the newtype pattern can provide an efficient, but inconvenient +workaround; see [newtype for views](../types/newtype.md)) + +The most important common traits to implement from `std` are: + +```rust +Clone, Show, Hash, Eq +``` + +#### When safe, derive or otherwise implement `Send` and `Share`. [FIXME] + +> **[FIXME]**. This guideline is in flux while the "opt-in" nature of +> built-in traits is being decided. See https://github.com/rust-lang/rfcs/pull/127 + +### Prefer to derive, rather than implement. [FIXME: needs RFC] + +Deriving saves implementation effort, makes correctness trivial, and +automatically adapts to upstream changes. + +### Do not overload operators in surprising ways. [FIXME: needs RFC] + +Operators with built in syntax (`*`, `|`, and so on) can be provided for a type +by implementing the traits in `core::ops`. These operators come with strong +expectations: implement `Mul` only for an operation that bears some resemblance +to multiplication (and shares the expected properties, e.g. associativity), and +so on for the other traits. + +### The `Drop` trait + +The `Drop` trait is treated specially by the compiler as a way of +associating destructors with types. See +[the section on destructors](../../ownership/destructors.md) for +guidance. + +### The `Deref`/`DerefMut` traits + +#### Use `Deref`/`DerefMut` only for smart pointers. [FIXME: needs RFC] + +The `Deref` traits are used implicitly by the compiler in many circumstances, +and interact with method resolution. The relevant rules are designed +specifically to accommodate smart pointers, and so the traits should be used +only for that purpose. + +#### Do not fail within a `Deref`/`DerefMut` implementation. [FIXME: needs RFC] + +Because the `Deref` traits are invoked implicitly by the compiler in sometimes +subtle ways, failure during dereferencing can be extremely confusing. If a +dereference might not succeed, target the `Deref` trait as a `Result` or +`Option` type instead. + +#### Avoid inherent methods when implementing `Deref`/`DerefMut` [FIXME: needs RFC] + +The rules around method resolution and `Deref` are in flux, but inherent methods +on a type implementing `Deref` are likely to shadow any methods of the referent +with the same name. diff --git a/src/doc/style/features/traits/extensions.md b/src/doc/style/features/traits/extensions.md new file mode 100644 index 0000000000000..fc3a03c01f5a1 --- /dev/null +++ b/src/doc/style/features/traits/extensions.md @@ -0,0 +1,7 @@ +% Using traits to add extension methods + +> **[FIXME]** Elaborate. + +### Consider using default methods rather than extension traits **[FIXME]** + +> **[FIXME]** Elaborate. diff --git a/src/doc/style/features/traits/generics.md b/src/doc/style/features/traits/generics.md new file mode 100644 index 0000000000000..ab4f9cb157961 --- /dev/null +++ b/src/doc/style/features/traits/generics.md @@ -0,0 +1,68 @@ +% Using traits for bounds on generics + +The most widespread use of traits is for writing generic functions or types. For +example, the following signature describes a function for consuming any iterator +yielding items of type `A` to produce a collection of `A`: + +```rust +fn from_iter>(iterator: T) -> SomeCollection +``` + +Here, the `Iterator` trait is specifies an interface that a type `T` must +explicitly implement to be used by this generic function. + +**Pros**: + +* _Reusability_. Generic functions can be applied to an open-ended collection of + types, while giving a clear contract for the functionality those types must + provide. +* _Static dispatch and optimization_. Each use of a generic function is + specialized ("monomorphized") to the particular types implementing the trait + bounds, which means that (1) invocations of trait methods are static, direct + calls to the implementation and (2) the compiler can inline and otherwise + optimize these calls. +* _Inline layout_. If a `struct` and `enum` type is generic over some type + parameter `T`, values of type `T` will be laid out _inline_ in the + `struct`/`enum`, without any indirection. +* _Inference_. Since the type parameters to generic functions can usually be + inferred, generic functions can help cut down on verbosity in code where + explicit conversions or other method calls would usually be necessary. See the + [overloading/implicits use case](#use-case:-limited-overloading-and/or-implicit-conversions) + below. +* _Precise types_. Because generic give a _name_ to the specific type + implementing a trait, it is possible to be precise about places where that + exact type is required or produced. For example, a function + + ```rust + fn binary(x: T, y: T) -> T + ``` + + is guaranteed to consume and produce elements of exactly the same type `T`; it + cannot be invoked with parameters of different types that both implement + `Trait`. + +**Cons**: + +* _Code size_. Specializing generic functions means that the function body is + duplicated. The increase in code size must be weighed against the performance + benefits of static dispatch. +* _Homogeneous types_. This is the other side of the "precise types" coin: if + `T` is a type parameter, it stands for a _single_ actual type. So for example + a `Vec` contains elements of a single concrete type (and, indeed, the + vector representation is specialized to lay these out in line). Sometimes + heterogeneous collections are useful; see + [trait objects](#use-case:-trait-objects) below. +* _Signature verbosity_. Heavy use of generics can bloat function signatures. + **[Ed. note]** This problem may be mitigated by some language improvements; stay tuned. + +### Favor widespread traits. **[FIXME: needs RFC]** + +Generic types are a form of abstraction, which entails a mental indirection: if +a function takes an argument of type `T` bounded by `Trait`, clients must first +think about the concrete types that implement `Trait` to understand how and when +the function is callable. + +To keep the cost of abstraction low, favor widely-known traits. Whenever +possible, implement and use traits provided as part of the standard library. Do +not introduce new traits for generics lightly; wait until there are a wide range +of types that can implement the type. diff --git a/src/doc/style/features/traits/objects.md b/src/doc/style/features/traits/objects.md new file mode 100644 index 0000000000000..38494a9b9bc3c --- /dev/null +++ b/src/doc/style/features/traits/objects.md @@ -0,0 +1,49 @@ +% Using trait objects + +> **[FIXME]** What are uses of trait objects other than heterogeneous collections? + +Trait objects are useful primarily when _heterogeneous_ collections of objects +need to be treated uniformly; it is the closest that Rust comes to +object-oriented programming. + +```rust +struct Frame { ... } +struct Button { ... } +struct Label { ... } + +trait Widget { ... } + +impl Widget for Frame { ... } +impl Widget for Button { ... } +impl Widget for Label { ... } + +impl Frame { + fn new(contents: &[Box]) -> Frame { + ... + } +} + +fn make_gui() -> Box { + let b: Box = box Button::new(...); + let l: Box = box Label::new(...); + + box Frame::new([b, l]) as Box +} +``` + +By using trait objects, we can set up a GUI framework with a `Frame` widget that +contains a heterogeneous collection of children widgets. + +**Pros**: + +* _Heterogeneity_. When you need it, you really need it. +* _Code size_. Unlike generics, trait objects do not generate specialized + (monomorphized) versions of code, which can greatly reduce code size. + +**Cons**: + +* _No generic methods_. Trait objects cannot currently provide generic methods. +* _Dynamic dispatch and fat pointers_. Trait objects inherently involve + indirection and vtable dispatch, which can carry a performance penalty. +* _No Self_. Except for the method receiver argument, methods on trait objects + cannot use the `Self` type. diff --git a/src/doc/style/features/traits/overloading.md b/src/doc/style/features/traits/overloading.md new file mode 100644 index 0000000000000..d7482c9619072 --- /dev/null +++ b/src/doc/style/features/traits/overloading.md @@ -0,0 +1,7 @@ +% Using traits for overloading + +> **[FIXME]** Elaborate. + +> **[FIXME]** We need to decide on guidelines for this use case. There are a few +> patterns emerging in current Rust code, but it's not clear how widespread they +> should be. diff --git a/src/doc/style/features/traits/reuse.md b/src/doc/style/features/traits/reuse.md new file mode 100644 index 0000000000000..6735023ae6800 --- /dev/null +++ b/src/doc/style/features/traits/reuse.md @@ -0,0 +1,30 @@ +% Using traits to share implementations + +> **[FIXME]** Elaborate. + +> **[FIXME]** We probably want to discourage this, at least when used in a way +> that is publicly exposed. + +Traits that provide default implmentations for function can provide code reuse +across types. For example, a `print` method can be defined across multiple +types as follows: + +``` Rust +trait Printable { + // Default method implementation + fn print(&self) { println!("{:?}", *self) } +} + +impl Printable for int {} + +impl Printable for String { + fn print(&self) { println!("{}", *self) } +} + +impl Printable for bool {} + +impl Printable for f32 {} +``` + +This allows the implementation of `print` to be shared across types, yet +overridden where needed, as seen in the `impl` for `String`. diff --git a/src/doc/style/features/types/README.md b/src/doc/style/features/types/README.md new file mode 100644 index 0000000000000..c675eb581c6ae --- /dev/null +++ b/src/doc/style/features/types/README.md @@ -0,0 +1,68 @@ +% Data types + +### Use custom types to imbue meaning; do not abuse `bool`, `Option` or other core types. **[FIXME: needs RFC]** + +Prefer + +```rust +let w = Widget::new(Small, Round) +``` + +over + +```rust +let w = Widget::new(true, false) +``` + +Core types like `bool`, `u8` and `Option` have many possible interpretations. + +Use custom types (whether `enum`s, `struct`, or tuples) to convey +interpretation and invariants. In the above example, +it is not immediately clear what `true` and `false` are conveying without +looking up the argument names, but `Small` and `Round` are more suggestive. + +Using custom types makes it easier to expand the +options later on, for example by adding an `ExtraLarge` variant. + +See [the newtype pattern](newtype.md) for a no-cost way to wrap +existing types with a distinguished name. + +### Prefer private fields, except for passive data. **[FIXME: needs RFC]** + +Making a field public is a strong commitment: it pins down a representation +choice, _and_ prevents the type from providing any validation or maintaining any +invariants on the contents of the field, since clients can mutate it arbitrarily. + +Public fields are most appropriate for `struct` types in the C spirit: compound, +passive data structures. Otherwise, consider providing getter/setter methods +and hiding fields instead. + +> **[FIXME]** Cross-reference validation for function arguments. + +### Use custom `enum`s for alternatives, `bitflags` for C-style flags. **[FIXME: needs RFC]** + +Rust supports `enum` types with "custom discriminants": + +~~~~ +enum Color { + Red = 0xff0000, + Green = 0x00ff00, + Blue = 0x0000ff +} +~~~~ + +Custom discriminants are useful when an `enum` type needs to be serialized to an +integer value compatibly with some other system/language. They support +"typesafe" APIs: by taking a `Color`, rather than an integer, a function is +guaranteed to get well-formed inputs, even if it later views those inputs as +integers. + +An `enum` allows an API to request exactly one choice from among many. Sometimes +an API's input is instead the presence or absence of a set of flags. In C code, +this is often done by having each flag correspond to a particular bit, allowing +a single integer to represent, say, 32 or 64 flags. Rust's `std::bitflags` +module provides a typesafe way for doing so. + +### Phantom types. [FIXME] + +> **[FIXME]** Add some material on phantom types (https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/) diff --git a/src/doc/style/features/types/conversions.md b/src/doc/style/features/types/conversions.md new file mode 100644 index 0000000000000..f0f230f57e557 --- /dev/null +++ b/src/doc/style/features/types/conversions.md @@ -0,0 +1,22 @@ +% Conversions between types + +### Associate conversions with the most specific type involved. **[FIXME: needs RFC]** + +When in doubt, prefer `to_`/`as_`/`into_` to `from_`, because they are +more ergonomic to use (and can be chained with other methods). + +For many conversions between two types, one of the types is clearly more +"specific": it provides some additional invariant or interpretation that is not +present in the other type. For example, `str` is more specific than `&[u8]`, +since it is a utf-8 encoded sequence of bytes. + +Conversions should live with the more specific of the involved types. Thus, +`str` provides both the `as_bytes` method and the `from_utf8` constructor for +converting to and from `&[u8]` values. Besides being intuitive, this convention +avoids polluting concrete types like `&[u8]` with endless conversion methods. + +### Explicitly mark lossy conversions, or do not label them as conversions. **[FIXME: needs RFC]** + +If a function's name implies that it is a conversion (prefix `from_`, `as_`, +`to_` or `into_`), but the function loses information, add a suffix `_lossy` or +otherwise indicate the lossyness. Consider avoiding the conversion name prefix. diff --git a/src/doc/style/features/types/newtype.md b/src/doc/style/features/types/newtype.md new file mode 100644 index 0000000000000..60c17fc2a52e2 --- /dev/null +++ b/src/doc/style/features/types/newtype.md @@ -0,0 +1,69 @@ +% The newtype pattern + +A "newtype" is a tuple or `struct` with a single field. The terminology is borrowed from Haskell. + +Newtypes are a zero-cost abstraction: they introduce a new, distinct name for an +existing type, with no runtime overhead when converting between the two types. + +### Use newtypes to provide static distinctions. [FIXME: needs RFC] + +Newtypes can statically distinguish between different interpretations of an +underlying type. + +For example, a `f64` value might be used to represent a quantity in miles or in +kilometers. Using newtypes, we can keep track of the intended interpretation: + +```rust +struct Miles(pub f64); +struct Kilometers(pub f64); + +impl Miles { + fn as_kilometers(&self) -> Kilometers { ... } +} +impl Kilometers { + fn as_miles(&self) -> Miles { ... } +} +``` + +Once we have separated these two types, we can statically ensure that we do not +confuse them. For example, the function + +```rust +fn are_we_there_yet(distance_travelled: Miles) -> bool { ... } +``` + +cannot accidentally be called with a `Kilometers` value. The compiler will +remind us to perform the conversion, thus averting certain +[catastrophic bugs](http://en.wikipedia.org/wiki/Mars_Climate_Orbiter). + +### Use newtypes with private fields for hiding. [FIXME: needs RFC] + +A newtype can be used to hide representation details while making precise +promises to the client. + +For example, consider a function `my_transform` that returns a compound iterator +type `Enumerate>>`. We wish to hide this type from the +client, so that the client's view of the return type is roughly `Iterator<(uint, +T)>`. We can do so using the newtype pattern: + +```rust +struct MyTransformResult(Enumerate>>); +impl Iterator<(uint, T)> for MyTransformResult { ... } + +fn my_transform>(iter: Iter) -> MyTransformResult { + ... +} +``` + +Aside from simplifying the signature, this use of newtypes allows us to make a +expose and promise less to the client. The client does not know _how_ the result +iterator is constructed or represented, which means the representation can +change in the future without breaking client code. + +> **[FIXME]** Interaction with auto-deref. + +### Use newtypes to provide cost-free _views_ of another type. **[FIXME]** + +> **[FIXME]** Describe the pattern of using newtypes to provide a new set of +> inherent or trait methods, providing a different perspective on the underlying +> type. diff --git a/src/doc/style/ownership/README.md b/src/doc/style/ownership/README.md new file mode 100644 index 0000000000000..11bdb03a3a818 --- /dev/null +++ b/src/doc/style/ownership/README.md @@ -0,0 +1,3 @@ +% Ownership and resource management + +> **[FIXME]** Add general remarks about ownership/resources here. diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md new file mode 100644 index 0000000000000..94eda59b95b65 --- /dev/null +++ b/src/doc/style/ownership/builders.md @@ -0,0 +1,176 @@ +% The builder pattern + +Some data structures are complicated to construct, due to their construction needing: + +* a large number of inputs +* compound data (e.g. slices) +* optional configuration data +* choice between several flavors + +which can easily lead to a large number of distinct constructors with +many arguments each. + +If `T` is such a data structure, consider introducing a `T` _builder_: + +1. Introduce a separate data type `TBuilder` for incrementally configuring a `T` + value. When possible, choose a better name: e.g. `Command` is the builder for + `Process`. +2. The builder constructor should take as parameters only the data _required_ to + to make a `T`. +3. The builder should offer a suite of convenient methods for configuration, + including setting up compound inputs (like slices) incrementally. + These methods should return `self` to allow chaining. +4. The builder should provide one or more "_terminal_" methods for actually building a `T`. + +The builder pattern is especially appropriate when building a `T` involves side +effects, such as spawning a task or launching a process. + +In Rust, there are two variants of the builder pattern, differing in the +treatment of ownership, as described below. + +### Non-consuming builders (preferred): + +In some cases, constructing the final `T` does not require the builder itself to +be consumed. The follow variant on +[`std::io::process::Command`](http://static.rust-lang.org/doc/master/std/io/process/struct.Command.html) +is one example: + +```rust +// NOTE: the actual Command API does not use owned Strings; +// this is a simplified version. + +pub struct Command { + program: String, + args: Vec, + cwd: Option, + // etc +} + +impl Command { + pub fn new(program: String) -> Command { + Command { + program: program, + args: Vec::new(), + cwd: None, + } + } + + /// Add an argument to pass to the program. + pub fn arg<'a>(&'a mut self, arg: String) -> &'a mut Command { + self.args.push(arg); + self + } + + /// Add multiple arguments to pass to the program. + pub fn args<'a>(&'a mut self, args: &[String]) + -> &'a mut Command { + self.args.push_all(args); + self + } + + /// Set the working directory for the child process. + pub fn cwd<'a>(&'a mut self, dir: String) -> &'a mut Command { + self.cwd = Some(dir); + self + } + + /// Executes the command as a child process, which is returned. + pub fn spawn(&self) -> IoResult { + ... + } +} +``` + +Note that the `spawn` method, which actually uses the builder configuration to +spawn a process, takes the builder by immutable reference. This is possible +because spawning the process does not require ownership of the configuration +data. + +Because the terminal `spawn` method only needs a reference, the configuration +methods take and return a mutable borrow of `self`. + +#### The benefit + +By using borrows throughout, `Command` can be used conveniently for both +one-liner and more complex constructions: + +```rust +// One-liners +Command::new("/bin/cat").arg("file.txt").spawn(); + +// Complex configuration +let mut cmd = Command::new("/bin/ls"); +cmd.arg("."); + +if size_sorted { + cmd.arg("-S"); +} + +cmd.spawn(); +``` + +### Consuming builders: + +Sometimes builders must transfer ownership when constructing the final type +`T`, meaning that the terminal methods must take `self` rather than `&self`: + +```rust +// A simplified excerpt from std::task::TaskBuilder + +impl TaskBuilder { + /// Name the task-to-be. Currently the name is used for identification + /// only in failure messages. + pub fn named(mut self, name: String) -> TaskBuilder { + self.name = Some(name); + self + } + + /// Redirect task-local stdout. + pub fn stdout(mut self, stdout: Box) -> TaskBuilder { + self.stdout = Some(stdout); + // ^~~~~~ this is owned and cannot be cloned/re-used + self + } + + /// Creates and executes a new child task. + pub fn spawn(self, f: proc():Send) { + // consume self + ... + } +} +``` + +Here, the `stdout` configuration involves passing ownership of a `Writer`, +which must be transferred to the task upon construction (in `spawn`). + +When the terminal methods of the builder require ownership, there is a basic tradeoff: + +* If the other builder methods take/return a mutable borrow, the complex + configuration case will work well, but one-liner configuration becomes + _impossible_. + +* If the other builder methods take/return an owned `self`, one-liners + continue to work well but complex configuration is less convenient. + +Under the rubric of making easy things easy and hard things possible, _all_ +builder methods for a consuming builder should take and returned an owned +`self`. Then client code works as follows: + +```rust +// One-liners +TaskBuilder::new().named("my_task").spawn(proc() { ... }); + +// Complex configuration +let mut task = TaskBuilder::new(); +task = task.named("my_task_2"); // must re-assign to retain ownership + +if reroute { + task = task.stdout(mywriter); +} + +task.spawn(proc() { ... }); +``` + +One-liners work as before, because ownership is threaded through each of the +builder methods until being consumed by `spawn`. Complex configuration, +however, is more verbose: it requires re-assigning the builder at each step. diff --git a/src/doc/style/ownership/cell-smart.md b/src/doc/style/ownership/cell-smart.md new file mode 100644 index 0000000000000..cd027cc4aaffc --- /dev/null +++ b/src/doc/style/ownership/cell-smart.md @@ -0,0 +1,4 @@ +% Cells and smart pointers + +> **[FIXME]** Add guidelines about when to use Cell, RefCell, Rc and +> Arc (and how to use them together). diff --git a/src/doc/style/ownership/constructors.md b/src/doc/style/ownership/constructors.md new file mode 100644 index 0000000000000..b4a1147315679 --- /dev/null +++ b/src/doc/style/ownership/constructors.md @@ -0,0 +1,62 @@ +% Constructors + +### Define constructors as static, inherent methods. [FIXME: needs RFC] + +In Rust, "constructors" are just a convention: + +```rust +impl Vec { + pub fn new() -> Vec { ... } +} +``` + +Constructors are static (no `self`) inherent methods for the type that they +construct. Combined with the practice of +[fully importing type names](../style/imports.md), this convention leads to +informative but concise construction: + +```rust +use vec::Vec; + +// construct a new vector +let mut v = Vec::new(); +``` + +This convention also applied to conversion constructors (prefix `from` rather +than `new`). + +### Provide constructors for passive `struct`s with defaults. [FIXME: needs RFC] + +Given the `struct` + +```rust +pub struct Config { + pub color: Color, + pub size: Size, + pub shape: Shape, +} +``` + +provide a constructor if there are sensible defaults: + +```rust +impl Config { + pub fn new() -> Config { + Config { + color: Brown, + size: Medium, + shape: Square, + } + } +} +``` + +which then allows clients to concisely override using `struct` update syntax: + +```rust +Config { color: Red, .. Config::new() }; +``` + +See the [guideline for field privacy](../features/types/README.md) for +discussion on when to create such "passive" `struct`s with public +fields. diff --git a/src/doc/style/ownership/destructors.md b/src/doc/style/ownership/destructors.md new file mode 100644 index 0000000000000..8f58aa6c6d2f1 --- /dev/null +++ b/src/doc/style/ownership/destructors.md @@ -0,0 +1,22 @@ +% Destructors + +Unlike constructors, destructors in Rust have a special status: they are added +by implementing `Drop` for a type, and they are automatically invoked as values +go out of scope. + +> **[FIXME]** This section needs to be expanded. + +### Destructors should not fail. [FIXME: needs RFC] + +Destructors are executed on task failure, and in that context a failing +destructor causes the program to abort. + +Instead of failing in a destructor, provide a separate method for checking for +clean teardown, e.g. a `close` method, that returns a `Result` to signal +problems. + +### Destructors should not block. [FIXME: needs RFC] + +Similarly, destructors should not invoke blocking operations, which can make +debugging much more difficult. Again, consider providing a separate method for +preparing for an infallible, nonblocking teardown. diff --git a/src/doc/style/ownership/raii.md b/src/doc/style/ownership/raii.md new file mode 100644 index 0000000000000..244e8096a1a2f --- /dev/null +++ b/src/doc/style/ownership/raii.md @@ -0,0 +1,12 @@ +% RAII + +Resource Acquisition is Initialization + +> **[FIXME]** Explain the RAII pattern and give best practices. + +### Whenever possible, tie resource access to guard scopes [FIXME] + +> **[FIXME]** Example: Mutex guards guarantee that access to the +> protected resource only happens when the guard is in scope. + +`must_use` diff --git a/src/doc/style/platform.md b/src/doc/style/platform.md new file mode 100644 index 0000000000000..d29d060b69461 --- /dev/null +++ b/src/doc/style/platform.md @@ -0,0 +1,7 @@ +% FFI and platform-specific code **[FIXME]** + +> **[FIXME]** Not sure where this should live. + +When writing cross-platform code, group platform-specific code into a +module called `platform`. Avoid `#[cfg]` directives outside this +`platform` module. diff --git a/src/doc/style/safety/README.md b/src/doc/style/safety/README.md new file mode 100644 index 0000000000000..1ac6e704d23eb --- /dev/null +++ b/src/doc/style/safety/README.md @@ -0,0 +1,19 @@ +% Safety and guarantees + +> **[FIXME]** Is there a better phrase than "strong guarantees" that encompasses +> both e.g. memory safety and e.g. data structure invariants? + +A _guarantee_ is a property that holds no matter what client code does, unless +the client explicitly opts out: + +* Rust guarantees memory safety and data-race freedom, with `unsafe` + blocks as an opt-out mechanism. + +* APIs in Rust often provide their own guarantees. For example, `std::str` +guarantees that its underlying buffer is valid utf-8. The `std::path::Path` type +guarantees no interior nulls. Both strings and paths provide `unsafe` mechanisms +for opting out of these guarantees (and thereby avoiding runtime checks). + +Thinking about guarantees is an essential part of writing good Rust code. The +rest of this subsection outlines some cross-cutting principles around +guarantees. diff --git a/src/doc/style/safety/lib-guarantees.md b/src/doc/style/safety/lib-guarantees.md new file mode 100644 index 0000000000000..aa87223383a10 --- /dev/null +++ b/src/doc/style/safety/lib-guarantees.md @@ -0,0 +1,81 @@ +% Library-level guarantees + +Most libraries rely on internal invariants, e.g. about their data, resource +ownership, or protocol states. In Rust, broken invariants cannot produce +segfaults, but they can still lead to wrong answers. + +### Provide library-level guarantees whenever practical. **[FIXME: needs RFC]** + +Library-level invariants should be turned into guarantees whenever +practical. They should hold no matter what the client does, modulo +explicit opt-outs. Depending on the kind of invariant, this can be +achieved through a combination of static and dynamic enforcement, as +described below. + +#### Static enforcement: + +Guaranteeing invariants almost always requires _hiding_, +i.e. preventing the client from directly accessing or modifying +internal data. + +For example, the representation of the `str` type is hidden, +which means that any value of type `str` must have been produced +through an API under the control of the `str` module, and these +APIs in turn ensure valid utf-8 encoding. + +Rust's type system makes it possible to provide guarantees even while +revealing more of the representation than usual. For example, the +`as_bytes()` method on `&str` gives a _read-only_ view into the +underlying buffer, which cannot be used to violate the utf-8 property. + +#### Dynamic enforcement: + +Malformed inputs from the client are hazards to library-level +guarantees, so library APIs should validate their input. + +For example, `std::str::from_utf8_owned` attempts to convert a `u8` +slice into an owned string, but dynamically checks that the slice is +valid utf-8 and returns `Err` if not. + +See +[the discussion on input validation](../features/functions-and-methods/input.md) +for more detail. + + +### Prefer static enforcement of guarantees. **[FIXME: needs RFC]** + +Static enforcement provides two strong benefits over dynamic enforcement: + +* Bugs are caught at compile time. +* There is no runtime cost. + +Sometimes purely static enforcement is impossible or impractical. In these +cases, a library should check as much as possible statically, but defer to +dynamic checks where needed. + +For example, the `std::string` module exports a `String` type with the guarantee +that all instances are valid utf-8: + +* Any _consumer_ of a `String` is statically guaranteed utf-8 contents. For example, + the `append` method can push a `&str` onto the end of a `String` without + checking anything dynamically, since the existing `String` and `&str` are + statically guaranteed to be in utf-8. + +* Some _producers_ of a `String` must perform dynamic checks. For example, the + `from_utf8` function attempts to convert a `Vec` into a `String`, but + dynamically checks that the contents are utf-8. + +### Provide opt-outs with caution; make them explicit. **[FIXME: needs RFC]** + +Providing library-level guarantees sometimes entails inconvenience (for static +checks) or overhead (for dynamic checks). So it is sometimes desirable to allow +clients to sidestep this checking, while promising to use the API in a way that +still provides the guarantee. Such escape hatches should only be be introduced +when there is a demonstrated need for them. + +It should be trivial for clients to audit their use of the library for +escape hatches. + +See +[the discussion on input validation](../features/functions-and-methods/input.md) +for conventions on marking opt-out functions. diff --git a/src/doc/style/safety/unsafe.md b/src/doc/style/safety/unsafe.md new file mode 100644 index 0000000000000..a8a50af044c29 --- /dev/null +++ b/src/doc/style/safety/unsafe.md @@ -0,0 +1,22 @@ +% Using `unsafe` + +### Unconditionally guarantee safety, or mark API as `unsafe`. **[FIXME: needs RFC]** + +Memory safety, type safety, and data race freedom are basic assumptions for all +Rust code. + +APIs that use `unsafe` blocks internally thus have two choices: + +* They can guarantee safety _unconditionally_ (i.e., regardless of client + behavior or inputs) and be exported as safe code. Any safety violation is then + the library's fault, not the client's fault. + +* They can export potentially unsafe functions with the `unsafe` qualifier. In + this case, the documentation should make very clear the conditions under which + safety is guaranteed. + +The result is that a client program can never violate safety merely by having a +bug; it must have explicitly opted out by using an `unsafe` block. + +Of the two options for using `unsafe`, creating such safe abstractions (the +first option above) is strongly preferred. diff --git a/src/doc/style/style/README.md b/src/doc/style/style/README.md new file mode 100644 index 0000000000000..87449710543c0 --- /dev/null +++ b/src/doc/style/style/README.md @@ -0,0 +1,5 @@ +% Style + +This section gives a set of strict rules for styling Rust code. + +> **[FIXME]** General remarks about the style guidelines diff --git a/src/doc/style/style/braces.md b/src/doc/style/style/braces.md new file mode 100644 index 0000000000000..0f61bac9fd229 --- /dev/null +++ b/src/doc/style/style/braces.md @@ -0,0 +1,77 @@ +% Braces, semicolons, and commas [FIXME: needs RFC] + +### Opening braces always go on the same line. + +``` rust +fn foo() { + ... +} + +fn frobnicate(a: Bar, b: Bar, + c: Bar, d: Bar) + -> Bar { + ... +} + +trait Bar { + fn baz(&self); +} + +impl Bar for Baz { + fn baz(&self) { + ... + } +} + +frob(|x| { + x.transpose() +}) +``` + +### `match` arms get braces, except for single-line expressions. + +``` rust +match foo { + bar => baz, + quux => { + do_something(); + do_something_else() + } +} +``` + +### `return` statements get semicolons. + +``` rust +fn foo() { + do_something(); + + if condition() { + return; + } + + do_something_else(); +} +``` + +### Trailing commas + +> **[FIXME]** We should have a guideline for when to include trailing +> commas in `struct`s, `match`es, function calls, etc. +> +> One possible rule: a trailing comma should be included whenever the +> closing delimiter appears on a separate line: + +```rust +Foo { bar: 0, baz: 1 } + +Foo { + bar: 0, + baz: 1, +} + +match a_thing { + None => 0, + Some(x) => 1, +} +``` diff --git a/src/doc/style/style/comments.md b/src/doc/style/style/comments.md new file mode 100644 index 0000000000000..347750ce6020d --- /dev/null +++ b/src/doc/style/style/comments.md @@ -0,0 +1,87 @@ +% Comments [FIXME: needs RFC] + +### Avoid block comments. + +Use line comments: + +``` rust +// Wait for the main task to return, and set the process error code +// appropriately. +``` + +Instead of: + +``` rust +/* + * Wait for the main task to return, and set the process error code + * appropriately. + */ +``` + +## Doc comments + +Doc comments are prefixed by three slashes (`///`) and indicate +documentation that you would like to be included in Rustdoc's output. +They support +[Markdown syntax](https://en.wikipedia.org/wiki/Markdown) +and are the main way of documenting your public APIs. + +The supported markdown syntax includes all of the extensions listed in the +[GitHub Flavored Markdown] +(https://help.github.com/articles/github-flavored-markdown) documentation, +plus superscripts. + +### Summary line + +The first line in any doc comment should be a single-line short sentence +providing a summary of the code. This line is used as a short summary +description throughout Rustdoc's output, so it's a good idea to keep it +short. + +### Sentence structure + +All doc comments, including the summary line, should begin with a +capital letter and end with a period, question mark, or exclamation +point. Prefer full sentences to fragments. + +The summary line should be written in +[third person singular present indicative form] +(http://en.wikipedia.org/wiki/English_verbs#Third_person_singular_present). +Basically, this means write "Returns" instead of "Return". + +For example: + +``` rust +/// Sets up a default runtime configuration, given compiler-supplied arguments. +/// +/// This function will block until the entire pool of M:N schedulers has +/// exited. This function also requires a local task to be available. +/// +/// # Arguments +/// +/// * `argc` & `argv` - The argument vector. On Unix this information is used +/// by `os::args`. +/// * `main` - The initial procedure to run inside of the M:N scheduling pool. +/// Once this procedure exits, the scheduling pool will begin to shut +/// down. The entire pool (and this function) will only return once +/// all child tasks have finished executing. +/// +/// # Return value +/// +/// The return value is used as the process return code. 0 on success, 101 on +/// error. +``` + +### Code snippets + +> **[FIXME]** + +### Avoid inner doc comments. + +Use inner doc comments _only_ to document crates and file-level modules: + +``` rust +//! The core library. +//! +//! The core library is a something something... +``` diff --git a/src/doc/style/style/features.md b/src/doc/style/style/features.md new file mode 100644 index 0000000000000..f73517c2b9c3b --- /dev/null +++ b/src/doc/style/style/features.md @@ -0,0 +1,13 @@ +## `return` [FIXME: needs RFC] + +Terminate `return` statements with semicolons: + +``` rust +fn foo(bar: int) -> Option { + if some_condition() { + return None; + } + + ... +} +``` diff --git a/src/doc/style/style/imports.md b/src/doc/style/style/imports.md new file mode 100644 index 0000000000000..207a3fd7f8d16 --- /dev/null +++ b/src/doc/style/style/imports.md @@ -0,0 +1,50 @@ +% Imports [FIXME: needs RFC] + +The imports of a crate/module should consist of the following +sections, in order, with a blank space between each: + +* `extern crate` directives +* external `use` imports +* local `use` imports +* `pub use` imports + +For example: + +```rust +// Crates. +extern crate getopts; +extern crate mylib; + +// Standard library imports. +use getopts::{optopt, getopts}; +use std::os; + +// Import from a library that we wrote. +use mylib::webserver; + +// Will be reexported when we import this module. +pub use self::types::Webdata; +``` + +### Avoid `use *`, except in tests. + +Glob imports have several downsides: +* They make it harder to tell where names are bound. +* They are forwards-incompatible, since new upstream exports can clash + with existing names. + +When writing a [`test` submodule](../testing/README.md), importing `super::*` is appropriate +as a convenience. + +### Prefer fully importing types/traits while module-qualifying functions. + +For example: + +```rust +use option::Option; +use mem; + +let i: int = mem::transmute(Option(0)); +``` + +> **[FIXME]** Add rationale. diff --git a/src/doc/style/style/naming/README.md b/src/doc/style/style/naming/README.md new file mode 100644 index 0000000000000..9d78721ad3644 --- /dev/null +++ b/src/doc/style/style/naming/README.md @@ -0,0 +1,115 @@ +% Naming conventions + +### General conventions [RFC #430] + +> The guidelines below were approved by [RFC #430](https://github.com/rust-lang/rfcs/pull/430). + +In general, Rust tends to use `CamelCase` for "type-level" constructs +(types and traits) and `snake_case` for "value-level" constructs. More +precisely: + +| Item | Convention | +| ---- | ---------- | +| Crates | `snake_case` (but prefer single word) | +| Modules | `snake_case` | +| Types | `CamelCase` | +| Traits | `CamelCase` | +| Enum variants | `CamelCase` | +| Functions | `snake_case` | +| Methods | `snake_case` | +| General constructors | `new` or `with_more_details` | +| Conversion constructors | `from_some_other_type` | +| Local variables | `snake_case` | +| Static variables | `SCREAMING_SNAKE_CASE` | +| Constant variables | `SCREAMING_SNAKE_CASE` | +| Type parameters | concise `CamelCase`, usually single uppercase letter: `T` | +| Lifetimes | short, lowercase: `'a` | + +

+In `CamelCase`, acronyms count as one word: use `Uuid` rather than +`UUID`. In `snake_case`, acronyms are lower-cased: `is_xid_start`. + +In `snake_case` or `SCREAMING_SNAKE_CASE`, a "word" should never +consist of a single letter unless it is the last "word". So, we have +`btree_map` rather than `b_tree_map`, but `PI_2` rather than `PI2`. + +### Referring to types in function/method names [RFC 344] + +> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344). + +Function names often involve type names, the most common example being conversions +like `as_slice`. If the type has a purely textual name (ignoring parameters), it +is straightforward to convert between type conventions and function conventions: + +Type name | Text in methods +--------- | --------------- +`String` | `string` +`Vec` | `vec` +`YourType`| `your_type` + +Types that involve notation follow the convention below. There is some +overlap on these rules; apply the most specific applicable rule: + +Type name | Text in methods +--------- | --------------- +`&str` | `str` +`&[T]` | `slice` +`&mut [T]`| `mut_slice` +`&[u8]` | `bytes` +`&T` | `ref` +`&mut T` | `mut` +`*const T`| `ptr` +`*mut T` | `mut_ptr` + +### Avoid redundant prefixes [RFC 356] + +> The guidelines below were approved by [RFC #356](https://github.com/rust-lang/rfcs/pull/356). + +Names of items within a module should not be prefixed with that module's name: + +Prefer + +``` rust +mod foo { + pub struct Error { ... } +} +``` + +over + +``` rust +mod foo { + pub struct FooError { ... } +} +``` + +This convention avoids stuttering (like `io::IoError`). Library clients can +rename on import to avoid clashes. + +### Getter/setter methods [RFC 344] + +> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344). + +Some data structures do not wish to provide direct access to their fields, but +instead offer "getter" and "setter" methods for manipulating the field state +(often providing checking or other functionality). + +The convention for a field `foo: T` is: + +* A method `foo(&self) -> &T` for getting the current value of the field. +* A method `set_foo(&self, val: T)` for setting the field. (The `val` argument + here may take `&T` or some other type, depending on the context.) + +Note that this convention is about getters/setters on ordinary data types, *not* +on [builder objects](../ownership/builders.html). + +### Escape hatches [FIXME] + +> **[FIXME]** Should we standardize a convention for functions that may break API +> guarantees? e.g. `ToCStr::to_c_str_unchecked` + +### Predicates + +* Simple boolean predicates should be prefixed with `is_` or another + short question word, e.g., `is_empty`. +* Common exceptions: `lt`, `gt`, and other established predicate names. diff --git a/src/doc/style/style/naming/containers.md b/src/doc/style/style/naming/containers.md new file mode 100644 index 0000000000000..04204f0f88aec --- /dev/null +++ b/src/doc/style/style/naming/containers.md @@ -0,0 +1,69 @@ +% Common container/wrapper methods [FIXME: needs RFC] + +Containers, wrappers, and cells all provide ways to access the data +they enclose. Accessor methods often have variants to access the data +by value, by reference, and by mutable reference. + +In general, the `get` family of methods is used to access contained +data without any risk of task failure; they return `Option` as +appropriate. This name is chosen rather than names like `find` or +`lookup` because it is appropriate for a wider range of container types. + +#### Containers + +For a container with keys/indexes of type `K` and elements of type `V`: + +```rust +// Look up element without failing +fn get(&self, key: K) -> Option<&V> +fn get_mut(&mut self, key: K) -> Option<&mut V> + +// Convenience for .get(key).map(|elt| elt.clone()) +fn get_clone(&self, key: K) -> Option + +// Lookup element, failing if it is not found: +impl Index for Container { ... } +impl IndexMut for Container { ... } +``` + +#### Wrappers/Cells + +Prefer specific conversion functions like `as_bytes` or `into_vec` whenever +possible. Otherwise, use: + +```rust +// Extract contents without failing +fn get(&self) -> &V +fn get_mut(&mut self) -> &mut V +fn unwrap(self) -> V +``` + +#### Wrappers/Cells around `Copy` data + +```rust +// Extract contents without failing +fn get(&self) -> V +``` + +#### `Option`-like types + +Finally, we have the cases of types like `Option` and `Result`, which +play a special role for failure. + +For `Option`: + +```rust +// Extract contents or fail if not available +fn assert(self) -> V +fn expect(self, &str) -> V +``` + +For `Result`: + +```rust +// Extract the contents of Ok variant; fail if Err +fn assert(self) -> V + +// Extract the contents of Err variant; fail if Ok +fn assert_err(self) -> E +``` diff --git a/src/doc/style/style/naming/conversions.md b/src/doc/style/style/naming/conversions.md new file mode 100644 index 0000000000000..0287919c78aae --- /dev/null +++ b/src/doc/style/style/naming/conversions.md @@ -0,0 +1,32 @@ +% Conversions [Rust issue #7087] + +> The guidelines below were approved by [rust issue #7087](https://github.com/rust-lang/rust/issues/7087). + +> **[FIXME]** Should we provide standard traits for conversions? Doing +> so nicely will require +> [trait reform](https://github.com/rust-lang/rfcs/pull/48) to land. + +Conversions should be provided as methods, with names prefixed as follows: + +| Prefix | Cost | Consumes convertee | +| ------ | ---- | ------------------ | +| `as_` | Free | No | +| `to_` | Expensive | No | +| `into_` | Variable | Yes | + +

+For example: + +* `as_bytes()` gives a `&[u8]` view into a `&str`, which is a no-op. +* `to_owned()` copies a `&str` to a new `String`. +* `into_bytes()` consumes a `String` and yields the underlying + `Vec`, which is a no-op. + +Conversions prefixed `as_` and `into_` typically _decrease abstraction_, either +exposing a view into the underlying representation (`as`) or deconstructing data +into its underlying representation (`into`). Conversions prefixed `to_`, on the +other hand, typically stay at the same level of abstraction but do some work to +change one representation into another. + +> **[FIXME]** The distinctions between conversion methods does not work +> so well for `from_` conversion constructors. Is that a problem? diff --git a/src/doc/style/style/naming/iterators.md b/src/doc/style/style/naming/iterators.md new file mode 100644 index 0000000000000..38138b5e39d3a --- /dev/null +++ b/src/doc/style/style/naming/iterators.md @@ -0,0 +1,32 @@ +% Iterators + +#### Method names [RFC #199] + +> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199). + +For a container with elements of type `U`, iterator methods should be named: + +```rust +fn iter(&self) -> T // where T implements Iterator<&U> +fn iter_mut(&mut self) -> T // where T implements Iterator<&mut U> +fn into_iter(self) -> T // where T implements Iterator +``` + +The default iterator variant yields shared references `&U`. + +#### Type names [RFC #344] + +> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344). + +The name of an iterator type should be the same as the method that +produces the iterator. + +For example: + +* `iter` should yield an `Iter` +* `iter_mut` should yield an `IterMut` +* `into_iter` should yield an `IntoIter` +* `keys` should yield `Keys` + +These type names make the most sense when prefixed with their owning module, +e.g. `vec::IntoIter`. diff --git a/src/doc/style/style/naming/ownership.md b/src/doc/style/style/naming/ownership.md new file mode 100644 index 0000000000000..32cd8a1595afb --- /dev/null +++ b/src/doc/style/style/naming/ownership.md @@ -0,0 +1,34 @@ +% Ownership variants [RFC #199] + +> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199). + +Functions often come in multiple variants: immutably borrowed, mutably +borrowed, and owned. + +The right default depends on the function in question. Variants should +be marked through suffixes. + +#### Immutably borrowed by default + +If `foo` uses/produces an immutable borrow by default, use: + +* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant. +* The `_move` suffix (e.g. `foo_move`) for the owned variant. + +#### Owned by default + +If `foo` uses/produces owned data by default, use: + +* The `_ref` suffix (e.g. `foo_ref`) for the immutably borrowed variant. +* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant. + +#### Exceptions + +In the case of iterators, the moving variant can also be understood as +an `into` conversion, `into_iter`, and `for x in v.into_iter()` reads +arguably better than `for x in v.iter_move()`, so the convention is +`into_iter`. + +For mutably borrowed variants, if the `mut` qualifier is part of a +type name (e.g. `as_mut_slice`), it should appear as it would appear +in the type. diff --git a/src/doc/style/style/optional.md b/src/doc/style/style/optional.md new file mode 100644 index 0000000000000..d3c2178cc993f --- /dev/null +++ b/src/doc/style/style/optional.md @@ -0,0 +1,3 @@ +* + +* diff --git a/src/doc/style/style/organization.md b/src/doc/style/style/organization.md new file mode 100644 index 0000000000000..85065406d761c --- /dev/null +++ b/src/doc/style/style/organization.md @@ -0,0 +1,14 @@ +% Organization [FIXME: needs RFC] + +> **[FIXME]** What else? + +### Reexport the most important types at the crate level. + +Crates `pub use` the most common types for convenience, so that clients do not +have to remember or write the crate's module hierarchy to use these types. + +### Define types and operations together. + +Type definitions and the functions/methods that operate on them should be +defined together in a single module, with the type appearing above the +functions/methods. diff --git a/src/doc/style/style/whitespace.md b/src/doc/style/style/whitespace.md new file mode 100644 index 0000000000000..b21b280dff0d7 --- /dev/null +++ b/src/doc/style/style/whitespace.md @@ -0,0 +1,133 @@ +% Whitespace [FIXME: needs RFC] + +* Lines must not exceed 99 characters. +* Use 4 spaces for indentation, _not_ tabs. +* No trailing whitespace at the end of lines or files. + +### Spaces + +* Use spaces around binary operators, including the equals sign in attributes: + +``` rust +#[deprecated = "Use `bar` instead."] +fn foo(a: uint, b: uint) -> uint { + a + b +} +``` + +* Use a space after colons and commas: + +``` rust +fn foo(a: Bar); + +MyStruct { foo: 3, bar: 4 } + +foo(bar, baz); +``` + +* Use a space after the opening and before the closing brace for + single line blocks or `struct` expressions: + +``` rust +spawn(proc() { do_something(); }) + +Point { x: 0.1, y: 0.3 } +``` + +### Line wrapping + +* For multiline function signatures, each new line should align with the + first parameter. Multiple parameters per line are permitted: + +``` rust +fn frobnicate(a: Bar, b: Bar, + c: Bar, d: Bar) + -> Bar { + ... +} + +fn foo( + a: Bar, + b: Bar) + -> Baz { + ... +} +``` + +* Multiline function invocations generally follow the same rule as for + signatures. However, if the final argument begins a new block, the + contents of the block may begin on a new line, indented one level: + +``` rust +fn foo_bar(a: Bar, b: Bar, + c: |Bar|) -> Bar { + ... +} + +// Same line is fine: +foo_bar(x, y, |z| { z.transpose(y) }); + +// Indented body on new line is also fine: +foo_bar(x, y, |z| { + z.quux(); + z.rotate(x) +}) +``` + +> **[FIXME]** Do we also want to allow the following? +> +> ```rust +> frobnicate( +> arg1, +> arg2, +> arg3) +> ``` +> +> This style could ease the conflict between line length and functions +> with many parameters (or long method chains). + +### Matches + +> * **[Deprecated]** If you have multiple patterns in a single `match` +> arm, write each pattern on a separate line: +> +> ``` rust +> match foo { +> bar(_) +> | baz => quux, +> x +> | y +> | z => { +> quuux +> } +> } +> ``` + +### Alignment + +Idiomatic code should not use extra whitespace in the middle of a line +to provide alignment. + + +``` rust +// Good +struct Foo { + short: f64, + really_long: f64, +} + +// Bad +struct Bar { + short: f64, + really_long: f64, +} + +// Good +let a = 0; +let radius = 7; + +// Bad +let b = 0; +let diameter = 7; +``` diff --git a/src/doc/style/testing/README.md b/src/doc/style/testing/README.md new file mode 100644 index 0000000000000..a21f69414d326 --- /dev/null +++ b/src/doc/style/testing/README.md @@ -0,0 +1,5 @@ +% Testing + +> **[FIXME]** Add some general remarks about when and how to unit +> test, versus other kinds of testing. What are our expectations for +> Rust's core libraries? diff --git a/src/doc/style/testing/unit.md b/src/doc/style/testing/unit.md new file mode 100644 index 0000000000000..813660d8fdfb9 --- /dev/null +++ b/src/doc/style/testing/unit.md @@ -0,0 +1,30 @@ +% Unit testing + +Unit tests should live in a `test` submodule at the bottom of the module they +test. Mark the `test` submodule with `#[cfg(test)]` so it is only compiled when +testing. + +The `test` module should contain: + +* Imports needed only for testing. +* Functions marked with `#[test]` striving for full coverage of the parent module's + definitions. +* Auxiliary functions needed for writing the tests. + +For example: + +``` rust +// Excerpt from std::str + +#[cfg(test)] +mod test { + #[test] + fn test_eq() { + assert!((eq(&"".to_owned(), &"".to_owned()))); + assert!((eq(&"foo".to_owned(), &"foo".to_owned()))); + assert!((!eq(&"foo".to_owned(), &"bar".to_owned()))); + } +} +``` + +> **[FIXME]** add details about useful macros for testing, e.g. `assert!` diff --git a/src/doc/style/todo.md b/src/doc/style/todo.md new file mode 100644 index 0000000000000..28ef2a1832d8b --- /dev/null +++ b/src/doc/style/todo.md @@ -0,0 +1,5 @@ +* [Containers and iteration]() +* [The visitor pattern]() +* [Concurrency]() +* [Documentation]() +* [Macros]() diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 9e16414d225a9..d57aff7f4f411 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -28,13 +28,14 @@ * [Generics](generics.md) * [Traits](traits.md) * [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md) + * [Macros](macros.md) * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) * [Documentation](documentation.md) * [III: Advanced Topics](advanced.md) * [FFI](ffi.md) * [Unsafe Code](unsafe.md) - * [Macros](macros.md) + * [Advanced Macros](advanced-macros.md) * [Compiler Plugins](plugins.md) * [Conclusion](conclusion.md) * [Glossary](glossary.md) diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md new file mode 100644 index 0000000000000..aff365051a4ea --- /dev/null +++ b/src/doc/trpl/advanced-macros.md @@ -0,0 +1,210 @@ +% Advanced macros + +This chapter picks up where the [introductory macro chapter](macros.html) left +off. + +# Syntactic requirements + +Even when Rust code contains un-expanded macros, it can be parsed as a full +syntax tree. This property can be very useful for editors and other tools that +process code. It also has a few consequences for the design of Rust's macro +system. + +One consequence is that Rust must determine, when it parses a macro invocation, +whether the macro stands in for + +* zero or more items, +* zero or more methods, +* an expression, +* a statement, or +* a pattern. + +A macro invocation within a block could stand for some items, or for an +expression / statement. Rust uses a simple rule to resolve this ambiguity. A +macro invocation that stands for items must be either + +* delimited by curly braces, e.g. `foo! { ... }`, or +* terminated by a semicolon, e.g. `foo!(...);` + +Another consequence of pre-expansion parsing is that the macro invocation must +consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces +must be balanced within a macro invocation. For example, `foo!([)` is +forbidden. This allows Rust to know where the macro invocation ends. + +More formally, the macro invocation body must be a sequence of *token trees*. +A token tree is defined recursively as either + +* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or +* any other single token. + +Within a matcher, each metavariable has a *fragment specifier*, identifying +which syntactic form it matches. + +* `ident`: an identifier. Examples: `x`; `foo`. +* `path`: a qualified name. Example: `T::SpecialA`. +* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`. +* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`. +* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`. +* `stmt`: a single statement. Example: `let x = 3`. +* `block`: a brace-delimited sequence of statements. Example: + `{ log(error, "hi"); return 12; }`. +* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`. +* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`. +* `tt`: a single token tree. + +There are additional rules regarding the next token after a metavariable: + +* `expr` variables must be followed by one of: `=> , ;` +* `ty` and `path` variables must be followed by one of: `=> , : = > as` +* `pat` variables must be followed by one of: `=> , =` +* Other variables may be followed by any token. + +These rules provide some flexibility for Rust's syntax to evolve without +breaking existing macros. + +The macro system does not deal with parse ambiguity at all. For example, the +grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would +be forced to choose between parsing `$t` and parsing `$e`. Changing the +invocation syntax to put a distinctive token in front can solve the problem. In +this case, you can write `$(T $t:ty)* E $e:exp`. + +[item]: ../reference.html#items + +# Scoping and macro import/export + +Macros are expanded at an early stage in compilation, before name resolution. +One downside is that scoping works differently for macros, compared to other +constructs in the language. + +Definition and expansion of macros both happen in a single depth-first, +lexical-order traversal of a crate's source. So a macro defined at module scope +is visible to any subsequent code in the same module, which includes the body +of any subsequent child `mod` items. + +A macro defined within the body of a single `fn`, or anywhere else not at +module scope, is visible only within that item. + +If a module has the `macro_use` attribute, its macros are also visible in its +parent module after the child's `mod` item. If the parent also has `macro_use` +then the macros will be visible in the grandparent after the parent's `mod` +item, and so forth. + +The `macro_use` attribute can also appear on `extern crate`. In this context +it controls which macros are loaded from the external crate, e.g. + +```rust,ignore +#[macro_use(foo, bar)] +extern crate baz; +``` + +If the attribute is given simply as `#[macro_use]`, all macros are loaded. If +there is no `#[macro_use]` attribute then no macros are loaded. Only macros +defined with the `#[macro_export]` attribute may be loaded. + +To load a crate's macros *without* linking it into the output, use `#[no_link]` +as well. + +An example: + +```rust +macro_rules! m1 { () => (()) } + +// visible here: m1 + +mod foo { + // visible here: m1 + + #[macro_export] + macro_rules! m2 { () => (()) } + + // visible here: m1, m2 +} + +// visible here: m1 + +macro_rules! m3 { () => (()) } + +// visible here: m1, m3 + +#[macro_use] +mod bar { + // visible here: m1, m3 + + macro_rules! m4 { () => (()) } + + // visible here: m1, m3, m4 +} + +// visible here: m1, m3, m4 +# fn main() { } +``` + +When this library is loaded with `#[macro_use] extern crate`, only `m2` will +be imported. + +The Rust Reference has a [listing of macro-related +attributes](../reference.html#macro--and-plugin-related-attributes). + +# The variable `$crate` + +A further difficulty occurs when a macro is used in multiple crates. Say that +`mylib` defines + +```rust +pub fn increment(x: u32) -> u32 { + x + 1 +} + +#[macro_export] +macro_rules! inc_a { + ($x:expr) => ( ::increment($x) ) +} + +#[macro_export] +macro_rules! inc_b { + ($x:expr) => ( ::mylib::increment($x) ) +} +# fn main() { } +``` + +`inc_a` only works within `mylib`, while `inc_b` only works outside the +library. Furthermore, `inc_b` will break if the user imports `mylib` under +another name. + +Rust does not (yet) have a hygiene system for crate references, but it does +provide a simple workaround for this problem. Within a macro imported from a +crate named `foo`, the special macro variable `$crate` will expand to `::foo`. +By contrast, when a macro is defined and then used in the same crate, `$crate` +will expand to nothing. This means we can write + +```rust +#[macro_export] +macro_rules! inc { + ($x:expr) => ( $crate::increment($x) ) +} +# fn main() { } +``` + +to define a single macro that works both inside and outside our library. The +function name will expand to either `::increment` or `::mylib::increment`. + +To keep this system simple and correct, `#[macro_use] extern crate ...` may +only appear at the root of your crate, not inside `mod`. This ensures that +`$crate` is a single identifier. + +# A final note + +Macros, as currently implemented, are not for the faint of heart. Even +ordinary syntax errors can be more difficult to debug when they occur inside a +macro, and errors caused by parse problems in generated code can be very +tricky. Invoking the `log_syntax!` macro can help elucidate intermediate +states, invoking `trace_macros!(true)` will automatically print those +intermediate states out, and passing the flag `--pretty expanded` as a +command-line argument to the compiler will show the result of expansion. + +If Rust's macro system can't do what you need, you may want to write a +[compiler plugin](plugins.html) instead. Compared to `macro_rules!` +macros, this is significantly more work, the interfaces are much less stable, +and the warnings about debugging apply ten-fold. In exchange you get the +flexibility of running arbitrary Rust code within the compiler. Syntax +extension plugins are sometimes called *procedural macros* for this reason. diff --git a/src/doc/trpl/compound-data-types.md b/src/doc/trpl/compound-data-types.md index db3202b30345f..85d67262c4066 100644 --- a/src/doc/trpl/compound-data-types.md +++ b/src/doc/trpl/compound-data-types.md @@ -322,8 +322,8 @@ The `ordering` variable has the type `Ordering`, and so contains one of the three values. We then do a bunch of `if`/`else` comparisons to check which one it is. -This `Ordering::Greater` notation is too long. Lets use `use` to import can -the `enum` variants instead. This will avoid full scoping: +This `Ordering::Greater` notation is too long. Let's use `use` to import the +`enum` variants instead. This will avoid full scoping: ```{rust} use std::cmp::Ordering::{self, Equal, Less, Greater}; diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index 3c933c1c5af58..9f8f76e1fea6e 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -57,13 +57,13 @@ place! ## Threads Rust's standard library provides a library for 'threads', which allow you to -run Rust code in parallel. Here's a basic example of using `Thread`: +run Rust code in parallel. Here's a basic example of using `std::thread`: ``` -use std::thread::Thread; +use std::thread; fn main() { - Thread::scoped(|| { + thread::scoped(|| { println!("Hello from a thread!"); }); } @@ -73,10 +73,10 @@ The `Thread::scoped()` method accepts a closure, which is executed in a new thread. It's called `scoped` because this thread returns a join guard: ``` -use std::thread::Thread; +use std::thread; fn main() { - let guard = Thread::scoped(|| { + let guard = thread::scoped(|| { println!("Hello from a thread!"); }); @@ -85,15 +85,15 @@ fn main() { ``` When `guard` goes out of scope, it will block execution until the thread is -finished. If we didn't want this behaviour, we could use `Thread::spawn()`: +finished. If we didn't want this behaviour, we could use `thread::spawn()`: ``` -use std::thread::Thread; +use std::thread; use std::old_io::timer; use std::time::Duration; fn main() { - Thread::spawn(|| { + thread::spawn(|| { println!("Hello from a thread!"); }); @@ -101,24 +101,6 @@ fn main() { } ``` -Or call `.detach()`: - -``` -use std::thread::Thread; -use std::old_io::timer; -use std::time::Duration; - -fn main() { - let guard = Thread::scoped(|| { - println!("Hello from a thread!"); - }); - - guard.detach(); - - timer::sleep(Duration::milliseconds(50)); -} -``` - We need to `sleep` here because when `main()` ends, it kills all of the running threads. @@ -164,7 +146,7 @@ As an example, here is a Rust program that would have a data race in many languages. It will not compile: ```ignore -use std::thread::Thread; +use std::thread; use std::old_io::timer; use std::time::Duration; @@ -172,7 +154,7 @@ fn main() { let mut data = vec![1u32, 2, 3]; for i in 0..2 { - Thread::spawn(move || { + thread::spawn(move || { data[i] += 1; }); } @@ -203,7 +185,7 @@ only one person at a time can mutate what's inside. For that, we can use the but for a different reason: ```ignore -use std::thread::Thread; +use std::thread; use std::old_io::timer; use std::time::Duration; use std::sync::Mutex; @@ -213,7 +195,7 @@ fn main() { for i in 0..2 { let data = data.lock().unwrap(); - Thread::spawn(move || { + thread::spawn(move || { data[i] += 1; }); } @@ -255,7 +237,7 @@ We can use `Arc` to fix this. Here's the working version: ``` use std::sync::{Arc, Mutex}; -use std::thread::Thread; +use std::thread; use std::old_io::timer; use std::time::Duration; @@ -264,7 +246,7 @@ fn main() { for i in 0us..2 { let data = data.clone(); - Thread::spawn(move || { + thread::spawn(move || { let mut data = data.lock().unwrap(); data[i] += 1; }); @@ -280,14 +262,14 @@ thread more closely: ``` # use std::sync::{Arc, Mutex}; -# use std::thread::Thread; +# use std::thread; # use std::old_io::timer; # use std::time::Duration; # fn main() { # let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); # for i in 0us..2 { # let data = data.clone(); -Thread::spawn(move || { +thread::spawn(move || { let mut data = data.lock().unwrap(); data[i] += 1; }); @@ -315,7 +297,7 @@ than waiting for a specific time: ``` use std::sync::{Arc, Mutex}; -use std::thread::Thread; +use std::thread; use std::sync::mpsc; fn main() { @@ -326,7 +308,7 @@ fn main() { for _ in 0..10 { let (data, tx) = (data.clone(), tx.clone()); - Thread::spawn(move || { + thread::spawn(move || { let mut data = data.lock().unwrap(); *data += 1; @@ -348,7 +330,7 @@ is `Send` over the channel! ``` use std::sync::{Arc, Mutex}; -use std::thread::Thread; +use std::thread; use std::sync::mpsc; fn main() { @@ -357,7 +339,7 @@ fn main() { for _ in 0..10 { let tx = tx.clone(); - Thread::spawn(move || { + thread::spawn(move || { let answer = 42u32; tx.send(answer); @@ -378,9 +360,9 @@ A `panic!` will crash the currently executing thread. You can use Rust's threads as a simple isolation mechanism: ``` -use std::thread::Thread; +use std::thread; -let result = Thread::scoped(move || { +let result = thread::spawn(move || { panic!("oops!"); }).join(); diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index 2651949747952..ded30063ebaf0 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -15,7 +15,7 @@ comments": // the "link" crate attribute is currently required for rustdoc, but normally // isn't needed. #![crate_id = "universe"] -#![crate_type="lib"] +#![crate_type= "lib"] //! Tools for dealing with universes (this is a doc comment, and is shown on //! the crate index page. The ! makes it apply to the parent of the comment, diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index ce0283480c60c..45c08af04f877 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -4,19 +4,19 @@ Let's talk about loops. Remember Rust's `for` loop? Here's an example: -```{rust} +```rust for x in 0..10 { println!("{}", x); } ``` -Now that you know more Rust, we can talk in detail about how this works. The -`range` function returns an *iterator*. An iterator is something that we can +Now that you know more Rust, we can talk in detail about how this works. +Ranges (the `0..10`) are 'iterators'. An iterator is something that we can call the `.next()` method on repeatedly, and it gives us a sequence of things. Like this: -```{rust} +```rust let mut range = 0..10; loop { @@ -29,12 +29,12 @@ loop { } ``` -We make a mutable binding to the return value of `range`, which is our iterator. -We then `loop`, with an inner `match`. This `match` is used on the result of -`range.next()`, which gives us a reference to the next value of the iterator. -`next` returns an `Option`, in this case, which will be `Some(i32)` when -we have a value and `None` once we run out. If we get `Some(i32)`, we print it -out, and if we get `None`, we `break` out of the loop. +We make a mutable binding to the range, which is our iterator. We then `loop`, +with an inner `match`. This `match` is used on the result of `range.next()`, +which gives us a reference to the next value of the iterator. `next` returns an +`Option`, in this case, which will be `Some(i32)` when we have a value and +`None` once we run out. If we get `Some(i32)`, we print it out, and if we get +`None`, we `break` out of the loop. This code sample is basically the same as our `for` loop version. The `for` loop is just a handy way to write this `loop`/`match`/`break` construct. @@ -43,13 +43,13 @@ loop is just a handy way to write this `loop`/`match`/`break` construct. 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 tasks. Before we talk about those, we should talk about a -Rust anti-pattern. And that's `range`. +Rust anti-pattern. And that's using ranges like this. -Yes, we just talked about how `range` is cool. But `range` is also very -primitive. For example, if you needed to iterate over the contents of -a vector, you may be tempted to write this: +Yes, we just talked about how ranges are cool. But ranges are also very +primitive. For example, if you needed to iterate over the contents of a vector, +you may be tempted to write this: -```{rust} +```rust let nums = vec![1, 2, 3]; for i in 0..nums.len() { @@ -61,7 +61,7 @@ This is strictly worse than using an actual iterator. The `.iter()` method on vectors returns an iterator which iterates through a reference to each element of the vector in turn. So write this: -```{rust} +```rust let nums = vec![1, 2, 3]; for num in nums.iter() { @@ -83,7 +83,7 @@ works. `num` is actually of type `&i32`. That is, it's a reference to an `i32`, not an `i32` itself. `println!` handles the dereferencing for us, so we don't see it. This code works fine too: -```{rust} +```rust let nums = vec![1, 2, 3]; for num in nums.iter() { @@ -97,7 +97,7 @@ involve making a copy of the data and giving us the copy. With references, we're just borrowing a reference to the data, and so it's just passing a reference, without needing to do the copy. -So, now that we've established that `range` is often not what you want, let's +So, now that we've established that ranges are often not what you want, let's talk about what you do want instead. There are three broad classes of things that are relevant here: iterators, @@ -108,8 +108,7 @@ There are three broad classes of things that are relevant here: iterators, different output sequence. * *consumers* operate on an iterator, producing some final set of values. -Let's talk about consumers first, since you've already seen an iterator, -`range`. +Let's talk about consumers first, since you've already seen an iterator, ranges. ## Consumers @@ -118,7 +117,7 @@ The most common consumer is `collect()`. This code doesn't quite compile, but it shows the intention: ```{rust,ignore} -let one_to_one_hundred = (1..101i32).collect(); +let one_to_one_hundred = (1..101).collect(); ``` As you can see, we call `collect()` on our iterator. `collect()` takes @@ -127,8 +126,8 @@ of the results. So why won't this compile? Rust can't determine what type of things you want to collect, and so you need to let it know. Here's the version that does compile: -```{rust} -let one_to_one_hundred = (1..101i32).collect::>(); +```rust +let one_to_one_hundred = (1..101).collect::>(); ``` If you remember, the `::<>` syntax allows us to give a type hint, @@ -137,7 +136,7 @@ need to use the whole type, though. Using a `_` will let you provide a partial hint: ```rust -let one_to_one_hundred = range(1, 101).collect::>(); +let one_to_one_hundred = (1..101).collect::>(); ``` This says "Collect into a `Vec`, please, but infer what the `T` is for me." @@ -146,8 +145,8 @@ This says "Collect into a `Vec`, please, but infer what the `T` is for me." `collect()` is the most common consumer, but there are others too. `find()` is one: -```{rust} -let greater_than_forty_two = (0..100i32) +```rust +let greater_than_forty_two = (0..100) .find(|x| *x > 42); match greater_than_forty_two { @@ -163,9 +162,8 @@ element, `find` returns an `Option` rather than the element itself. Another important consumer is `fold`. Here's what it looks like: -```{rust} -let sum = (1..4) - .fold(0, |sum, x| sum + x); +```rust +let sum = (1..4).fold(0, |sum, x| sum + x); ``` `fold()` is a consumer that looks like this: @@ -187,7 +185,7 @@ in this iterator: We called `fold()` with these arguments: -```{rust} +```rust # (1..4) .fold(0, |sum, x| sum + x); ``` @@ -218,25 +216,25 @@ are *lazy* and don't need to generate all of the values upfront. This code, for example, does not actually generate the numbers `1-100`, and just creates a value that represents the sequence: -```{rust} +```rust let nums = 1..100; ``` Since we didn't do anything with the range, it didn't generate the sequence. Let's add the consumer: -```{rust} +```rust let nums = (1..100).collect::>(); ``` Now, `collect()` will require that the range gives it some numbers, and so it will do the work of generating the sequence. -A range is one of two basic iterators that you'll see. The other is `iter()`, +Ranges are one of two basic iterators that you'll see. The other is `iter()`, which you've used before. `iter()` can turn a vector into a simple iterator that gives you each element in turn: -```{rust} +```rust let nums = [1, 2, 3]; for num in nums.iter() { @@ -247,7 +245,7 @@ for num in nums.iter() { These two basic iterators should serve you well. There are some more advanced iterators, including ones that are infinite. Like `count`: -```{rust} +```rust std::iter::count(1, 5); ``` @@ -265,7 +263,7 @@ we need to talk about with regards to iterators. Let's get to it! a new iterator. The simplest one is called `map`: ```{rust,ignore} -(1..100i32).map(|x| x + 1); +(1..100).map(|x| x + 1); ``` `map` is called upon another iterator, and produces a new iterator where each @@ -273,7 +271,7 @@ element reference has the closure it's been given as an argument called on it. So this would give us the numbers from `2-100`. Well, almost! If you compile the example, you'll get a warning: -```{notrust,ignore} +```text warning: unused result which must be used: iterator adaptors are lazy and do nothing unless consumed, #[warn(unused_must_use)] on by default (1..100).map(|x| x + 1); @@ -295,7 +293,7 @@ iterator over the next `n` elements of the original iterator, note that this has no side effect on the original iterator. Let's try it out with our infinite iterator from before, `count()`: -```{rust} +```rust for i in std::iter::count(1, 5).take(5) { println!("{}", i); } @@ -303,7 +301,7 @@ for i in std::iter::count(1, 5).take(5) { This will print -```{notrust,ignore} +```text 1 6 11 @@ -315,8 +313,8 @@ This will print returns `true` or `false`. The new iterator `filter()` produces only the elements that that closure returns `true` for: -```{rust} -for i in (1..100i32).filter(|&x| x % 2 == 0) { +```rust +for i in (1..100).filter(|&x| x % 2 == 0) { println!("{}", i); } ``` @@ -330,8 +328,8 @@ itself.) You can chain all three things together: start with an iterator, adapt it a few times, and then consume the result. Check it out: -```{rust} -(1..1000i32) +```rust +(1..1000) .filter(|&x| x % 2 == 0) .filter(|&x| x % 3 == 0) .take(5) diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index f429e9df19657..ce6fa3ce949cd 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -1,588 +1,365 @@ % Macros -# Introduction - -Functions are the primary tool that programmers can use to build abstractions. -Sometimes, however, programmers want to abstract over compile-time syntax -rather than run-time values. -Macros provide syntactic abstraction. -For an example of how this can be useful, consider the following two code fragments, -which both pattern-match on their input and both return early in one case, -doing nothing otherwise: - -~~~~ -# enum T { SpecialA(u32), SpecialB(u32) } -# fn f() -> u32 { -# let input_1 = T::SpecialA(0); -# let input_2 = T::SpecialA(0); -match input_1 { - T::SpecialA(x) => { return x; } - _ => {} -} -// ... -match input_2 { - T::SpecialB(x) => { return x; } - _ => {} -} -# return 0; -# } -~~~~ - -This code could become tiresome if repeated many times. -However, no function can capture its functionality to make it possible -to abstract the repetition away. -Rust's macro system, however, can eliminate the repetition. Macros are -lightweight custom syntax extensions, themselves defined using the -`macro_rules!` syntax extension. The following `early_return` macro captures -the pattern in the above code: - -~~~~ -# enum T { SpecialA(u32), SpecialB(u32) } -# fn f() -> u32 { -# let input_1 = T::SpecialA(0); -# let input_2 = T::SpecialA(0); -macro_rules! early_return { - ($inp:expr, $sp:path) => ( // invoke it like `(input_5, SpecialE)` - match $inp { - $sp(x) => { return x; } - _ => {} - } - ); -} -// ... -early_return!(input_1, T::SpecialA); -// ... -early_return!(input_2, T::SpecialB); -# return 0; -# } -# fn main() {} -~~~~ - -Macros are defined in pattern-matching style: in the above example, the text -`($inp:expr, $sp:path)` that appears on the left-hand side of the `=>` is the -*macro invocation syntax*, a pattern denoting how to write a call to the -macro. The text on the right-hand side of the `=>`, beginning with `match -$inp`, is the *macro transcription syntax*: what the macro expands to. - -# Invocation syntax - -The macro invocation syntax specifies the syntax for the arguments to the -macro. It appears on the left-hand side of the `=>` in a macro definition. It -conforms to the following rules: - -1. It must be surrounded by parentheses. -2. `$` has special meaning (described below). -3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is -forbidden. -4. Some arguments can be followed only by a limited set of separators, to -avoid ambiguity (described below). - -Otherwise, the invocation syntax is free-form. - -To take a fragment of Rust code as an argument, write `$` followed by a name - (for use on the right-hand side), followed by a `:`, followed by a *fragment - specifier*. The fragment specifier denotes the sort of fragment to match. The - most common fragment specifiers are: - -* `ident` (an identifier, referring to a variable or item. Examples: `f`, `x`, - `foo`.) -* `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; - `f(42)`.) -* `ty` (a type. Examples: `i32`, `Vec<(char, String)>`, `&T`.) -* `path` (a path to struct or enum variant. Example: `T::SpecialA`) -* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of - a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.) -* `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`) - -The parser interprets any token that's not preceded by a `$` literally. Rust's usual -rules of tokenization apply, - -So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro -that could be invoked like: `my_macro!(i->(( 2+2 )))`. - -To avoid ambiguity, macro invocation syntax must conform to the following rules: - -* `expr` must be followed by `=>`, `,` or `;`. -* `ty` and `path` must be followed by `=>`, `,`, `:`, `=`, `>` or `as`. -* `pat` must be followed by `=>`, `,` or `=`. -* `ident` and `block` can be followed by any token. - -## Invocation location - -A macro invocation may take the place of (and therefore expand to) an -expression, item, statement, or pattern. The Rust parser will parse the macro -invocation as a "placeholder" for whichever syntactic form is appropriate for -the location. - -At expansion time, the output of the macro will be parsed as whichever of the -three nonterminals it stands in for. This means that a single macro might, -for example, expand to an item or an expression, depending on its arguments -(and cause a syntax error if it is called with the wrong argument for its -location). Although this behavior sounds excessively dynamic, it is known to -be useful under some circumstances. - - -# Transcription syntax - -The right-hand side of the `=>` follows the same rules as the left-hand side, -except that a `$` need only be followed by the name of the syntactic fragment -to transcribe into the macro expansion; its type need not be repeated. - -The right-hand side must be enclosed by delimiters, which the transcriber ignores. -Therefore `() => ((1,2,3))` is a macro that expands to a tuple expression, -`() => (let $x=$val)` is a macro that expands to a statement, -and `() => (1,2,3)` is a macro that expands to a syntax error -(since the transcriber interprets the parentheses on the right-hand-size as delimiters, -and `1,2,3` is not a valid Rust expression on its own). - -Except for permissibility of `$name` (and `$(...)*`, discussed below), the -right-hand side of a macro definition is ordinary Rust syntax. In particular, -macro invocations (including invocations of the macro currently being defined) -are permitted in expression, statement, and item locations. However, nothing -else about the code is examined or executed by the macro system; execution -still has to wait until run-time. - -## Interpolation location - -The interpolation `$argument_name` may appear in any location consistent with -its fragment specifier (i.e., if it is specified as `ident`, it may be used -anywhere an identifier is permitted). - -# Multiplicity - -## Invocation - -Going back to the motivating example, recall that `early_return` expanded into -a `match` that would `return` if the `match`'s scrutinee matched the -"special case" identifier provided as the second argument to `early_return`, -and do nothing otherwise. Now suppose that we wanted to write a -version of `early_return` that could handle a variable number of "special" -cases. - -The syntax `$(...)*` on the left-hand side of the `=>` in a macro definition -accepts zero or more occurrences of its contents. It works much -like the `*` operator in regular expressions. It also supports a -separator token (a comma-separated list could be written `$(...),*`), and `+` -instead of `*` to mean "at least one". - -~~~~ -# enum T { SpecialA(u32), SpecialB(u32), SpecialC(u32), SpecialD(u32) } -# fn f() -> u32 { -# let input_1 = T::SpecialA(0); -# let input_2 = T::SpecialA(0); -macro_rules! early_return { - ($inp:expr, [ $($sp:path),+ ]) => ( - match $inp { +By now you've learned about many of the tools Rust provides for abstracting and +reusing code. These units of code reuse have a rich semantic structure. For +example, functions have a type signature, type parameters have trait bounds, +and overloaded functions must belong to a particular trait. + +This structure means that Rust's core abstractions have powerful compile-time +correctness checking. But this comes at the price of reduced flexibility. If +you visually identify a pattern of repeated code, you may find it's difficult +or cumbersome to express that pattern as a generic function, a trait, or +anything else within Rust's semantics. + +Macros allow us to abstract at a *syntactic* level. A macro invocation is +shorthand for an "expanded" syntactic form. This expansion happens early in +compilation, before any static checking. As a result, macros can capture many +patterns of code reuse that Rust's core abstractions cannot. + +The drawback is that macro-based code can be harder to understand, because +fewer of the built-in rules apply. Like an ordinary function, a well-behaved +macro can be used without understanding its implementation. However, it can be +difficult to design a well-behaved macro! Additionally, compiler errors in +macro code are harder to interpret, because they describe problems in the +expanded code, not the source-level form that developers use. + +These drawbacks make macros something of a "feature of last resort". That's not +to say that macros are bad; they are part of Rust because sometimes they're +needed for truly concise, well-abstracted code. Just keep this tradeoff in +mind. + +# Defining a macro + +You may have seen the `vec!` macro, used to initialize a [vector][] with any +number of elements. + +[vector]: arrays-vectors-and-slices.html + +```rust +let x: Vec = vec![1, 2, 3]; +# assert_eq!(&[1,2,3], &x); +``` + +This can't be an ordinary function, because it takes any number of arguments. +But we can imagine it as syntactic shorthand for + +```rust +let x: Vec = { + let mut temp_vec = Vec::new(); + temp_vec.push(1); + temp_vec.push(2); + temp_vec.push(3); + temp_vec +}; +# assert_eq!(&[1,2,3], &x); +``` + +We can implement this shorthand, using a macro: [^actual] + +[^actual]: The actual definition of `vec!` in libcollections differs from the + one presented here, for reasons of efficiency and reusability. Some + of these are mentioned in the [advanced macros chapter][]. + +```rust +macro_rules! vec { + ( $( $x:expr ),* ) => { + { + let mut temp_vec = Vec::new(); $( - $sp(x) => { return x; } - )+ - _ => {} + temp_vec.push($x); + )* + temp_vec } - ) -} -// ... -early_return!(input_1, [T::SpecialA,T::SpecialC,T::SpecialD]); -// ... -early_return!(input_2, [T::SpecialB]); -# return 0; -# } -# fn main() {} -~~~~ - -### Transcription - -As the above example demonstrates, `$(...)*` is also valid on the right-hand -side of a macro definition. The behavior of `*` in transcription, -especially in cases where multiple `*`s are nested, and multiple different -names are involved, can seem somewhat magical and unintuitive at first. The -system that interprets them is called "Macro By Example". The two rules to -keep in mind are (1) the behavior of `$(...)*` is to walk through one "layer" -of repetitions for all of the `$name`s it contains in lockstep, and (2) each -`$name` must be under at least as many `$(...)*`s as it was matched against. -If it is under more, it'll be repeated, as appropriate. - -## Parsing limitations - - -For technical reasons, there are two limitations to the treatment of syntax -fragments by the macro parser: - -1. The parser will always parse as much as possible of a Rust syntactic -fragment. For example, if the comma were omitted from the syntax of -`early_return!` above, `input_1 [` would've been interpreted as the beginning -of an array index. In fact, invoking the macro would have been impossible. -2. The parser must have eliminated all ambiguity by the time it reaches a -`$name:fragment_specifier` declaration. This limitation can result in parse -errors when declarations occur at the beginning of, or immediately after, -a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to -parse because the parser would be forced to choose between parsing `t` and -parsing `e`. Changing the invocation syntax to require a distinctive token in -front can solve the problem. In the above example, `$(T $t:ty)* E $e:exp` -solves the problem. - -# Macro argument pattern matching - -## Motivation - -Now consider code like the following: - -~~~~ -# enum T1 { Good1(T2, u32), Bad1} -# struct T2 { body: T3 } -# enum T3 { Good2(u32), Bad2} -# fn f(x: T1) -> u32 { -match x { - T1::Good1(g1, val) => { - match g1.body { - T3::Good2(result) => { - // complicated stuff goes here - return result + val; - }, - _ => panic!("Didn't get good_2") - } - } - _ => return 0 // default value + }; } +# fn main() { +# assert_eq!(&[1,2,3], &vec![1,2,3]); # } -# fn main() {} -~~~~ - -All the complicated stuff is deeply indented, and the error-handling code is -separated from matches that fail. We'd like to write a macro that performs -a match, but with a syntax that suits the problem better. The following macro -can solve the problem: - -~~~~ -macro_rules! biased_match { - // special case: `let (x) = ...` is illegal, so use `let x = ...` instead - ( ($e:expr) -> ($p:pat) else $err:stmt ; - binds $bind_res:ident - ) => ( - let $bind_res = match $e { - $p => ( $bind_res ), - _ => { $err } - }; - ); - // more than one name; use a tuple - ( ($e:expr) -> ($p:pat) else $err:stmt ; - binds $( $bind_res:ident ),* - ) => ( - let ( $( $bind_res ),* ) = match $e { - $p => ( $( $bind_res ),* ), - _ => { $err } - }; - ) -} +``` -# enum T1 { Good1(T2, u32), Bad1} -# struct T2 { body: T3 } -# enum T3 { Good2(u32), Bad2} -# fn f(x: T1) -> u32 { -biased_match!((x) -> (T1::Good1(g1, val)) else { return 0 }; - binds g1, val ); -biased_match!((g1.body) -> (T3::Good2(result) ) - else { panic!("Didn't get good_2") }; - binds result ); -// complicated stuff goes here -return result + val; -# } -# fn main() {} -~~~~ - -This solves the indentation problem. But if we have a lot of chained matches -like this, we might prefer to write a single macro invocation. The input -pattern we want is clear: - -~~~~ -# fn main() {} -# macro_rules! b { - ( $( ($e:expr) -> ($p:pat) else $err:stmt ; )* - binds $( $bind_res:ident ),* - ) -# => (0) } -~~~~ - -However, it's not possible to directly expand to nested match statements. But -there is a solution. - -## The recursive approach to macro writing - -A macro may accept multiple different input grammars. The first one to -successfully match the actual argument to a macro invocation is the one that -"wins". - -In the case of the example above, we want to write a recursive macro to -process the semicolon-terminated lines, one-by-one. So, we want the following -input patterns: - -~~~~ -# macro_rules! b { - ( binds $( $bind_res:ident ),* ) -# => (0) } -# fn main() {} -~~~~ - -...and: - -~~~~ -# fn main() {} -# macro_rules! b { - ( ($e :expr) -> ($p :pat) else $err :stmt ; - $( ($e_rest:expr) -> ($p_rest:pat) else $err_rest:stmt ; )* - binds $( $bind_res:ident ),* - ) -# => (0) } -~~~~ - -The resulting macro looks like this. Note that the separation into -`biased_match!` and `biased_match_rec!` occurs only because we have an outer -piece of syntax (the `let`) which we only want to transcribe once. - -~~~~ -# fn main() { +Whoa, that's a lot of new syntax! Let's break it down. -macro_rules! biased_match_rec { - // Handle the first layer - ( ($e :expr) -> ($p :pat) else $err :stmt ; - $( ($e_rest:expr) -> ($p_rest:pat) else $err_rest:stmt ; )* - binds $( $bind_res:ident ),* - ) => ( - match $e { - $p => { - // Recursively handle the next layer - biased_match_rec!($( ($e_rest) -> ($p_rest) else $err_rest ; )* - binds $( $bind_res ),* - ) - } - _ => { $err } - } - ); - // Produce the requested values - ( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) ) -} +```ignore +macro_rules! vec { ... } +``` -// Wrap the whole thing in a `let`. -macro_rules! biased_match { - // special case: `let (x) = ...` is illegal, so use `let x = ...` instead - ( $( ($e:expr) -> ($p:pat) else $err:stmt ; )* - binds $bind_res:ident - ) => ( - let $bind_res = biased_match_rec!( - $( ($e) -> ($p) else $err ; )* - binds $bind_res - ); - ); - // more than one name: use a tuple - ( $( ($e:expr) -> ($p:pat) else $err:stmt ; )* - binds $( $bind_res:ident ),* - ) => ( - let ( $( $bind_res ),* ) = biased_match_rec!( - $( ($e) -> ($p) else $err ; )* - binds $( $bind_res ),* - ); - ) -} +This says we're defining a macro named `vec`, much as `fn vec` would define a +function named `vec`. In prose, we informally write a macro's name with an +exclamation point, e.g. `vec!`. The exclamation point is part of the invocation +syntax and serves to distinguish a macro from an ordinary function. +## Matching -# enum T1 { Good1(T2, u32), Bad1} -# struct T2 { body: T3 } -# enum T3 { Good2(u32), Bad2} -# fn f(x: T1) -> u32 { -biased_match!( - (x) -> (T1::Good1(g1, val)) else { return 0 }; - (g1.body) -> (T3::Good2(result) ) else { panic!("Didn't get Good2") }; - binds val, result ); -// complicated stuff goes here -return result + val; -# } -# } -~~~~ - -This technique applies to many cases where transcribing a result all at once is not possible. -The resulting code resembles ordinary functional programming in some respects, -but has some important differences from functional programming. - -The first difference is important, but also easy to forget: the transcription -(right-hand) side of a `macro_rules!` rule is literal syntax, which can only -be executed at run-time. If a piece of transcription syntax does not itself -appear inside another macro invocation, it will become part of the final -program. If it is inside a macro invocation (for example, the recursive -invocation of `biased_match_rec!`), it does have the opportunity to affect -transcription, but only through the process of attempted pattern matching. - -The second, related, difference is that the evaluation order of macros feels -"backwards" compared to ordinary programming. Given an invocation -`m1!(m2!())`, the expander first expands `m1!`, giving it as input the literal -syntax `m2!()`. If it transcribes its argument unchanged into an appropriate -position (in particular, not as an argument to yet another macro invocation), -the expander will then proceed to evaluate `m2!()` (along with any other macro -invocations `m1!(m2!())` produced). +The macro is defined through a series of *rules*, which are pattern-matching +cases. Above, we had -# Hygiene +```ignore +( $( $x:expr ),* ) => { ... }; +``` -To prevent clashes, rust implements -[hygienic macros](http://en.wikipedia.org/wiki/Hygienic_macro). +This is like a `match` expression arm, but the matching happens on Rust syntax +trees, at compile time. The semicolon is optional on the last (here, only) +case. The "pattern" on the left-hand side of `=>` is known as a *matcher*. +These have [their own little grammar] within the language. -As an example, `loop` and `for-loop` labels (discussed in the lifetimes guide) -will not clash. The following code will print "Hello!" only once: +[their own little grammar]: ../reference.html#macros -~~~ -macro_rules! loop_x { - ($e: expr) => ( - // $e will not interact with this 'x - 'x: loop { - println!("Hello!"); - $e - } - ); +The matcher `$x:expr` will match any Rust expression, binding that syntax tree +to the *metavariable* `$x`. The identifier `expr` is a *fragment specifier*; +the full possibilities are enumerated in the [advanced macros chapter][]. +Surrounding the matcher with `$(...),*` will match zero or more expressions, +separated by commas. + +Aside from the special matcher syntax, any Rust tokens that appear in a matcher +must match exactly. For example, + +```rust +macro_rules! foo { + (x => $e:expr) => (println!("mode X: {}", $e)); + (y => $e:expr) => (println!("mode Y: {}", $e)); } fn main() { - 'x: loop { - loop_x!(break 'x); - println!("I am never printed."); - } + foo!(y => 3); } -~~~ +``` -The two `'x` names did not clash, which would have caused the loop -to print "I am never printed" and to run forever. +will print -# Scoping and macro import/export +```text +mode Y: 3 +``` + +With -Macros are expanded at an early stage in compilation, before name resolution. -One downside is that scoping works differently for macros, compared to other -constructs in the language. +```rust,ignore +foo!(z => 3); +``` -Definition and expansion of macros both happen in a single depth-first, -lexical-order traversal of a crate's source. So a macro defined at module scope -is visible to any subsequent code in the same module, which includes the body -of any subsequent child `mod` items. +we get the compiler error -A macro defined within the body of a single `fn`, or anywhere else not at -module scope, is visible only within that item. +```text +error: no rules expected the token `z` +``` -If a module has the `macro_use` attribute, its macros are also visible in its -parent module after the child's `mod` item. If the parent also has `macro_use` -then the macros will be visible in the grandparent after the parent's `mod` -item, and so forth. +## Expansion -The `macro_use` attribute can also appear on `extern crate`. In this context -it controls which macros are loaded from the external crate, e.g. +The right-hand side of a macro rule is ordinary Rust syntax, for the most part. +But we can splice in bits of syntax captured by the matcher. From the original +example: -```rust,ignore -#[macro_use(foo, bar)] -extern crate baz; +```ignore +$( + temp_vec.push($x); +)* ``` -If the attribute is given simply as `#[macro_use]`, all macros are loaded. If -there is no `#[macro_use]` attribute then no macros are loaded. Only macros -defined with the `#[macro_export]` attribute may be loaded. +Each matched expression `$x` will produce a single `push` statement in the +macro expansion. The repetition in the expansion proceeds in "lockstep" with +repetition in the matcher (more on this in a moment). -To load a crate's macros *without* linking it into the output, use `#[no_link]` -as well. +Because `$x` was already declared as matching an expression, we don't repeat +`:expr` on the right-hand side. Also, we don't include a separating comma as +part of the repetition operator. Instead, we have a terminating semicolon +within the repeated block. -An example: +Another detail: the `vec!` macro has *two* pairs of braces on the right-hand +side. They are often combined like so: -```rust -macro_rules! m1 { () => (()) } +```ignore +macro_rules! foo { + () => {{ + ... + }} +} +``` + +The outer braces are part of the syntax of `macro_rules!`. In fact, you can use +`()` or `[]` instead. They simply delimit the right-hand side as a whole. + +The inner braces are part of the expanded syntax. Remember, the `vec!` macro is +used in an expression context. To write an expression with multiple statements, +including `let`-bindings, we use a block. If your macro expands to a single +expression, you don't need this extra layer of braces. + +Note that we never *declared* that the macro produces an expression. In fact, +this is not determined until we use the macro as an expression. With care, you +can write a macro whose expansion works in several contexts. For example, +shorthand for a data type could be valid as either an expression or a pattern. + +## Repetition -// visible here: m1 +The repetition behavior can seem somewhat magical, especially when multiple +names are bound at multiple nested levels of repetition. The two rules to keep +in mind are: -mod foo { - // visible here: m1 +1. the behavior of `$(...)*` is to walk through one "layer" of repetitions, for +all of the `$name`s it contains, in lockstep, and +2. each `$name` must be under at least as many `$(...)*`s as it was matched +against. If it is under more, it'll be duplicated, as appropriate. - #[macro_export] - macro_rules! m2 { () => (()) } +This baroque macro illustrates the duplication of variables from outer +repetition levels. + +```rust +macro_rules! o_O { + ( + $( + $x:expr; [ $( $y:expr ),* ] + );* + ) => { + &[ $($( $x + $y ),*),* ] + } +} + +fn main() { + let a: &[i32] + = o_O!(10; [1, 2, 3]; + 20; [4, 5, 6]); - // visible here: m1, m2 + assert_eq!(a, [11, 12, 13, 24, 25, 26]); } +``` -// visible here: m1 +That's most of the matcher syntax. These examples use `$(...)*`, which is a +"zero or more" match. Alternatively you can write `$(...)+` for a "one or +more" match. Both forms optionally include a separator, which can be any token +except `+` or `*`. -macro_rules! m3 { () => (()) } +# Hygiene -// visible here: m1, m3 +Some languages implement macros using simple text substitution, which leads to +various problems. For example, this C program prints `13` instead of the +expected `25`. -#[macro_use] -mod bar { - // visible here: m1, m3 +```text +#define FIVE_TIMES(x) 5 * x - macro_rules! m4 { () => (()) } +int main() { + printf("%d\n", FIVE_TIMES(2 + 3)); + return 0; +} +``` - // visible here: m1, m3, m4 +After expansion we have `5 * 2 + 3`, and multiplication has greater precedence +than addition. If you've used C macros a lot, you probably know the standard +idioms for avoiding this problem, as well as five or six others. In Rust, we +don't have to worry about it. + +```rust +macro_rules! five_times { + ($x:expr) => (5 * $x); } -// visible here: m1, m3, m4 -# fn main() { } +fn main() { + assert_eq!(25, five_times!(2 + 3)); +} +``` + +The metavariable `$x` is parsed as a single expression node, and keeps its +place in the syntax tree even after substitution. + +Another common problem in macro systems is *variable capture*. Here's a C +macro, using [a GNU C extension] to emulate Rust's expression blocks. + +[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html + +```text +#define LOG(msg) ({ \ + int state = get_log_state(); \ + if (state > 0) { \ + printf("log(%d): %s\n", state, msg); \ + } \ +}) ``` -When this library is loaded with `#[use_macros] extern crate`, only `m2` will -be imported. +This looks reasonable, but watch what happens in this example: -The Rust Reference has a [listing of macro-related -attributes](../reference.html#macro--and-plugin-related-attributes). +```text +const char *state = "reticulating splines"; +LOG(state); +``` + +The program will likely segfault, after it tries to execute -# The variable `$crate` +```text +printf("log(%d): %s\n", state, state); +``` -A further difficulty occurs when a macro is used in multiple crates. Say that -`mylib` defines +The equivalent Rust macro has the desired behavior. ```rust -pub fn increment(x: u32) -> u32 { - x + 1 +# fn get_log_state() -> i32 { 3 } +macro_rules! log { + ($msg:expr) => {{ + let state: i32 = get_log_state(); + if state > 0 { + println!("log({}): {}", state, $msg); + } + }}; } -#[macro_export] -macro_rules! inc_a { - ($x:expr) => ( ::increment($x) ) +fn main() { + let state: &str = "reticulating splines"; + log!(state); } +``` + +This works because Rust has a [hygienic macro system][]. Each macro expansion +happens in a distinct *syntax context*, and each variable is tagged with the +syntax context where it was introduced. It's as though the variable `state` +inside `main` is painted a different "color" from the variable `state` inside +the macro, and therefore they don't conflict. -#[macro_export] -macro_rules! inc_b { - ($x:expr) => ( ::mylib::increment($x) ) +[hygienic macro system]: http://en.wikipedia.org/wiki/Hygienic_macro + +This also restricts the ability of macros to introduce new bindings at the +invocation site. Code such as the following will not work: + +```rust,ignore +macro_rules! foo { + () => (let x = 3); +} + +fn main() { + foo!(); + println!("{}", x); } -# fn main() { } ``` -`inc_a` only works within `mylib`, while `inc_b` only works outside the -library. Furthermore, `inc_b` will break if the user imports `mylib` under -another name. +Instead you need to pass the variable name into the invocation, so it's tagged +with the right syntax context. -Rust does not (yet) have a hygiene system for crate references, but it does -provide a simple workaround for this problem. Within a macro imported from a -crate named `foo`, the special macro variable `$crate` will expand to `::foo`. -By contrast, when a macro is defined and then used in the same crate, `$crate` -will expand to nothing. This means we can write +```rust +macro_rules! foo { + ($v:ident) => (let $v = 3); +} + +fn main() { + foo!(x); + println!("{}", x); +} +``` + +This holds for `let` bindings and loop labels, but not for [items][]. +So the following code does compile: ```rust -#[macro_export] -macro_rules! inc { - ($x:expr) => ( $crate::increment($x) ) +macro_rules! foo { + () => (fn x() { }); +} + +fn main() { + foo!(); + x(); } -# fn main() { } ``` -to define a single macro that works both inside and outside our library. The -function name will expand to either `::increment` or `::mylib::increment`. - -To keep this system simple and correct, `#[macro_use] extern crate ...` may -only appear at the root of your crate, not inside `mod`. This ensures that -`$crate` is a single identifier. - -# A final note - -Macros, as currently implemented, are not for the faint of heart. Even -ordinary syntax errors can be more difficult to debug when they occur inside a -macro, and errors caused by parse problems in generated code can be very -tricky. Invoking the `log_syntax!` macro can help elucidate intermediate -states, invoking `trace_macros!(true)` will automatically print those -intermediate states out, and passing the flag `--pretty expanded` as a -command-line argument to the compiler will show the result of expansion. - -If Rust's macro system can't do what you need, you may want to write a -[compiler plugin](plugins.html) instead. Compared to `macro_rules!` -macros, this is significantly more work, the interfaces are much less stable, -and the warnings about debugging apply ten-fold. In exchange you get the -flexibility of running arbitrary Rust code within the compiler. Syntax -extension plugins are sometimes called *procedural macros* for this reason. +[items]: ../reference.html#items + +# Further reading + +The [advanced macros chapter][] goes into more detail about macro syntax. It +also describes how to share macros between different modules or crates. + +[advanced macros chapter]: advanced-macros.html diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index e6570c2ee74c8..64d540582a399 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -99,8 +99,8 @@ fn grow(&self) -> Circle { # Circle } } ``` -We just say we're returning a `Circle`. With this, we can grow a new circle -that's twice as big as the old one. +We just say we're returning a `Circle`. With this method, we can grow a new +circle with an area that's 100 times larger than the old one. ## Static methods diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index a2b70e96e1e8d..6aced23ede08e 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -293,7 +293,7 @@ struct Foo<'a> { } fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y; + let y = &5; // this is the same as `let _y = 5; let y = &_y;` let f = Foo { x: y }; println!("{}", f.x); diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index e091878cf86ec..abd9af1af33a0 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -273,6 +273,96 @@ One last thing about traits: generic functions with a trait bound use dispatched. What's that mean? Check out the chapter on [static and dynamic dispatch](static-and-dynamic-dispatch.html) for more. +## Where clause + +Writing functions with only a few generic types and a small number of trait +bounds isn't too bad, but as the number increases, the syntax gets increasingly +awkward: + +``` +use std::fmt::Debug; + +fn foo(x: T, y: K) { + x.clone(); + y.clone(); + println!("{:?}", y); +} +``` + +The name of the function is on the far left, and the parameter list is on the +far right. The bounds are getting in the way. + +Rust has a solution, and it's called a '`where` clause': + +``` +use std::fmt::Debug; + +fn foo(x: T, y: K) { + x.clone(); + y.clone(); + println!("{:?}", y); +} + +fn bar(x: T, y: K) where T: Clone, K: Clone + Debug { + x.clone(); + y.clone(); + println!("{:?}", y); +} + +fn main() { + foo("Hello", "world"); + bar("Hello", "workd"); +} +``` + +`foo()` uses the syntax we showed earlier, and `bar()` uses a `where` clause. +All you need to do is leave off the bounds when defining your type parameters, +and then add `where` after the parameter list. For longer lists, whitespace can +be added: + +``` +use std::fmt::Debug; + +fn bar(x: T, y: K) + where T: Clone, + K: Clone + Debug { + + x.clone(); + y.clone(); + println!("{:?}", y); +} +``` + +This flexibility can add clarity in complex situations. + +`where` is also more powerful than the simpler syntax. For example: + +``` +trait ConvertTo { + fn convert(&self) -> Output; +} + +impl ConvertTo for i32 { + fn convert(&self) -> i64 { *self as i64 } +} + +// can be called with T == i32 +fn normal>(x: &T) -> i64 { + x.convert() +} + +// can be called with T == i64 +fn inverse() -> T + // this is using ConvertTo as if it were "ConvertFrom" + where i32: ConvertTo { + 1i32.convert() +} +``` + +This shows off the additional feature of `where` clauses: they allow bounds +where the left-hand side is an arbitrary type (`i32` in this case), not just a +plain type parameter (like `T`). + ## Our `inverse` Example Back in [Generics](generics.html), we were trying to write code like this: diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index b364d00f95c20..4e14085599b60 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -308,7 +308,7 @@ crate to allow) and of course requires an `unsafe` block. ## Assembly template The `assembly template` is the only required parameter and must be a -literal string (i.e `""`) +literal string (i.e. `""`) ``` #![feature(asm)] @@ -412,7 +412,7 @@ memory, `memory` should also be specified. ## Options The last section, `options` is specific to Rust. The format is comma -separated literal strings (i.e `:"foo", "bar", "baz"`). It's used to +separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to specify some extra info about the inline assembly: Current valid options are: @@ -420,7 +420,7 @@ Current valid options are: 1. *volatile* - specifying this is analogous to `__asm__ __volatile__ (...)` in gcc/clang. 2. *alignstack* - certain instructions expect the stack to be - aligned a certain way (i.e SSE) and specifying this indicates to + aligned a certain way (i.e. SSE) and specifying this indicates to the compiler to insert its usual stack alignment code 3. *intel* - use intel syntax instead of the default AT&T. @@ -646,8 +646,8 @@ The `rustc` compiler has certain pluggable operations, that is, functionality that isn't hard-coded into the language, but is implemented in libraries, with a special marker to tell the compiler it exists. The marker is the attribute `#[lang="..."]` and there are -various different values of `...`, i.e. various different "lang -items". +various different values of `...`, i.e. various different 'lang +items'. For example, `Box` pointers require two lang items, one for allocation and one for deallocation. A freestanding program that uses the `Box` diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 0617c604121f4..3830d7fe29532 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -35,14 +35,14 @@ //! //! ``` //! use std::sync::Arc; -//! use std::thread::Thread; +//! use std::thread; //! //! let five = Arc::new(5); //! //! for _ in 0..10 { //! let five = five.clone(); //! -//! Thread::spawn(move || { +//! thread::spawn(move || { //! println!("{:?}", five); //! }); //! } @@ -52,14 +52,14 @@ //! //! ``` //! use std::sync::{Arc, Mutex}; -//! use std::thread::Thread; +//! use std::thread; //! //! let five = Arc::new(Mutex::new(5)); //! //! for _ in 0..10 { //! let five = five.clone(); //! -//! Thread::spawn(move || { +//! thread::spawn(move || { //! let mut number = five.lock().unwrap(); //! //! *number += 1; @@ -95,7 +95,7 @@ use heap::deallocate; /// /// ```rust /// use std::sync::Arc; -/// use std::thread::Thread; +/// use std::thread; /// /// fn main() { /// let numbers: Vec<_> = (0..100u32).map(|i| i as f32).collect(); @@ -104,7 +104,7 @@ use heap::deallocate; /// for _ in 0..10 { /// let child_numbers = shared_numbers.clone(); /// -/// Thread::spawn(move || { +/// thread::spawn(move || { /// let local_numbers = child_numbers.as_slice(); /// /// // Work with the local numbers @@ -621,7 +621,7 @@ mod tests { use std::option::Option::{Some, None}; use std::sync::atomic; use std::sync::atomic::Ordering::{Acquire, SeqCst}; - use std::thread::Thread; + use std::thread; use std::vec::Vec; use super::{Arc, Weak, weak_count, strong_count}; use std::sync::Mutex; @@ -648,7 +648,7 @@ mod tests { let (tx, rx) = channel(); - let _t = Thread::spawn(move || { + let _t = thread::spawn(move || { let arc_v: Arc> = rx.recv().unwrap(); assert_eq!((*arc_v)[3], 4); }); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 87106041c69d7..b3c2638f3ae28 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -126,11 +126,3 @@ pub fn oom() -> ! { // optimize it out). #[doc(hidden)] pub fn fixme_14344_be_sure_to_link_to_collections() {} - -// NOTE: remove after next snapshot -#[cfg(all(stage0, not(test)))] -#[doc(hidden)] -mod std { - pub use core::fmt; - pub use core::option; -} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index ab3c0901bc956..f361c36ec8fa7 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -170,7 +170,7 @@ struct RcBox { weak: Cell } -/// An immutable reference-counted pointer type. +/// A reference-counted pointer type over an immutable value. /// /// See the [module level documentation](./index.html) for more details. #[unsafe_no_drop_flag] @@ -776,9 +776,7 @@ impl RcBoxPtr for Rc { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - if cfg!(not(stage0)) { // NOTE remove cfg after next snapshot - assume(!self._ptr.is_null()); - } + assume(!self._ptr.is_null()); &(**self._ptr) } } @@ -792,9 +790,7 @@ impl RcBoxPtr for Weak { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - if cfg!(not(stage0)) { // NOTE remove cfg after next snapshot - assume(!self._ptr.is_null()); - } + assume(!self._ptr.is_null()); &(**self._ptr) } } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 1d994839d9941..6196d94b5a6bd 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -655,17 +655,7 @@ impl FromIterator for BinaryHeap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for BinaryHeap { - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BinaryHeap { type Item = T; type IntoIter = IntoIter; @@ -675,17 +665,7 @@ impl IntoIterator for BinaryHeap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a BinaryHeap where T: Ord { - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a BinaryHeap where T: Ord { type Item = &'a T; type IntoIter = Iter<'a, T>; diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index ca598a8d4d292..0b762788b208a 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -1070,17 +1070,7 @@ impl<'a> RandomAccessIterator for Iter<'a> { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a> IntoIterator for &'a Bitv { - type IntoIter = Iter<'a>; - - fn into_iter(self) -> Iter<'a> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> IntoIterator for &'a Bitv { type Item = bool; type IntoIter = Iter<'a>; @@ -1894,17 +1884,7 @@ impl<'a> Iterator for SymmetricDifference<'a> { #[inline] fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a> IntoIterator for &'a BitvSet { - type IntoIter = SetIter<'a>; - - fn into_iter(self) -> SetIter<'a> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> IntoIterator for &'a BitvSet { type Item = usize; type IntoIter = SetIter<'a>; diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 84f9825e989b3..747211e923859 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -462,17 +462,7 @@ impl BTreeMap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for BTreeMap { - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeMap { type Item = (K, V); type IntoIter = IntoIter; @@ -482,17 +472,7 @@ impl IntoIterator for BTreeMap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, K, V> IntoIterator for &'a BTreeMap { - type IntoIter = Iter<'a, K, V>; - - fn into_iter(self) -> Iter<'a, K, V> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> IntoIterator for &'a BTreeMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -502,17 +482,7 @@ impl<'a, K, V> IntoIterator for &'a BTreeMap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, K, V> IntoIterator for &'a mut BTreeMap { - type IntoIter = IterMut<'a, K, V>; - - fn into_iter(mut self) -> IterMut<'a, K, V> { - self.iter_mut() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> IntoIterator for &'a mut BTreeMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index aecf594031192..7ef887b70cc6c 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -480,17 +480,7 @@ impl FromIterator for BTreeSet { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for BTreeSet { - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeSet { type Item = T; type IntoIter = IntoIter; @@ -500,17 +490,7 @@ impl IntoIterator for BTreeSet { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a BTreeSet { - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a BTreeSet { type Item = &'a T; type IntoIter = Iter<'a, T>; diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 27b282ee9a9c1..eb1bf93c0aafc 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -837,17 +837,7 @@ impl FromIterator for DList { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for DList { - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for DList { type Item = T; type IntoIter = IntoIter; @@ -857,17 +847,7 @@ impl IntoIterator for DList { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a DList { - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a DList { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -877,17 +857,6 @@ impl<'a, T> IntoIterator for &'a DList { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a mut DList { - type IntoIter = IterMut<'a, T>; - - fn into_iter(mut self) -> IterMut<'a, T> { - self.iter_mut() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot impl<'a, T> IntoIterator for &'a mut DList { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; @@ -971,7 +940,7 @@ mod tests { use prelude::*; use std::rand; use std::hash::{self, SipHasher}; - use std::thread::Thread; + use std::thread; use test::Bencher; use test; @@ -1320,7 +1289,7 @@ mod tests { #[test] fn test_send() { let n = list_from(&[1,2,3]); - Thread::scoped(move || { + thread::spawn(move || { check_links(&n); let a: &[_] = &[&1,&2,&3]; assert_eq!(a, n.iter().collect::>()); diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 5c37be188fea4..d5403ca5d9b19 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -257,17 +257,7 @@ impl FromIterator for EnumSet { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, E> IntoIterator for &'a EnumSet where E: CLike { - type IntoIter = Iter; - - fn into_iter(self) -> Iter { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, E> IntoIterator for &'a EnumSet where E: CLike { type Item = E; type IntoIter = Iter; diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 8325e7247d5fc..cacbf3bce80f0 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -111,15 +111,6 @@ pub fn fixme_14344_be_sure_to_link_to_collections() {} #[cfg(not(test))] mod std { - // NOTE: remove after next snapshot - #[cfg(stage0)] pub use core::clone; // derive(Clone) - #[cfg(stage0)] pub use core::cmp; // derive(Eq, Ord, etc.) - #[cfg(stage0)] pub use core::marker; // derive(Copy) - #[cfg(stage0)] pub use core::hash; // derive(Hash) - #[cfg(stage0)] pub use core::iter; - #[cfg(stage0)] pub use core::fmt; // necessary for panic!() - #[cfg(stage0)] pub use core::option; // necessary for panic!() - pub use core::ops; // RangeFull } diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs index 79c86a846f1b9..ebcfb8d1cf84e 100644 --- a/src/libcollections/macros.rs +++ b/src/libcollections/macros.rs @@ -9,12 +9,34 @@ // except according to those terms. /// Creates a `Vec` containing the arguments. +/// +/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions. +/// There are two forms of this macro: +/// +/// - Create a `Vec` containing a given list of elements: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// assert_eq!(v[0], 1); +/// assert_eq!(v[1], 2); +/// assert_eq!(v[2], 3); +/// ``` +/// +/// - Create a `Vec` from a given element and size: +/// +/// ``` +/// let v = vec![1; 3]; +/// assert_eq!(v, vec![1, 1, 1]); +/// ``` +/// +/// Note that unlike array expressions this syntax supports all elements +/// which implement `Clone` and the number of elements doesn't have to be +/// a constant. #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! vec { - ($x:expr; $y:expr) => ( - <[_] as $crate::slice::SliceExt>::into_vec( - $crate::boxed::Box::new([$x; $y])) + ($elem:expr; $n:expr) => ( + $crate::vec::from_elem($elem, $n) ); ($($x:expr),*) => ( <[_] as $crate::slice::SliceExt>::into_vec( diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 0a4ccde923667..6dcdb21f8000b 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! This crate implements a double-ended queue with `O(1)` amortized inserts and removals from both -//! ends of the container. It also has `O(1)` indexing like a vector. The contained elements are -//! not required to be copyable, and the queue will be sendable if the contained type is sendable. +//! RingBuf is a double-ended queue, which is implemented with the help of a +//! growing circular buffer. +//! +//! This queue has `O(1)` amortized inserts and removals from both ends of the +//! container. It also has `O(1)` indexing like a vector. The contained elements +//! are not required to be copyable, and the queue will be sendable if the +//! contained type is sendable. #![stable(feature = "rust1", since = "1.0.0")] @@ -113,7 +117,8 @@ impl RingBuf { #[inline] fn is_full(&self) -> bool { self.cap - self.len() == 1 } - /// Returns the index in the underlying buffer for a given logical element index. + /// Returns the index in the underlying buffer for a given logical element + /// index. #[inline] fn wrap_index(&self, idx: usize) -> usize { wrap_index(idx, self.cap) } @@ -1699,17 +1704,7 @@ impl FromIterator for RingBuf { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for RingBuf { - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for RingBuf { type Item = T; type IntoIter = IntoIter; @@ -1719,17 +1714,7 @@ impl IntoIterator for RingBuf { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a RingBuf { - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a RingBuf { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1739,17 +1724,7 @@ impl<'a, T> IntoIterator for &'a RingBuf { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a mut RingBuf { - type IntoIter = IterMut<'a, T>; - - fn into_iter(mut self) -> IterMut<'a, T> { - self.iter_mut() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a mut RingBuf { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index f294dd3c3e0f6..bde733644b5b5 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1252,6 +1252,30 @@ unsafe fn dealloc(ptr: *mut T, len: usize) { } } +#[doc(hidden)] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_elem(elem: T, n: usize) -> Vec { + unsafe { + let mut v = Vec::with_capacity(n); + let mut ptr = v.as_mut_ptr(); + + // Write all elements except the last one + for i in 1..n { + ptr::write(ptr, Clone::clone(&elem)); + ptr = ptr.offset(1); + v.set_len(i); // Increment the length in every step in case Clone::clone() panics + } + + if n > 0 { + // We can write the last element directly without cloning needlessly + ptr::write(ptr, elem); + v.set_len(n); + } + + v + } +} + //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// @@ -1383,7 +1407,7 @@ impl ops::DerefMut for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for Vec { #[inline] - fn from_iter>(iterator: I) -> Vec { + fn from_iter>(mut iterator: I) -> Vec { let (lower, _) = iterator.size_hint(); let mut vector = Vec::with_capacity(lower); @@ -1393,13 +1417,20 @@ impl FromIterator for Vec { // vector.push(item); // } // - // This equivalent crucially runs the iterator precisely once. The - // optimization below (eliding bound/growth checks) means that we - // actually run the iterator twice. To ensure the "moral equivalent" we - // do a `fuse()` operation to ensure that the iterator continues to - // return `None` after seeing the first `None`. - let mut i = iterator.fuse(); - for element in i.by_ref().take(vector.capacity()) { + // This equivalent crucially runs the iterator precisely once. Below we + // actually in theory run the iterator twice (one without bounds checks + // and one with). To achieve the "moral equivalent", we use the `if` + // statement below to break out early. + // + // If the first loop has terminated, then we have one of two conditions. + // + // 1. The underlying iterator returned `None`. In this case we are + // guaranteed that less than `vector.capacity()` elements have been + // returned, so we break out early. + // 2. The underlying iterator yielded `vector.capacity()` elements and + // has not yielded `None` yet. In this case we run the iterator to + // its end below. + for element in iterator.by_ref().take(vector.capacity()) { let len = vector.len(); unsafe { ptr::write(vector.get_unchecked_mut(len), element); @@ -1407,24 +1438,16 @@ impl FromIterator for Vec { } } - for element in i { - vector.push(element) + if vector.len() == vector.capacity() { + for element in iterator { + vector.push(element); + } } vector } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for Vec { - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for Vec { type Item = T; type IntoIter = IntoIter; @@ -1434,17 +1457,7 @@ impl IntoIterator for Vec { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a Vec { - type IntoIter = slice::Iter<'a, T>; - - fn into_iter(self) -> slice::Iter<'a, T> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a Vec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -1454,17 +1467,7 @@ impl<'a, T> IntoIterator for &'a Vec { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a mut Vec { - type IntoIter = slice::IterMut<'a, T>; - - fn into_iter(mut self) -> slice::IterMut<'a, T> { - self.iter_mut() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a mut Vec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 7f9484c58a185..82ccfd0614fd5 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -668,17 +668,7 @@ impl FromIterator<(usize, V)> for VecMap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for VecMap { - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for VecMap { type Item = (usize, T); type IntoIter = IntoIter; @@ -688,17 +678,7 @@ impl IntoIterator for VecMap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a VecMap { - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a VecMap { type Item = (usize, &'a T); type IntoIter = Iter<'a, T>; @@ -708,17 +688,7 @@ impl<'a, T> IntoIterator for &'a VecMap { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a mut VecMap { - type IntoIter = IterMut<'a, T>; - - fn into_iter(mut self) -> IterMut<'a, T> { - self.iter_mut() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a mut VecMap { type Item = (usize, &'a mut T); type IntoIter = IterMut<'a, T>; diff --git a/src/libcore/array.rs b/src/libcore/array.rs index abaa7594d0478..838ca4e478b72 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -48,17 +48,7 @@ macro_rules! array_impls { } } - // NOTE(stage0): remove impl after a snapshot - #[cfg(stage0)] - impl<'a, T> IntoIterator for &'a [T; $N] { - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } - } - - #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a [T; $N] { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -68,17 +58,7 @@ macro_rules! array_impls { } } - // NOTE(stage0): remove impl after a snapshot - #[cfg(stage0)] - impl<'a, T> IntoIterator for &'a mut [T; $N] { - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } - } - - #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a mut [T; $N] { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index 32e8cffcae4f9..05d864accc130 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -42,13 +42,13 @@ //! ``` //! use std::sync::Arc; //! use std::sync::atomic::{AtomicUsize, Ordering}; -//! use std::thread::Thread; +//! use std::thread; //! //! fn main() { //! let spinlock = Arc::new(AtomicUsize::new(1)); //! //! let spinlock_clone = spinlock.clone(); -//! Thread::spawn(move|| { +//! thread::spawn(move|| { //! spinlock_clone.store(0, Ordering::SeqCst); //! }); //! diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index cf293ded13f00..eb138e6142b80 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -78,12 +78,12 @@ //! use std::cell::RefCell; //! //! struct Graph { -//! edges: Vec<(uint, uint)>, -//! span_tree_cache: RefCell>> +//! edges: Vec<(i32, i32)>, +//! span_tree_cache: RefCell>> //! } //! //! impl Graph { -//! fn minimum_spanning_tree(&self) -> Vec<(uint, uint)> { +//! fn minimum_spanning_tree(&self) -> Vec<(i32, i32)> { //! // Create a new scope to contain the lifetime of the //! // dynamic borrow //! { @@ -104,7 +104,7 @@ //! // This is the major hazard of using `RefCell`. //! self.minimum_spanning_tree() //! } -//! # fn calc_span_tree(&self) -> Vec<(uint, uint)> { vec![] } +//! # fn calc_span_tree(&self) -> Vec<(i32, i32)> { vec![] } //! } //! ``` //! @@ -125,7 +125,7 @@ //! //! struct RcBox { //! value: T, -//! refcount: Cell +//! refcount: Cell //! } //! //! impl Clone for Rc { @@ -279,8 +279,8 @@ pub enum BorrowState { } // Values [1, MAX-1] represent the number of `Ref` active -// (will not outgrow its range since `uint` is the size of the address space) -type BorrowFlag = uint; +// (will not outgrow its range since `usize` is the size of the address space) +type BorrowFlag = usize; const UNUSED: BorrowFlag = 0; const WRITING: BorrowFlag = -1; @@ -375,9 +375,9 @@ impl RefCell { /// /// ``` /// use std::cell::RefCell; - /// use std::thread::Thread; + /// use std::thread; /// - /// let result = Thread::scoped(move || { + /// let result = thread::spawn(move || { /// let c = RefCell::new(5); /// let m = c.borrow_mut(); /// @@ -436,9 +436,9 @@ impl RefCell { /// /// ``` /// use std::cell::RefCell; - /// use std::thread::Thread; + /// use std::thread; /// - /// let result = Thread::scoped(move || { + /// let result = thread::spawn(move || { /// let c = RefCell::new(5); /// let m = c.borrow_mut(); /// @@ -649,8 +649,7 @@ impl<'b, T> DerefMut for RefMut<'b, T> { /// /// **NOTE:** `UnsafeCell`'s fields are public to allow static initializers. It is not /// recommended to access its fields directly, `get` should be used instead. -#[cfg_attr(stage0, lang="unsafe")] // NOTE: remove after next snapshot -#[cfg_attr(not(stage0), lang="unsafe_cell")] +#[lang="unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] pub struct UnsafeCell { /// Wrapped value diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 1ebd2df5814d1..19ec245300d02 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -8,35 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Defines the `PartialOrd` and `PartialEq` comparison traits. +//! Functionality for ordering and comparison. //! -//! This module defines both `PartialOrd` and `PartialEq` traits which are used by the -//! compiler to implement comparison operators. Rust programs may implement -//!`PartialOrd` to overload the `<`, `<=`, `>`, and `>=` operators, and may implement -//! `PartialEq` to overload the `==` and `!=` operators. +//! This module defines both `PartialOrd` and `PartialEq` traits which are used by the compiler to +//! implement comparison operators. Rust programs may implement `PartialOrd` to overload the `<`, +//! `<=`, `>`, and `>=` operators, and may implement `PartialEq` to overload the `==` and `!=` +//! operators. //! -//! For example, to define a type with a customized definition for the PartialEq -//! operators, you could do the following: +//! For example, to define a type with a customized definition for the PartialEq operators, you +//! could do the following: //! -//! ```rust +//! ``` //! use core::num::SignedInt; //! -//! // Our type. -//! struct SketchyNum { -//! num : int +//! struct FuzzyNum { +//! num: i32, //! } //! -//! // Our implementation of `PartialEq` to support `==` and `!=`. -//! impl PartialEq for SketchyNum { +//! impl PartialEq for FuzzyNum { //! // Our custom eq allows numbers which are near each other to be equal! :D -//! fn eq(&self, other: &SketchyNum) -> bool { +//! fn eq(&self, other: &FuzzyNum) -> bool { //! (self.num - other.num).abs() < 5 //! } //! } //! //! // Now these binary operators will work when applied! -//! assert!(SketchyNum {num: 37} == SketchyNum {num: 34}); -//! assert!(SketchyNum {num: 25} != SketchyNum {num: 57}); +//! assert!(FuzzyNum { num: 37 } == FuzzyNum { num: 34 }); +//! assert!(FuzzyNum { num: 25 } != FuzzyNum { num: 57 }); //! ``` #![stable(feature = "rust1", since = "1.0.0")] @@ -49,24 +47,22 @@ use option::Option::{self, Some, None}; /// Trait for equality comparisons which are [partial equivalence relations]( /// http://en.wikipedia.org/wiki/Partial_equivalence_relation). /// -/// This trait allows for partial equality, for types that do not have a full -/// equivalence relation. For example, in floating point numbers `NaN != NaN`, -/// so floating point types implement `PartialEq` but not `Eq`. +/// This trait allows for partial equality, for types that do not have a full equivalence relation. +/// For example, in floating point numbers `NaN != NaN`, so floating point types implement +/// `PartialEq` but not `Eq`. /// /// Formally, the equality must be (for all `a`, `b` and `c`): /// /// - symmetric: `a == b` implies `b == a`; and /// - transitive: `a == b` and `b == c` implies `a == c`. /// -/// Note that these requirements mean that the trait itself must be -/// implemented symmetrically and transitively: if `T: PartialEq` -/// and `U: PartialEq` then `U: PartialEq` and `T: +/// Note that these requirements mean that the trait itself must be implemented symmetrically and +/// transitively: if `T: PartialEq` and `U: PartialEq` then `U: PartialEq` and `T: /// PartialEq`. /// -/// PartialEq only requires the `eq` method to be implemented; `ne` is defined -/// in terms of it by default. Any manual implementation of `ne` *must* respect -/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and -/// only if `a != b`. +/// PartialEq only requires the `eq` method to be implemented; `ne` is defined in terms of it by +/// default. Any manual implementation of `ne` *must* respect the rule that `eq` is a strict +/// inverse of `ne`; that is, `!(a == b)` if and only if `a != b`. #[lang="eq"] #[stable(feature = "rust1", since = "1.0.0")] #[old_orphan_check] @@ -84,12 +80,15 @@ pub trait PartialEq { /// Trait for equality comparisons which are [equivalence relations]( /// https://en.wikipedia.org/wiki/Equivalence_relation). /// -/// This means, that in addition to `a == b` and `a != b` being strict -/// inverses, the equality must be (for all `a`, `b` and `c`): +/// This means, that in addition to `a == b` and `a != b` being strict inverses, the equality must +/// be (for all `a`, `b` and `c`): /// /// - reflexive: `a == a`; /// - symmetric: `a == b` implies `b == a`; and /// - transitive: `a == b` and `b == c` implies `a == c`. +/// +/// This property cannot be checked by the compiler, and therefore `Eq` implies +/// `PartialEq`, and has no extra methods. #[stable(feature = "rust1", since = "1.0.0")] pub trait Eq: PartialEq { // FIXME #13101: this method is used solely by #[deriving] to @@ -101,10 +100,26 @@ pub trait Eq: PartialEq { // This should never be implemented by hand. #[doc(hidden)] #[inline(always)] + #[stable(feature = "rust1", since = "1.0.0")] fn assert_receiver_is_total_eq(&self) {} } -/// An ordering is, e.g, a result of a comparison between two values. +/// An `Ordering` is the result of a comparison between two values. +/// +/// # Examples +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// let result = 1.cmp(&2); +/// assert_eq!(Ordering::Less, result); +/// +/// let result = 1.cmp(&1); +/// assert_eq!(Ordering::Equal, result); +/// +/// let result = 2.cmp(&1); +/// assert_eq!(Ordering::Greater, result); +/// ``` #[derive(Clone, Copy, PartialEq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Ordering { @@ -120,17 +135,28 @@ pub enum Ordering { } impl Ordering { - /// Reverse the `Ordering`, so that `Less` becomes `Greater` and - /// vice versa. + /// Reverse the `Ordering`. /// - /// # Example + /// * `Less` becomes `Greater`. + /// * `Greater` becomes `Less`. + /// * `Equal` becomes `Equal`. /// - /// ```rust - /// use std::cmp::Ordering::{Less, Equal, Greater}; + /// # Examples /// - /// assert_eq!(Less.reverse(), Greater); - /// assert_eq!(Equal.reverse(), Equal); - /// assert_eq!(Greater.reverse(), Less); + /// Basic behavior: + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.reverse(), Ordering::Greater); + /// assert_eq!(Ordering::Equal.reverse(), Ordering::Equal); + /// assert_eq!(Ordering::Greater.reverse(), Ordering::Less); + /// ``` + /// + /// This method can be used to reverse a comparison: + /// + /// ``` + /// use std::cmp::Ordering; /// /// let mut data: &mut [_] = &mut [2, 10, 5, 8]; /// @@ -155,28 +181,27 @@ impl Ordering { } } -/// Trait for types that form a [total order]( -/// https://en.wikipedia.org/wiki/Total_order). +/// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// /// An order is a total order if it is (for all `a`, `b` and `c`): /// -/// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is -/// true; and -/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for -/// both `==` and `>`. +/// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and +/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { - /// This method returns an ordering between `self` and `other` values. + /// This method returns an `Ordering` between `self` and `other`. /// - /// By convention, `self.cmp(&other)` returns the ordering matching - /// the expression `self other` if true. For example: + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples /// /// ``` - /// use std::cmp::Ordering::{Less, Equal, Greater}; + /// use std::cmp::Ordering; /// - /// assert_eq!( 5.cmp(&10), Less); // because 5 < 10 - /// assert_eq!(10.cmp(&5), Greater); // because 10 > 5 - /// assert_eq!( 5.cmp(&5), Equal); // because 5 == 5 + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn cmp(&self, other: &Self) -> Ordering; @@ -208,30 +233,60 @@ impl PartialOrd for Ordering { /// The comparison must satisfy, for all `a`, `b` and `c`: /// /// - antisymmetry: if `a < b` then `!(a > b)` and vice versa; and -/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for -/// both `==` and `>`. +/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. /// -/// Note that these requirements mean that the trait itself must be -/// implemented symmetrically and transitively: if `T: PartialOrd` -/// and `U: PartialOrd` then `U: PartialOrd` and `T: +/// Note that these requirements mean that the trait itself must be implemented symmetrically and +/// transitively: if `T: PartialOrd` and `U: PartialOrd` then `U: PartialOrd` and `T: /// PartialOrd`. /// -/// PartialOrd only requires implementation of the `partial_cmp` method, -/// with the others generated from default implementations. +/// PartialOrd only requires implementation of the `partial_cmp` method, with the others generated +/// from default implementations. /// -/// However it remains possible to implement the others separately for types -/// which do not have a total order. For example, for floating point numbers, -/// `NaN < 0 == false` and `NaN >= 0 == false` (cf. IEEE 754-2008 section -/// 5.11). +/// However it remains possible to implement the others separately for types which do not have a +/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == +/// false` (cf. IEEE 754-2008 section 5.11). #[lang="ord"] #[stable(feature = "rust1", since = "1.0.0")] pub trait PartialOrd: PartialEq { - /// This method returns an ordering between `self` and `other` values - /// if one exists. + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = std::f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn partial_cmp(&self, other: &Rhs) -> Option; /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn lt(&self, other: &Rhs) -> bool { @@ -241,7 +296,18 @@ pub trait PartialOrd: PartialEq { } } - /// This method tests less than or equal to (`<=`). + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn le(&self, other: &Rhs) -> bool { @@ -251,7 +317,17 @@ pub trait PartialOrd: PartialEq { } } - /// This method tests greater than (`>`). + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn gt(&self, other: &Rhs) -> bool { @@ -261,7 +337,18 @@ pub trait PartialOrd: PartialEq { } } - /// This method tests greater than or equal to (`>=`). + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn ge(&self, other: &Rhs) -> bool { @@ -273,6 +360,15 @@ pub trait PartialOrd: PartialEq { } /// Compare and return the minimum of two values. +/// +/// # Examples +/// +/// ``` +/// use std::cmp; +/// +/// assert_eq!(1, cmp::min(1, 2)); +/// assert_eq!(2, cmp::min(2, 2)); +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min(v1: T, v2: T) -> T { @@ -280,6 +376,15 @@ pub fn min(v1: T, v2: T) -> T { } /// Compare and return the maximum of two values. +/// +/// # Examples +/// +/// ``` +/// use std::cmp; +/// +/// assert_eq!(2, cmp::max(1, 2)); +/// assert_eq!(2, cmp::max(2, 2)); +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn max(v1: T, v2: T) -> T { @@ -289,6 +394,24 @@ pub fn max(v1: T, v2: T) -> T { /// Compare and return the minimum of two values if there is one. /// /// Returns the first argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// use std::cmp; +/// +/// assert_eq!(Some(1), cmp::partial_min(1, 2)); +/// assert_eq!(Some(2), cmp::partial_min(2, 2)); +/// ``` +/// +/// When comparison is impossible: +/// +/// ``` +/// use std::cmp; +/// +/// let result = cmp::partial_min(std::f64::NAN, 1.0); +/// assert_eq!(result, None); +/// ``` #[inline] #[unstable(feature = "core")] pub fn partial_min(v1: T, v2: T) -> Option { @@ -302,6 +425,24 @@ pub fn partial_min(v1: T, v2: T) -> Option { /// Compare and return the maximum of two values if there is one. /// /// Returns the first argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// use std::cmp; +/// +/// assert_eq!(Some(2), cmp::partial_max(1, 2)); +/// assert_eq!(Some(2), cmp::partial_max(2, 2)); +/// ``` +/// +/// When comparison is impossible: +/// +/// ``` +/// use std::cmp; +/// +/// let result = cmp::partial_max(std::f64::NAN, 1.0); +/// assert_eq!(result, None); +/// ``` #[inline] #[unstable(feature = "core")] pub fn partial_max(v1: T, v2: T) -> Option { diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 09733df35398f..67c8c9fec09ab 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -197,6 +197,7 @@ impl<'a> Arguments<'a> { /// created with `argumentuint`. However, failing to do so doesn't cause /// unsafety, but will ignore invalid . #[doc(hidden)] #[inline] + #[stable(feature = "rust1", since = "1.0.0")] pub fn new_v1_formatted(pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument]) -> Arguments<'a> { diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 03c473ed96741..fffba1561a380 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -118,21 +118,13 @@ pub trait FromIterator { fn from_iter>(iterator: T) -> Self; } -// NOTE(stage0): remove trait after a snapshot -#[cfg(stage0)] /// Conversion into an `Iterator` +#[stable(feature = "rust1", since = "1.0.0")] pub trait IntoIterator { - type IntoIter: Iterator; - - /// Consumes `Self` and returns an iterator over it #[stable(feature = "rust1", since = "1.0.0")] - fn into_iter(self) -> Self::IntoIter; -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot -/// Conversion into an `Iterator` -pub trait IntoIterator { type Item; + + #[stable(feature = "rust1", since = "1.0.0")] type IntoIter: Iterator; /// Consumes `Self` and returns an iterator over it @@ -140,17 +132,7 @@ pub trait IntoIterator { fn into_iter(self) -> Self::IntoIter; } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for I where I: Iterator { - type IntoIter = I; - - fn into_iter(self) -> I { - self - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for I { type Item = I::Item; type IntoIter = I; @@ -2374,7 +2356,7 @@ impl Iterator for Unfold where F: FnMut(&mut St) -> Option { /// iteration #[derive(Clone)] #[unstable(feature = "core", - reason = "may be renamed or replaced by range notation adapaters")] + reason = "may be renamed or replaced by range notation adapters")] pub struct Counter { /// The current state the counter is at (next value to be yielded) state: A, @@ -2385,7 +2367,7 @@ pub struct Counter { /// Creates a new counter with the specified start/step #[inline] #[unstable(feature = "core", - reason = "may be renamed or replaced by range notation adapaters")] + reason = "may be renamed or replaced by range notation adapters")] pub fn count(start: A, step: A) -> Counter { Counter{state: start, step: step} } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 7243bd4f0cb25..f0c60ffe4bf66 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -67,6 +67,7 @@ #![feature(simd, unsafe_destructor)] #![feature(staged_api)] #![feature(unboxed_closures)] +#![feature(rustc_attrs)] #[macro_use] mod macros; @@ -153,25 +154,16 @@ mod array; mod core { pub use panicking; pub use fmt; - #[cfg(not(stage0))] pub use clone; - #[cfg(not(stage0))] pub use cmp; - #[cfg(not(stage0))] pub use hash; - #[cfg(not(stage0))] pub use marker; - #[cfg(not(stage0))] pub use option; - #[cfg(not(stage0))] pub use iter; + pub use clone; + pub use cmp; + pub use hash; + pub use marker; + pub use option; + pub use iter; } #[doc(hidden)] mod std { - // NOTE: remove after next snapshot - #[cfg(stage0)] pub use clone; - #[cfg(stage0)] pub use cmp; - #[cfg(stage0)] pub use hash; - #[cfg(stage0)] pub use marker; - #[cfg(stage0)] pub use option; - #[cfg(stage0)] pub use fmt; - #[cfg(stage0)] pub use iter; - // range syntax pub use ops; } diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index da93d4f6ca44e..56e1c5dedc1ce 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -32,9 +32,19 @@ use clone::Clone; reason = "will be overhauled with new lifetime rules; see RFC 458")] #[lang="send"] #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +#[cfg(stage0)] pub unsafe trait Send: 'static { // empty. } +/// Types able to be transferred across thread boundaries. +#[unstable(feature = "core", + reason = "will be overhauled with new lifetime rules; see RFC 458")] +#[lang="send"] +#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +#[cfg(not(stage0))] +pub unsafe trait Send { + // empty. +} /// Types with a constant size known at compile-time. #[stable(feature = "rust1", since = "1.0.0")] @@ -424,3 +434,11 @@ pub struct NoCopy; #[lang="managed_bound"] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Managed; + +#[cfg(not(stage0))] +mod impls { + use super::{Send, Sync, Sized}; + + unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {} + unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {} +} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 51bf3c1648f56..740997b7a249d 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -43,7 +43,7 @@ pub use intrinsics::forget; /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn size_of() -> uint { +pub fn size_of() -> usize { unsafe { intrinsics::size_of::() } } @@ -58,7 +58,7 @@ pub fn size_of() -> uint { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn size_of_val(_val: &T) -> uint { +pub fn size_of_val(_val: &T) -> usize { size_of::() } @@ -75,7 +75,7 @@ pub fn size_of_val(_val: &T) -> uint { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn min_align_of() -> uint { +pub fn min_align_of() -> usize { unsafe { intrinsics::min_align_of::() } } @@ -90,7 +90,7 @@ pub fn min_align_of() -> uint { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn min_align_of_val(_val: &T) -> uint { +pub fn min_align_of_val(_val: &T) -> usize { min_align_of::() } @@ -108,7 +108,7 @@ pub fn min_align_of_val(_val: &T) -> uint { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn align_of() -> uint { +pub fn align_of() -> usize { // We use the preferred alignment as the default alignment for a type. This // appears to be what clang migrated towards as well: // @@ -130,7 +130,7 @@ pub fn align_of() -> uint { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn align_of_val(_val: &T) -> uint { +pub fn align_of_val(_val: &T) -> usize { align_of::() } @@ -150,7 +150,7 @@ pub fn align_of_val(_val: &T) -> uint { /// ``` /// use std::mem; /// -/// let x: int = unsafe { mem::zeroed() }; +/// let x: i32 = unsafe { mem::zeroed() }; /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -171,7 +171,7 @@ pub unsafe fn zeroed() -> T { /// ``` /// use std::mem; /// -/// let x: int = unsafe { mem::uninitialized() }; +/// let x: i32 = unsafe { mem::uninitialized() }; /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 3f83302742c8c..5644f76306929 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -19,8 +19,8 @@ pub unsafe trait Zeroable {} unsafe impl Zeroable for *const T {} unsafe impl Zeroable for *mut T {} unsafe impl Zeroable for Unique { } -unsafe impl Zeroable for int {} -unsafe impl Zeroable for uint {} +unsafe impl Zeroable for isize {} +unsafe impl Zeroable for usize {} unsafe impl Zeroable for i8 {} unsafe impl Zeroable for u8 {} unsafe impl Zeroable for i16 {} diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 3dc94ba555f35..9a89682127fb1 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -605,6 +605,8 @@ impl Option { /// Returns `None` if the option is `None`, otherwise calls `f` with the /// wrapped value and returns the result. /// + /// Some languages call this operation flatmap. + /// /// # Example /// /// ``` diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index cd91843f359ea..bbfe7e58ef4ac 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -626,17 +626,7 @@ impl<'a, T> Default for &'a [T] { // Iterators // -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a [T] { - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a [T] { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -646,17 +636,7 @@ impl<'a, T> IntoIterator for &'a [T] { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T> IntoIterator for &'a mut [T] { - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a mut [T] { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; diff --git a/src/libcoretest/finally.rs b/src/libcoretest/finally.rs index 42c2dfbda082a..55fcb8498513c 100644 --- a/src/libcoretest/finally.rs +++ b/src/libcoretest/finally.rs @@ -11,7 +11,7 @@ #![allow(deprecated)] use core::finally::{try_finally, Finally}; -use std::thread::Thread; +use std::thread; #[test] fn test_success() { @@ -22,7 +22,7 @@ fn test_success() { *i = 10; }, |i| { - assert!(!Thread::panicking()); + assert!(!thread::panicking()); assert_eq!(*i, 10); *i = 20; }); @@ -40,7 +40,7 @@ fn test_fail() { panic!(); }, |i| { - assert!(Thread::panicking()); + assert!(thread::panicking()); assert_eq!(*i, 10); }) } diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index ca184fb8736cd..c743119f40909 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -92,6 +92,7 @@ #![feature(collections)] #![feature(int_uint)] #![feature(staged_api)] +#![feature(str_words)] #![cfg_attr(test, feature(rustc_private))] #[cfg(test)] #[macro_use] extern crate log; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index a1a271bc5abb5..230deabee0034 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -276,7 +276,7 @@ #![feature(int_uint)] #![feature(collections)] #![feature(core)] -#![feature(io)] +#![feature(old_io)] use self::LabelText::*; diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index e42b6c9c356d7..0aa41e03f9f71 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -5734,10 +5734,3 @@ pub mod funcs { pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen correctly #[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows - -// NOTE: remove after next snapshot -#[doc(hidden)] -#[cfg(all(stage0, not(test)))] -mod std { - pub use core::marker; -} diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 5edb4a96a7df6..4dab07acfd2a0 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -171,7 +171,7 @@ #![feature(box_syntax)] #![feature(int_uint)] #![feature(core)] -#![feature(io)] +#![feature(old_io)] #![feature(std_misc)] #![feature(env)] diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 4113718cfd15b..915c70bbf8ce1 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -497,17 +497,6 @@ pub struct Open01(pub F); /// ``` pub struct Closed01(pub F); -// NOTE: remove after next snapshot -#[cfg(all(stage0, not(test)))] -mod std { - pub use core::{option, fmt}; // panic!() - pub use core::clone; // derive Clone - pub use core::marker; - // for-loops - pub use core::iter; - pub use core::ops; // slicing syntax -} - #[cfg(test)] mod test { use std::rand; diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 154dbbdb75034..488d599932386 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -28,7 +28,7 @@ #![feature(collections)] #![feature(core)] #![feature(int_uint)] -#![feature(io)] +#![feature(old_io)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc/README.txt b/src/librustc/README.txt index 697dddca74fb1..37097764f717c 100644 --- a/src/librustc/README.txt +++ b/src/librustc/README.txt @@ -4,8 +4,8 @@ An informal guide to reading and working on the rustc compiler. If you wish to expand on this document, or have a more experienced Rust contributor add anything else to it, please get in touch: -https://github.com/rust-lang/rust/wiki/Note-development-policy -("Communication" subheading) +* http://internals.rust-lang.org/ +* https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust or file a bug: diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index abf70813d36e7..fe9a81bb7c984 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,10 +29,10 @@ #![feature(core)] #![feature(hash)] #![feature(int_uint)] -#![feature(io)] +#![feature(old_io)] #![feature(libc)] #![feature(env)] -#![feature(path)] +#![feature(old_path)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index d09e4bd975924..ba108b5488ede 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -47,6 +47,7 @@ use syntax::{abi, ast, ast_map}; use syntax::ast_util::is_shift_binop; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{self, Span}; +use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; use syntax::parse::token; use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64}; use syntax::ast_util; @@ -640,67 +641,19 @@ impl LintPass for UnusedAttributes { } fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) { - static ATTRIBUTE_WHITELIST: &'static [&'static str] = &[ - // FIXME: #14408 whitelist docs since rustdoc looks at them - "doc", - - // FIXME: #14406 these are processed in trans, which happens after the - // lint pass - "cold", - "export_name", - "inline", - "link", - "link_name", - "link_section", - "linkage", - "no_builtins", - "no_mangle", - "no_split_stack", - "no_stack_check", - "packed", - "static_assert", - "thread_local", - "no_debug", - "omit_gdb_pretty_printer_section", - "unsafe_no_drop_flag", - - // used in resolve - "prelude_import", - - // FIXME: #14407 these are only looked at on-demand so we can't - // guarantee they'll have already been checked - "deprecated", - "must_use", - "stable", - "unstable", - "rustc_on_unimplemented", - "rustc_error", - - // FIXME: #19470 this shouldn't be needed forever - "old_orphan_check", - "old_impl_check", - "rustc_paren_sugar", // FIXME: #18101 temporary unboxed closure hack - ]; - - static CRATE_ATTRS: &'static [&'static str] = &[ - "crate_name", - "crate_type", - "feature", - "no_start", - "no_main", - "no_std", - "no_builtins", - ]; - - for &name in ATTRIBUTE_WHITELIST { - if attr.check_name(name) { - break; + for &(ref name, ty) in KNOWN_ATTRIBUTES { + match ty { + AttributeType::Whitelisted + | AttributeType::Gated(_, _) if attr.check_name(name) => { + break; + }, + _ => () } } if !attr::is_used(attr) { cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); - if CRATE_ATTRS.contains(&&attr.name()[]) { + if KNOWN_ATTRIBUTES.contains(&(&attr.name()[], AttributeType::CrateLevel)) { let msg = match attr.node.style { ast::AttrOuter => "crate-level attribute should be an inner \ attribute: add an exclamation mark: #![foo]", @@ -1761,7 +1714,7 @@ impl LintPass for Stability { } fn check_item(&mut self, cx: &Context, item: &ast::Item) { - stability::check_item(cx.tcx, item, + stability::check_item(cx.tcx, item, false, &mut |id, sp, stab| self.lint(cx, id, sp, stab)); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index a086e91f4d9f2..0a0f555f97769 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -261,12 +261,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { if self.tcx.sess.features.borrow().unmarked_api { self.tcx.sess.span_warn(span, "use of unmarked library feature"); self.tcx.sess.span_note(span, "this is either a bug in the library you are \ - using and a bug in the compiler - please \ + using or a bug in the compiler - please \ report it in both places"); } else { self.tcx.sess.span_err(span, "use of unmarked library feature"); self.tcx.sess.span_note(span, "this is either a bug in the library you are \ - using and a bug in the compiler - please \ + using or a bug in the compiler - please \ report it in both places"); self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \ crate attributes to override this"); @@ -283,7 +283,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { // name `__test` if item.span == DUMMY_SP && item.ident.as_str() == "__test" { return } - check_item(self.tcx, item, + check_item(self.tcx, item, true, &mut |id, sp, stab| self.check(id, sp, stab)); visit::walk_item(self, item); } @@ -302,7 +302,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { } /// Helper for discovering nodes to check for stability -pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, +pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool, cb: &mut FnMut(ast::DefId, Span, &Option)) { match item.node { ast::ItemExternCrate(_) => { @@ -316,6 +316,35 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID }; maybe_do_stability_check(tcx, id, item.span, cb); } + + // For implementations of traits, check the stability of each item + // individually as it's possible to have a stable trait with unstable + // items. + ast::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => { + let trait_did = tcx.def_map.borrow()[t.ref_id].def_id(); + let trait_items = ty::trait_items(tcx, trait_did); + + for impl_item in impl_items { + let (ident, span) = match *impl_item { + ast::MethodImplItem(ref method) => { + (match method.node { + ast::MethDecl(ident, _, _, _, _, _, _, _) => ident, + ast::MethMac(..) => unreachable!(), + }, method.span) + } + ast::TypeImplItem(ref typedef) => { + (typedef.ident, typedef.span) + } + }; + let item = trait_items.iter().find(|item| { + item.name() == ident.name + }).unwrap(); + if warn_about_defns { + maybe_do_stability_check(tcx, item.def_id(), span, cb); + } + } + } + _ => (/* pass */) } } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index e27e7a8024685..9bf35bd428472 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -530,17 +530,6 @@ impl<'a,T> Iterator for EnumeratedItems<'a,T> { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for VecPerParamSpace { - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_vec().into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot impl IntoIterator for VecPerParamSpace { type Item = T; type IntoIter = IntoIter; @@ -550,17 +539,6 @@ impl IntoIterator for VecPerParamSpace { } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a,T> IntoIterator for &'a VecPerParamSpace { - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.as_slice().into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot impl<'a,T> IntoIterator for &'a VecPerParamSpace { type Item = &'a T; type IntoIter = Iter<'a, T>; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 6f58f4655fed1..061557eb7dccd 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -20,7 +20,7 @@ use self::EvaluationResult::*; use super::{DerivedObligationCause}; use super::{project}; use super::project::Normalized; -use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause}; +use super::{PredicateObligation, TraitObligation, ObligationCause}; use super::{ObligationCauseCode, BuiltinDerivedObligation}; use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; use super::{Selection}; @@ -34,7 +34,7 @@ use super::{util}; use middle::fast_reject; use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace}; -use middle::ty::{self, AsPredicate, RegionEscape, ToPolyTraitRef, Ty}; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; @@ -1459,22 +1459,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundSync | ty::BoundSend => { - // Note: technically, a region pointer is only - // sendable if it has lifetime - // `'static`. However, we don't take regions - // into account when doing trait matching: - // instead, when we decide that `T : Send`, we - // will register a separate constraint with - // the region inferencer that `T : 'static` - // holds as well (because the trait `Send` - // requires it). This will ensure that there - // is no borrowed data in `T` (or else report - // an inference error). The reason we do it - // this way is that we do not yet *know* what - // lifetime the borrowed reference has, since - // we haven't finished running inference -- in - // other words, there's a kind of - // chicken-and-egg problem. Ok(If(vec![referent_ty])) } } @@ -1817,21 +1801,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }) }).collect::>(); - let mut obligations = match obligations { + let obligations = match obligations { Ok(o) => o, Err(ErrorReported) => Vec::new() }; - // as a special case, `Send` requires `'static` - if bound == ty::BoundSend { - obligations.push(Obligation { - cause: obligation.cause.clone(), - recursion_depth: obligation.recursion_depth+1, - predicate: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(), - ty::ReStatic)).as_predicate(), - }); - } - let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new()); debug!("vtable_builtin_data: obligations={}", diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 107715a826157..8618bde95fe6f 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -73,8 +73,6 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt; use std::hash::{Hash, Writer, SipHasher, Hasher}; -#[cfg(stage0)] -use std::marker; use std::mem; use std::ops; use std::rc::Rc; @@ -944,26 +942,6 @@ pub struct TyS<'tcx> { // the maximal depth of any bound regions appearing in this type. region_depth: u32, - - // force the lifetime to be invariant to work-around - // region-inference issues with a covariant lifetime. - #[cfg(stage0)] - marker: ShowInvariantLifetime<'tcx>, -} - -#[cfg(stage0)] -struct ShowInvariantLifetime<'a>(marker::InvariantLifetime<'a>); -#[cfg(stage0)] -impl<'a> ShowInvariantLifetime<'a> { - fn new() -> ShowInvariantLifetime<'a> { - ShowInvariantLifetime(marker::InvariantLifetime) - } -} -#[cfg(stage0)] -impl<'a> fmt::Debug for ShowInvariantLifetime<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "InvariantLifetime") - } } impl fmt::Debug for TypeFlags { @@ -972,14 +950,6 @@ impl fmt::Debug for TypeFlags { } } -#[cfg(stage0)] -impl<'tcx> PartialEq for TyS<'tcx> { - fn eq<'a,'b>(&'a self, other: &'b TyS<'tcx>) -> bool { - let other: &'a TyS<'tcx> = unsafe { mem::transmute(other) }; - (self as *const _) == (other as *const _) - } -} -#[cfg(not(stage0))] impl<'tcx> PartialEq for TyS<'tcx> { fn eq(&self, other: &TyS<'tcx>) -> bool { // (self as *const _) == (other as *const _) @@ -2562,12 +2532,6 @@ fn intern_ty<'tcx>(type_arena: &'tcx TypedArena>, let flags = FlagComputation::for_sty(&st); let ty = match () { - #[cfg(stage0)] - () => type_arena.alloc(TyS { sty: st, - flags: flags.flags, - region_depth: flags.depth, - marker: ShowInvariantLifetime::new(), }), - #[cfg(not(stage0))] () => type_arena.alloc(TyS { sty: st, flags: flags.flags, region_depth: flags.depth, }), diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8340a49b92ae3..5768539b2cd76 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -645,7 +645,7 @@ pub fn build_target_config(opts: &Options, sp: &SpanHandler) -> Config { "32" => (ast::TyI32, ast::TyU32), "64" => (ast::TyI64, ast::TyU64), w => sp.handler().fatal(&format!("target specification was invalid: unrecognized \ - target-word-size {}", w)[]) + target-pointer-width {}", w)[]) }; Config { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0363978bada25..426101e858a89 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -697,9 +697,8 @@ impl<'tcx> UserString<'tcx> for ty::TyTrait<'tcx> { } // Region, if not obviously implied by builtin bounds. - if bounds.region_bound != ty::ReStatic || - !bounds.builtin_bounds.contains(&ty::BoundSend) - { // Region bound is implied by builtin bounds: + if bounds.region_bound != ty::ReStatic { + // Region bound is implied by builtin bounds: components.push(bounds.region_bound.user_string(tcx)); } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 54b3e8f208125..d589b063204c7 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -35,9 +35,9 @@ #![feature(core)] #![feature(hash)] #![feature(int_uint)] -#![feature(io)] +#![feature(old_io)] #![feature(os)] -#![feature(path)] +#![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(env)] diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 2a4f5b00e9307..692e6b474fd27 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -40,7 +40,7 @@ //! this module defines the format the JSON file should take, though each //! underscore in the field names should be replaced with a hyphen (`-`) in the //! JSON file. Some fields are required in every target specification, such as -//! `data-layout`, `llvm-target`, `target-endian`, `target-word-size`, and +//! `data-layout`, `llvm-target`, `target-endian`, `target-pointer-width`, and //! `arch`. In general, options passed to rustc with `-C` override the target's //! settings, though `target-feature` and `link-args` will *add* to the list //! specified by the target, rather than replace. @@ -245,7 +245,7 @@ impl Target { data_layout: get_req_field("data-layout"), llvm_target: get_req_field("llvm-target"), target_endian: get_req_field("target-endian"), - target_pointer_width: get_req_field("target-word-size"), + target_pointer_width: get_req_field("target-pointer-width"), arch: get_req_field("arch"), target_os: get_req_field("os"), options: Default::default(), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index eb1dba7159cf8..728ff64759998 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -471,9 +471,10 @@ pub fn phase_2_configure_and_expand(sess: &Session, new_path.extend(env::split_paths(&_old_path)); env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap()); } + let features = sess.features.borrow(); let cfg = syntax::ext::expand::ExpansionConfig { crate_name: crate_name.to_string(), - enable_quotes: sess.features.borrow().quote, + features: Some(&features), recursion_limit: sess.recursion_limit.get(), }; let ret = syntax::ext::expand::expand_crate(&sess.parse_sess, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 9b8ca398b12b8..ac91a0098ea75 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -28,16 +28,15 @@ #![feature(core)] #![feature(env)] #![feature(int_uint)] -#![feature(io)] +#![feature(old_io)] #![feature(libc)] #![feature(os)] -#![feature(path)] +#![feature(old_path)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(unsafe_destructor)] #![feature(staged_api)] -#![feature(std_misc)] #![feature(unicode)] extern crate arena; @@ -73,7 +72,7 @@ use rustc::metadata; use rustc::util::common::time; use std::cmp::Ordering::Equal; -use std::old_io; +use std::old_io::{self, stdio}; use std::iter::repeat; use std::env; use std::sync::mpsc::channel; @@ -94,7 +93,7 @@ pub mod pretty; static BUG_REPORT_URL: &'static str = - "http://doc.rust-lang.org/complement-bugreport.html"; + "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports"; pub fn run(args: Vec) -> int { @@ -765,7 +764,7 @@ fn parse_crate_attrs(sess: &Session, input: &Input) -> /// /// The diagnostic emitter yielded to the procedure should be used for reporting /// errors of the compiler. -pub fn monitor(f: F) { +pub fn monitor(f: F) { static STACK_SIZE: uint = 8 * 1024 * 1024; // 8MB let (tx, rx) = channel(); @@ -780,7 +779,7 @@ pub fn monitor(f: F) { cfg = cfg.stack_size(STACK_SIZE); } - match cfg.scoped(move || { std::old_io::stdio::set_stderr(box w); f() }).join() { + match cfg.spawn(move || { stdio::set_stderr(box w); f() }).unwrap().join() { Ok(()) => { /* fallthrough */ } Err(value) => { // Thread panicked without emitting a fatal diagnostic diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 213e356536246..aa90d7c851ba6 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -29,7 +29,7 @@ #![feature(int_uint)] #![feature(libc)] #![feature(link_args)] -#![feature(path)] +#![feature(old_path)] #![feature(staged_api)] #![feature(std_misc)] @@ -58,7 +58,7 @@ pub use self::Linkage::*; use std::ffi::CString; use std::cell::RefCell; -use std::{raw, mem, ptr}; +use std::{raw, mem}; use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; use libc::{c_longlong, c_ulonglong, c_void}; use debuginfo::{DIBuilderRef, DIDescriptor, @@ -2251,65 +2251,6 @@ pub unsafe fn debug_loc_to_string(c: ContextRef, tr: DebugLocRef) -> String { .expect("got a non-UTF8 DebugLoc from LLVM") } -// FIXME #15460 - create a public function that actually calls our -// static LLVM symbols. Otherwise the linker will just throw llvm -// away. We're just calling lots of stuff until we transitively get -// all of LLVM. This is worse than anything. -pub unsafe fn static_link_hack_this_sucks() { - LLVMInitializePasses(); - - LLVMInitializeX86TargetInfo(); - LLVMInitializeX86Target(); - LLVMInitializeX86TargetMC(); - LLVMInitializeX86AsmPrinter(); - LLVMInitializeX86AsmParser(); - - LLVMInitializeARMTargetInfo(); - LLVMInitializeARMTarget(); - LLVMInitializeARMTargetMC(); - LLVMInitializeARMAsmPrinter(); - LLVMInitializeARMAsmParser(); - - LLVMInitializeAArch64TargetInfo(); - LLVMInitializeAArch64Target(); - LLVMInitializeAArch64TargetMC(); - LLVMInitializeAArch64AsmPrinter(); - LLVMInitializeAArch64AsmParser(); - - LLVMInitializeMipsTargetInfo(); - LLVMInitializeMipsTarget(); - LLVMInitializeMipsTargetMC(); - LLVMInitializeMipsAsmPrinter(); - LLVMInitializeMipsAsmParser(); - - LLVMInitializePowerPCTargetInfo(); - LLVMInitializePowerPCTarget(); - LLVMInitializePowerPCTargetMC(); - LLVMInitializePowerPCAsmPrinter(); - LLVMInitializePowerPCAsmParser(); - - LLVMRustSetLLVMOptions(0 as c_int, ptr::null()); - - LLVMPassManagerBuilderPopulateModulePassManager(ptr::null_mut(), ptr::null_mut()); - LLVMPassManagerBuilderPopulateLTOPassManager(ptr::null_mut(), ptr::null_mut(), False, False); - LLVMPassManagerBuilderPopulateFunctionPassManager(ptr::null_mut(), ptr::null_mut()); - LLVMPassManagerBuilderSetOptLevel(ptr::null_mut(), 0 as c_uint); - LLVMPassManagerBuilderUseInlinerWithThreshold(ptr::null_mut(), 0 as c_uint); - LLVMWriteBitcodeToFile(ptr::null_mut(), ptr::null()); - LLVMPassManagerBuilderCreate(); - LLVMPassManagerBuilderDispose(ptr::null_mut()); - - LLVMRustLinkInExternalBitcode(ptr::null_mut(), ptr::null(), 0 as size_t); - - LLVMLinkInMCJIT(); - LLVMLinkInInterpreter(); - - extern { - fn LLVMLinkInMCJIT(); - fn LLVMLinkInInterpreter(); - } -} - // The module containing the native LLVM dependencies, generated by the build system // Note that this must come after the rustllvm extern declaration so that // parts of LLVM that rustllvm depends on aren't thrown away by the linker. diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 68f413eff85c6..9934d9993d61d 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -939,7 +939,7 @@ fn run_work_multithreaded(sess: &Session, } tx.take().unwrap().send(()).unwrap(); - }); + }).unwrap(); } let mut panicked = false; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 21557379e3ae2..4606200d058c6 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -30,10 +30,10 @@ #![feature(core)] #![feature(hash)] #![feature(int_uint)] -#![feature(io)] +#![feature(old_io)] #![feature(env)] #![feature(libc)] -#![feature(path)] +#![feature(old_path)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 5ece5e59299a0..b0ed6f9e727a2 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -827,7 +827,19 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, &format!("comparison of `{}`", cx.ty_to_string(rhs_t))[], StrEqFnLangItem); - callee::trans_lang_call(cx, did, &[lhs, rhs], None, debug_loc) + let t = ty::mk_str_slice(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ast::MutImmutable); + // The comparison function gets the slices by value, so we have to make copies here. Even + // if the function doesn't write through the pointer, things like lifetime intrinsics + // require that we do this properly + let lhs_arg = alloc_ty(cx, t, "lhs"); + let rhs_arg = alloc_ty(cx, t, "rhs"); + memcpy_ty(cx, lhs_arg, lhs, t); + memcpy_ty(cx, rhs_arg, rhs, t); + let res = callee::trans_lang_call(cx, did, &[lhs_arg, rhs_arg], None, debug_loc); + call_lifetime_end(res.bcx, lhs_arg); + call_lifetime_end(res.bcx, rhs_arg); + + res } let _icx = push_ctxt("compare_values"); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b09c3f730fc64..bab734db12650 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -25,15 +25,16 @@ #![feature(env)] #![feature(hash)] #![feature(int_uint)] -#![feature(io)] +#![feature(old_io)] #![feature(libc)] #![feature(os)] -#![feature(path)] +#![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(std_misc)] #![feature(test)] #![feature(unicode)] +#![feature(str_words)] extern crate arena; extern crate getopts; @@ -55,6 +56,7 @@ use std::env; use std::old_io::File; use std::old_io; use std::rc::Rc; +use std::sync::mpsc::channel; use externalfiles::ExternalHtml; use serialize::Decodable; use serialize::json::{self, Json}; @@ -125,8 +127,8 @@ pub fn main() { let res = std::thread::Builder::new().stack_size(STACK_SIZE).scoped(move || { let s = env::args().collect::>(); main_args(&s) - }).join(); - env::set_exit_status(res.ok().unwrap() as i32); + }).unwrap().join(); + env::set_exit_status(res as i32); } pub fn opts() -> Vec { @@ -365,12 +367,14 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche let cr = Path::new(cratefile); info!("starting to run rustc"); - let (mut krate, analysis) = std::thread::Thread::scoped(move || { + let (tx, rx) = channel(); + std::thread::spawn(move || { use rustc::session::config::Input; let cr = cr; - core::run_core(paths, cfgs, externs, Input::File(cr), triple) + tx.send(core::run_core(paths, cfgs, externs, Input::File(cr), triple)).unwrap(); }).join().map_err(|_| "rustc failed").unwrap(); + let (mut krate, analysis) = rx.recv().unwrap(); info!("finished with rustc"); let mut analysis = Some(analysis); ANALYSISKEY.with(|s| { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 09df9fc8cbb66..bf14b86ebd1e3 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -15,7 +15,7 @@ use std::old_io::{Command, TempDir}; use std::old_io; use std::env; use std::str; -use std::thread::Thread; +use std::thread; use std::thunk::Thunk; use std::collections::{HashSet, HashMap}; @@ -142,7 +142,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, let w1 = old_io::ChanWriter::new(tx); let w2 = w1.clone(); let old = old_io::stdio::set_stderr(box w1); - Thread::spawn(move || { + thread::spawn(move || { let mut p = old_io::ChanReader::new(rx); let mut err = match old { Some(old) => { diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 6cada2e5614ba..853da598ab5be 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -29,8 +29,8 @@ Core encoding and decoding interfaces. #![feature(collections)] #![feature(core)] #![feature(int_uint)] -#![feature(io)] -#![feature(path)] +#![feature(old_io)] +#![feature(old_path)] #![feature(hash)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 0a3abd5d1acc3..4d38d17576ddb 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -12,15 +12,12 @@ //! Operations on ASCII strings and characters -#![unstable(feature = "std_misc", - reason = "unsure about placement and naming")] +#![stable(feature = "rust1", since = "1.0.0")] -use iter::IteratorExt; -use ops::FnMut; -use slice::SliceExt; -use str::StrExt; -use string::String; -use vec::Vec; +use prelude::v1::*; + +use mem; +use iter::Range; /// Extension methods for ASCII-subset only operations on owned strings #[unstable(feature = "std_misc", @@ -38,31 +35,50 @@ pub trait OwnedAsciiExt { } /// Extension methods for ASCII-subset only operations on string slices -#[unstable(feature = "std_misc", - reason = "would prefer to do this in a more general way")] -pub trait AsciiExt { +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsciiExt { + #[stable(feature = "rust1", since = "1.0.0")] + type Owned; + /// Check if within the ASCII range. + #[stable(feature = "rust1", since = "1.0.0")] fn is_ascii(&self) -> bool; /// Makes a copy of the string in ASCII upper case: /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. - fn to_ascii_uppercase(&self) -> T; + #[stable(feature = "rust1", since = "1.0.0")] + fn to_ascii_uppercase(&self) -> Self::Owned; /// Makes a copy of the string in ASCII lower case: /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. - fn to_ascii_lowercase(&self) -> T; + #[stable(feature = "rust1", since = "1.0.0")] + fn to_ascii_lowercase(&self) -> Self::Owned; /// Check that two strings are an ASCII case-insensitive match. /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporary strings. + #[stable(feature = "rust1", since = "1.0.0")] fn eq_ignore_ascii_case(&self, other: &Self) -> bool; + + /// Convert this type to its ASCII upper case equivalent in-place. + /// + /// See `to_ascii_uppercase` for more information. + #[unstable(feature = "ascii")] + fn make_ascii_uppercase(&mut self); + + /// Convert this type to its ASCII lower case equivalent in-place. + /// + /// See `to_ascii_lowercase` for more information. + #[unstable(feature = "ascii")] + fn make_ascii_lowercase(&mut self); } -#[unstable(feature = "std_misc", - reason = "would prefer to do this in a more general way")] -impl AsciiExt for str { +#[stable(feature = "rust1", since = "1.0.0")] +impl AsciiExt for str { + type Owned = String; + #[inline] fn is_ascii(&self) -> bool { self.bytes().all(|b| b.is_ascii()) @@ -70,20 +86,28 @@ impl AsciiExt for str { #[inline] fn to_ascii_uppercase(&self) -> String { - // Vec::to_ascii_uppercase() preserves the UTF-8 invariant. - unsafe { String::from_utf8_unchecked(self.as_bytes().to_ascii_uppercase()) } + self.to_string().into_ascii_uppercase() } #[inline] fn to_ascii_lowercase(&self) -> String { - // Vec::to_ascii_lowercase() preserves the UTF-8 invariant. - unsafe { String::from_utf8_unchecked(self.as_bytes().to_ascii_lowercase()) } + self.to_string().into_ascii_lowercase() } #[inline] fn eq_ignore_ascii_case(&self, other: &str) -> bool { self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) } + + fn make_ascii_uppercase(&mut self) { + let me: &mut [u8] = unsafe { mem::transmute(self) }; + me.make_ascii_uppercase() + } + + fn make_ascii_lowercase(&mut self) { + let me: &mut [u8] = unsafe { mem::transmute(self) }; + me.make_ascii_lowercase() + } } #[unstable(feature = "std_misc", @@ -102,9 +126,9 @@ impl OwnedAsciiExt for String { } } -#[unstable(feature = "std_misc", - reason = "would prefer to do this in a more general way")] -impl AsciiExt> for [u8] { +#[stable(feature = "rust1", since = "1.0.0")] +impl AsciiExt for [u8] { + type Owned = Vec; #[inline] fn is_ascii(&self) -> bool { self.iter().all(|b| b.is_ascii()) @@ -112,12 +136,12 @@ impl AsciiExt> for [u8] { #[inline] fn to_ascii_uppercase(&self) -> Vec { - self.iter().map(|b| b.to_ascii_uppercase()).collect() + self.to_vec().into_ascii_uppercase() } #[inline] fn to_ascii_lowercase(&self) -> Vec { - self.iter().map(|b| b.to_ascii_lowercase()).collect() + self.to_vec().into_ascii_lowercase() } #[inline] @@ -127,6 +151,18 @@ impl AsciiExt> for [u8] { a.eq_ignore_ascii_case(b) }) } + + fn make_ascii_uppercase(&mut self) { + for byte in self { + byte.make_ascii_uppercase(); + } + } + + fn make_ascii_lowercase(&mut self) { + for byte in self { + byte.make_ascii_lowercase(); + } + } } #[unstable(feature = "std_misc", @@ -134,48 +170,39 @@ impl AsciiExt> for [u8] { impl OwnedAsciiExt for Vec { #[inline] fn into_ascii_uppercase(mut self) -> Vec { - for byte in &mut self { - *byte = byte.to_ascii_uppercase(); - } + self.make_ascii_uppercase(); self } #[inline] fn into_ascii_lowercase(mut self) -> Vec { - for byte in &mut self { - *byte = byte.to_ascii_lowercase(); - } + self.make_ascii_lowercase(); self } } -#[unstable(feature = "std_misc", - reason = "would prefer to do this in a more general way")] +#[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for u8 { + type Owned = u8; #[inline] - fn is_ascii(&self) -> bool { - *self & 128 == 0u8 - } - + fn is_ascii(&self) -> bool { *self & 128 == 0u8 } #[inline] - fn to_ascii_uppercase(&self) -> u8 { - ASCII_UPPERCASE_MAP[*self as usize] - } - + fn to_ascii_uppercase(&self) -> u8 { ASCII_UPPERCASE_MAP[*self as usize] } #[inline] - fn to_ascii_lowercase(&self) -> u8 { - ASCII_LOWERCASE_MAP[*self as usize] - } - + fn to_ascii_lowercase(&self) -> u8 { ASCII_LOWERCASE_MAP[*self as usize] } #[inline] fn eq_ignore_ascii_case(&self, other: &u8) -> bool { self.to_ascii_lowercase() == other.to_ascii_lowercase() } + #[inline] + fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); } + #[inline] + fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); } } -#[unstable(feature = "std_misc", - reason = "would prefer to do this in a more general way")] +#[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for char { + type Owned = char; #[inline] fn is_ascii(&self) -> bool { *self as u32 <= 0x7F @@ -203,6 +230,19 @@ impl AsciiExt for char { fn eq_ignore_ascii_case(&self, other: &char) -> bool { self.to_ascii_lowercase() == other.to_ascii_lowercase() } + + #[inline] + fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); } + #[inline] + fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); } +} + +/// An iterator over the escaped version of a byte, constructed via +/// `std::ascii::escape_default`. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct EscapeDefault { + range: Range, + data: [u8; 4], } /// Returns a 'default' ASCII and C++11-like literal escape of a `u8` @@ -214,34 +254,46 @@ impl AsciiExt for char { /// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. /// - Single-quote, double-quote and backslash chars are backslash-escaped. /// - Any other chars in the range [0x20,0x7e] are not escaped. -/// - Any other chars are given hex escapes. +/// - Any other chars are given hex escapes of the form '\xNN'. /// - Unicode escapes are never generated by this function. -#[unstable(feature = "std_misc", - reason = "needs to be updated to use an iterator")] -pub fn escape_default(c: u8, mut f: F) where - F: FnMut(u8), -{ - match c { - b'\t' => { f(b'\\'); f(b't'); } - b'\r' => { f(b'\\'); f(b'r'); } - b'\n' => { f(b'\\'); f(b'n'); } - b'\\' => { f(b'\\'); f(b'\\'); } - b'\'' => { f(b'\\'); f(b'\''); } - b'"' => { f(b'\\'); f(b'"'); } - b'\x20' ... b'\x7e' => { f(c); } - _ => { - f(b'\\'); - f(b'x'); - for &offset in &[4u, 0u] { - match ((c as i32) >> offset) & 0xf { - i @ 0 ... 9 => f(b'0' + (i as u8)), - i => f(b'a' + (i as u8 - 10)), - } - } +#[stable(feature = "rust1", since = "1.0.0")] +pub fn escape_default(c: u8) -> EscapeDefault { + let (data, len) = match c { + b'\t' => ([b'\\', b't', 0, 0], 2), + b'\r' => ([b'\\', b'r', 0, 0], 2), + b'\n' => ([b'\\', b'n', 0, 0], 2), + b'\\' => ([b'\\', b'\\', 0, 0], 2), + b'\'' => ([b'\\', b'\'', 0, 0], 2), + b'"' => ([b'\\', b'"', 0, 0], 2), + b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1), + _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), + }; + + return EscapeDefault { range: range(0, len), data: data }; + + fn hexify(b: u8) -> u8 { + match b { + 0 ... 9 => b'0' + b, + _ => b'a' + b - 10, } } } +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EscapeDefault { + type Item = u8; + fn next(&mut self) -> Option { self.range.next().map(|i| self.data[i]) } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for EscapeDefault { + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| self.data[i]) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for EscapeDefault {} + static ASCII_LOWERCASE_MAP: [u8; 256] = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 241e409910f36..1b9f8b9901723 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1372,21 +1372,7 @@ enum VacantEntryState { NoElem(EmptyBucket), } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, K, V, S, H> IntoIterator for &'a HashMap - where K: Eq + Hash, - S: HashState, - H: hash::Hasher -{ - type IntoIter = Iter<'a, K, V>; - - fn into_iter(self) -> Iter<'a, K, V> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S, H> IntoIterator for &'a HashMap where K: Eq + Hash, S: HashState, @@ -1400,21 +1386,7 @@ impl<'a, K, V, S, H> IntoIterator for &'a HashMap } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, K, V, S, H> IntoIterator for &'a mut HashMap - where K: Eq + Hash, - S: HashState, - H: hash::Hasher -{ - type IntoIter = IterMut<'a, K, V>; - - fn into_iter(mut self) -> IterMut<'a, K, V> { - self.iter_mut() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S, H> IntoIterator for &'a mut HashMap where K: Eq + Hash, S: HashState, @@ -1428,21 +1400,7 @@ impl<'a, K, V, S, H> IntoIterator for &'a mut HashMap } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for HashMap - where K: Eq + Hash, - S: HashState, - H: hash::Hasher -{ - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for HashMap where K: Eq + Hash, S: HashState, diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 300e208931765..5fbbcb3b347af 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -835,21 +835,7 @@ pub struct Union<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>> } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl<'a, T, S, H> IntoIterator for &'a HashSet - where T: Eq + Hash, - S: HashState, - H: hash::Hasher -{ - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S, H> IntoIterator for &'a HashSet where T: Eq + Hash, S: HashState, @@ -863,21 +849,7 @@ impl<'a, T, S, H> IntoIterator for &'a HashSet } } -// NOTE(stage0): remove impl after a snapshot -#[cfg(stage0)] -impl IntoIterator for HashSet - where T: Eq + Hash, - S: HashState, - H: hash::Hasher -{ - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_iter() - } -} - -#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for HashSet where T: Eq + Hash, S: HashState, diff --git a/src/libstd/env.rs b/src/libstd/env.rs index ea18838211f26..93dc3efe2c4fc 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -488,12 +488,20 @@ impl Iterator for Args { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.inner.len() } +} + impl Iterator for ArgsOs { type Item = OsString; fn next(&mut self) -> Option { self.inner.next() } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } +impl ExactSizeIterator for ArgsOs { + fn len(&self) -> usize { self.inner.len() } +} + /// Returns the page size of the current architecture in bytes. pub fn page_size() -> usize { os_imp::page_size() diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 5f91d173ed2ac..69791084e2f9f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -114,7 +114,7 @@ impl File { /// Open a file in write-only mode. /// - /// This function will create a file it it does not exist, + /// This function will create a file if it does not exist, /// and will truncate it if it does. /// /// See the `OpenOptions::open` function for more details. diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 89c45f60d1ca8..c38d52161c96e 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -443,9 +443,8 @@ pub trait Seek { /// A seek beyond the end of a stream is allowed, but seeking before offset /// 0 is an error. /// - /// Seeking past the end of the stream does not modify the underlying - /// stream, but the next write may cause the previous data to be filled in - /// with a bit pattern. + /// The behavior when seeking past the end of the stream is implementation + /// defined. /// /// This method returns the new position within the stream if the seek /// operation completed successfully. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 139693ccdbcb9..7c9a8a7b4b5ad 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -292,13 +292,6 @@ mod tuple; // can be resolved within libstd. #[doc(hidden)] mod std { - // NOTE: remove after next snapshot - // mods used for deriving - #[cfg(stage0)] pub use clone; - #[cfg(stage0)] pub use cmp; - #[cfg(stage0)] pub use hash; - #[cfg(stage0)] pub use default; - pub use sync; // used for select!() pub use error; // used for try!() pub use fmt; // used for any formatting strings @@ -319,7 +312,4 @@ mod std { pub use slice; pub use boxed; // used for vec![] - // for-loops - // NOTE: remove after next snapshot - #[cfg(stage0)] pub use iter; } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6a2aafcf8f396..00bb7f86b170c 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -60,23 +60,6 @@ macro_rules! panic { }); } -/// Use the syntax described in `std::fmt` to create a value of type `String`. -/// See `std::fmt` for more information. -/// -/// # Example -/// -/// ``` -/// format!("test"); -/// format!("hello {}", "world!"); -/// format!("x = {}, y = {y}", 10, y = 30); -/// ``` -#[cfg(stage0)] // NOTE: remove after snapshot -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -macro_rules! format { - ($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*))) -} - /// Equivalent to the `println!` macro except that a newline is not printed at /// the end of the message. #[macro_export] @@ -126,7 +109,7 @@ macro_rules! try { /// # Examples /// /// ``` -/// use std::thread::Thread; +/// use std::thread; /// use std::sync::mpsc; /// /// // two placeholder functions for now @@ -136,8 +119,8 @@ macro_rules! try { /// let (tx1, rx1) = mpsc::channel(); /// let (tx2, rx2) = mpsc::channel(); /// -/// Thread::spawn(move|| { long_running_task(); tx1.send(()).unwrap(); }); -/// Thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); }); +/// thread::spawn(move|| { long_running_task(); tx1.send(()).unwrap(); }); +/// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); }); /// /// select! ( /// _ = rx1.recv() => println!("the long running task finished first"), diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 50eafdfc5c238..b861b74947eeb 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -43,7 +43,7 @@ pub struct TcpStream(net_imp::TcpStream); /// /// ```no_run /// use std::net::{TcpListener, TcpStream}; -/// use std::thread::Thread; +/// use std::thread; /// /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); /// @@ -55,7 +55,7 @@ pub struct TcpStream(net_imp::TcpStream); /// for stream in listener.incoming() { /// match stream { /// Ok(stream) => { -/// Thread::spawn(move|| { +/// thread::spawn(move|| { /// // connection succeeded /// handle_client(stream) /// }); @@ -217,7 +217,7 @@ mod tests { use net::*; use net::test::{next_test_ip4, next_test_ip6}; use sync::mpsc::channel; - use thread::Thread; + use thread; fn each_ip(f: &mut FnMut(SocketAddr)) { f(next_test_ip4()); @@ -247,7 +247,8 @@ mod tests { fn connect_error() { match TcpStream::connect("0.0.0.0:1") { Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind(), ErrorKind::ConnectionRefused), + Err(e) => assert!((e.kind() == ErrorKind::ConnectionRefused) + || (e.kind() == ErrorKind::InvalidInput)), } } @@ -256,7 +257,7 @@ mod tests { let socket_addr = next_test_ip4(); let listener = t!(TcpListener::bind(&socket_addr)); - let _t = Thread::scoped(move || { + let _t = thread::spawn(move || { let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); t!(stream.write(&[144])); @@ -273,7 +274,7 @@ mod tests { let addr = next_test_ip4(); let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut stream = t!(TcpStream::connect(&("127.0.0.1", addr.port()))); t!(stream.write(&[44])); }); @@ -289,7 +290,7 @@ mod tests { let addr = next_test_ip6(); let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut stream = t!(TcpStream::connect(&("::1", addr.port()))); t!(stream.write(&[66])); }); @@ -306,7 +307,7 @@ mod tests { let acceptor = t!(TcpListener::bind(&addr)); let (tx, rx) = channel(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut stream = t!(TcpStream::connect(&addr)); t!(stream.write(&[99])); tx.send(t!(stream.socket_addr())).unwrap(); @@ -325,7 +326,7 @@ mod tests { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let _stream = t!(TcpStream::connect(&addr)); // Close }); @@ -345,7 +346,7 @@ mod tests { let acceptor = t!(TcpListener::bind(&addr)); let (tx, rx) = channel(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { drop(t!(TcpStream::connect(&addr))); tx.send(()).unwrap(); }); @@ -371,7 +372,7 @@ mod tests { let max = 10; let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { for _ in 0..max { let mut stream = t!(TcpStream::connect(&addr)); t!(stream.write(&[99])); @@ -393,11 +394,11 @@ mod tests { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let acceptor = acceptor; for (i, stream) in acceptor.incoming().enumerate().take(MAX) { // Start another task to handle the connection - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut stream = t!(stream); let mut buf = [0]; t!(stream.read(&mut buf)); @@ -412,7 +413,7 @@ mod tests { fn connect(i: usize, addr: SocketAddr) { if i == MAX { return } - let t = Thread::scoped(move|| { + let t = thread::spawn(move|| { let mut stream = t!(TcpStream::connect(&addr)); // Connect again before writing connect(i + 1, addr); @@ -428,10 +429,10 @@ mod tests { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { for stream in acceptor.incoming().take(MAX) { // Start another task to handle the connection - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut stream = t!(stream); let mut buf = [0]; t!(stream.read(&mut buf)); @@ -446,7 +447,7 @@ mod tests { fn connect(i: usize, addr: SocketAddr) { if i == MAX { return } - let t = Thread::scoped(move|| { + let t = thread::spawn(move|| { let mut stream = t!(TcpStream::connect(&addr)); connect(i + 1, addr); t!(stream.write(&[99])); @@ -467,7 +468,7 @@ mod tests { let listener = t!(TcpListener::bind(&addr)); let so_name = t!(listener.socket_addr()); assert_eq!(addr, so_name); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { t!(listener.accept()); }); @@ -481,7 +482,7 @@ mod tests { each_ip(&mut |addr| { let (tx, rx) = channel(); let srv = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut cl = t!(srv.accept()).0; cl.write(&[10]).unwrap(); let mut b = [0]; @@ -517,7 +518,7 @@ mod tests { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { t!(TcpStream::connect(&addr)); }); @@ -532,7 +533,7 @@ mod tests { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut s = t!(TcpStream::connect(&addr)); let mut buf = [0, 0]; assert_eq!(s.read(&mut buf), Ok(1)); @@ -545,7 +546,7 @@ mod tests { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; rx1.recv().unwrap(); t!(s2.write(&[1])); @@ -565,7 +566,7 @@ mod tests { let (tx1, rx) = channel(); let tx2 = tx1.clone(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut s = t!(TcpStream::connect(&addr)); t!(s.write(&[1])); rx.recv().unwrap(); @@ -577,7 +578,7 @@ mod tests { let s2 = t!(s1.try_clone()); let (done, rx) = channel(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; let mut buf = [0, 0]; t!(s2.read(&mut buf)); @@ -597,7 +598,7 @@ mod tests { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut s = t!(TcpStream::connect(&addr)); let mut buf = [0, 1]; t!(s.read(&mut buf)); @@ -608,7 +609,7 @@ mod tests { let s2 = t!(s1.try_clone()); let (done, rx) = channel(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; t!(s2.write(&[1])); done.send(()).unwrap(); @@ -623,7 +624,7 @@ mod tests { fn shutdown_smoke() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut c = t!(a.accept()).0; let mut b = [0]; assert_eq!(c.read(&mut b), Ok(0)); @@ -644,7 +645,7 @@ mod tests { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); let (tx, rx) = channel::<()>(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let _s = t!(a.accept()); let _ = rx.recv(); }); @@ -682,7 +683,7 @@ mod tests { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); let (tx1, rx) = channel::<()>(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let _s = t!(a.accept()); let _ = rx.recv(); }); @@ -690,7 +691,7 @@ mod tests { let s = t!(TcpStream::connect(&addr)); let s2 = t!(s.try_clone()); let (tx, rx) = channel(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; assert_eq!(t!(s2.read(&mut [0])), 0); tx.send(()).unwrap(); @@ -713,7 +714,7 @@ mod tests { let (tx, rx) = channel(); let (txdone, rxdone) = channel(); let txdone2 = txdone.clone(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut tcp = t!(TcpStream::connect(&addr)); rx.recv().unwrap(); t!(tcp.write(&[0])); @@ -724,7 +725,7 @@ mod tests { let tcp = t!(accept.accept()).0; let tcp2 = t!(tcp.try_clone()); let txdone3 = txdone.clone(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let mut tcp2 = tcp2; t!(tcp2.read(&mut [0])); txdone3.send(()).unwrap(); @@ -732,7 +733,7 @@ mod tests { // Try to ensure that the reading clone is indeed reading for _ in 0..50 { - Thread::yield_now(); + thread::yield_now(); } // clone the handle again while it's reading, then let it finish the @@ -750,10 +751,10 @@ mod tests { let a = t!(TcpListener::bind(&addr)); let a2 = t!(a.try_clone()); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let _ = TcpStream::connect(&addr); }); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let _ = TcpStream::connect(&addr); }); @@ -771,17 +772,17 @@ mod tests { let (tx, rx) = channel(); let tx2 = tx.clone(); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { tx.send(t!(a.accept())).unwrap(); }); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { tx2.send(t!(a2.accept())).unwrap(); }); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let _ = TcpStream::connect(&addr); }); - let _t = Thread::scoped(move|| { + let _t = thread::spawn(move|| { let _ = TcpStream::connect(&addr); }); diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index d162a29790ea1..92f00599826dd 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -131,7 +131,7 @@ mod tests { use net::*; use net::test::{next_test_ip4, next_test_ip6}; use sync::mpsc::channel; - use thread::Thread; + use thread; fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { f(next_test_ip4(), next_test_ip4()); @@ -164,7 +164,7 @@ mod tests { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let client = t!(UdpSocket::bind(&client_ip)); rx1.recv().unwrap(); t!(client.send_to(&[99], &server_ip)); @@ -196,7 +196,7 @@ mod tests { let sock1 = t!(UdpSocket::bind(&addr1)); let sock2 = t!(UdpSocket::bind(&addr2)); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut buf = [0, 0]; assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1))); assert_eq!(buf[0], 1); @@ -207,7 +207,7 @@ mod tests { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx1.recv().unwrap(); t!(sock3.send_to(&[1], &addr2)); tx2.send(()).unwrap(); @@ -227,7 +227,7 @@ mod tests { let (tx1, rx) = channel(); let tx2 = tx1.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { t!(sock2.send_to(&[1], &addr1)); rx.recv().unwrap(); t!(sock2.send_to(&[2], &addr1)); @@ -237,7 +237,7 @@ mod tests { let sock3 = t!(sock1.try_clone()); let (done, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut buf = [0, 0]; t!(sock3.recv_from(&mut buf)); tx2.send(()).unwrap(); @@ -260,7 +260,7 @@ mod tests { let (tx, rx) = channel(); let (serv_tx, serv_rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut buf = [0, 1]; rx.recv().unwrap(); t!(sock2.recv_from(&mut buf)); @@ -271,7 +271,7 @@ mod tests { let (done, rx) = channel(); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { match sock3.send_to(&[1], &addr2) { Ok(..) => { let _ = tx2.send(()); } Err(..) => {} diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 29532cb9b02d0..4582dcd2b0392 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -51,71 +51,143 @@ pub trait Float + Rem { // inlined methods from `num::Float` - /// Returns the NaN value. + /// Returns the `NaN` value. + /// + /// ``` + /// use std::num::Float; + /// + /// let nan: f32 = Float::nan(); + /// + /// assert!(nan.is_nan()); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn nan() -> Self; /// Returns the infinite value. + /// + /// ``` + /// use std::num::Float; + /// use std::f32; + /// + /// let infinity: f32 = Float::infinity(); + /// + /// assert!(infinity.is_infinite()); + /// assert!(!infinity.is_finite()); + /// assert!(infinity > f32::MAX); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn infinity() -> Self; /// Returns the negative infinite value. + /// + /// ``` + /// use std::num::Float; + /// use std::f32; + /// + /// let neg_infinity: f32 = Float::neg_infinity(); + /// + /// assert!(neg_infinity.is_infinite()); + /// assert!(!neg_infinity.is_finite()); + /// assert!(neg_infinity < f32::MIN); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn neg_infinity() -> Self; - /// Returns the `0` value. + /// Returns `0.0`. + /// + /// ``` + /// use std::num::Float; + /// + /// let inf: f32 = Float::infinity(); + /// let zero: f32 = Float::zero(); + /// let neg_zero: f32 = Float::neg_zero(); + /// + /// assert_eq!(zero, neg_zero); + /// assert_eq!(7.0f32/inf, zero); + /// assert_eq!(zero * 10.0, zero); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn zero() -> Self; - /// Returns -0.0. + /// Returns `-0.0`. + /// + /// ``` + /// use std::num::Float; + /// + /// let inf: f32 = Float::infinity(); + /// let zero: f32 = Float::zero(); + /// let neg_zero: f32 = Float::neg_zero(); + /// + /// assert_eq!(zero, neg_zero); + /// assert_eq!(7.0f32/inf, zero); + /// assert_eq!(zero * 10.0, zero); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn neg_zero() -> Self; - /// Returns the `1` value. + /// Returns `1.0`. + /// + /// ``` + /// use std::num::Float; + /// + /// let one: f32 = Float::one(); + /// + /// assert_eq!(one, 1.0f32); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn one() -> Self; // FIXME (#5527): These should be associated constants - /// Returns the number of binary digits of mantissa that this type supports. + /// Deprecated: use `std::f32::MANTISSA_DIGITS` or `std::f64::MANTISSA_DIGITS` + /// instead. #[unstable(feature = "std_misc")] #[deprecated(since = "1.0.0", reason = "use `std::f32::MANTISSA_DIGITS` or \ `std::f64::MANTISSA_DIGITS` as appropriate")] fn mantissa_digits(unused_self: Option) -> uint; - /// Returns the number of base-10 digits of precision that this type supports. + /// Deprecated: use `std::f32::DIGITS` or `std::f64::DIGITS` instead. #[unstable(feature = "std_misc")] #[deprecated(since = "1.0.0", reason = "use `std::f32::DIGITS` or `std::f64::DIGITS` as appropriate")] fn digits(unused_self: Option) -> uint; - /// Returns the difference between 1.0 and the smallest representable number larger than 1.0. + /// Deprecated: use `std::f32::EPSILON` or `std::f64::EPSILON` instead. #[unstable(feature = "std_misc")] #[deprecated(since = "1.0.0", reason = "use `std::f32::EPSILON` or `std::f64::EPSILON` as appropriate")] fn epsilon() -> Self; - /// Returns the minimum binary exponent that this type can represent. + /// Deprecated: use `std::f32::MIN_EXP` or `std::f64::MIN_EXP` instead. #[unstable(feature = "std_misc")] #[deprecated(since = "1.0.0", reason = "use `std::f32::MIN_EXP` or `std::f64::MIN_EXP` as appropriate")] fn min_exp(unused_self: Option) -> int; - /// Returns the maximum binary exponent that this type can represent. + /// Deprecated: use `std::f32::MAX_EXP` or `std::f64::MAX_EXP` instead. #[unstable(feature = "std_misc")] #[deprecated(since = "1.0.0", reason = "use `std::f32::MAX_EXP` or `std::f64::MAX_EXP` as appropriate")] fn max_exp(unused_self: Option) -> int; - /// Returns the minimum base-10 exponent that this type can represent. + /// Deprecated: use `std::f32::MIN_10_EXP` or `std::f64::MIN_10_EXP` instead. #[unstable(feature = "std_misc")] #[deprecated(since = "1.0.0", reason = "use `std::f32::MIN_10_EXP` or `std::f64::MIN_10_EXP` as appropriate")] fn min_10_exp(unused_self: Option) -> int; - /// Returns the maximum base-10 exponent that this type can represent. + /// Deprecated: use `std::f32::MAX_10_EXP` or `std::f64::MAX_10_EXP` instead. #[unstable(feature = "std_misc")] #[deprecated(since = "1.0.0", reason = "use `std::f32::MAX_10_EXP` or `std::f64::MAX_10_EXP` as appropriate")] fn max_10_exp(unused_self: Option) -> int; /// Returns the smallest finite value that this type can represent. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let x: f64 = Float::min_value(); + /// + /// assert_eq!(x, f64::MIN); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn min_value() -> Self; @@ -124,50 +196,222 @@ pub trait Float reason = "unsure about its place in the world")] fn min_pos_value(unused_self: Option) -> Self; /// Returns the largest finite value that this type can represent. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let x: f64 = Float::max_value(); + /// assert_eq!(x, f64::MAX); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn max_value() -> Self; - - /// Returns true if this value is NaN and false otherwise. + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let nan = f64::NAN; + /// let f = 7.0; + /// + /// assert!(nan.is_nan()); + /// assert!(!f.is_nan()); + /// ``` #[unstable(feature = "std_misc", reason = "position is undecided")] fn is_nan(self) -> bool; - /// Returns true if this value is positive infinity or negative infinity and + /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. + /// + /// ``` + /// use std::num::Float; + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf: f32 = Float::infinity(); + /// let neg_inf: f32 = Float::neg_infinity(); + /// let nan: f32 = f32::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// assert!(inf.is_infinite()); + /// assert!(neg_inf.is_infinite()); + /// ``` #[unstable(feature = "std_misc", reason = "position is undecided")] fn is_infinite(self) -> bool; - /// Returns true if this number is neither infinite nor NaN. + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::num::Float; + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf: f32 = Float::infinity(); + /// let neg_inf: f32 = Float::neg_infinity(); + /// let nan: f32 = f32::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// assert!(!inf.is_finite()); + /// assert!(!neg_inf.is_finite()); + /// ``` #[unstable(feature = "std_misc", reason = "position is undecided")] fn is_finite(self) -> bool; - /// Returns true if this number is neither zero, infinite, denormal, or NaN. + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::num::Float; + /// use std::f32; + /// + /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 + /// let max = f32::MAX; + /// let lower_than_min = 1.0e-40_f32; + /// let zero = 0.0f32; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f32::NAN.is_normal()); + /// assert!(!f32::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// ``` + /// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number #[unstable(feature = "std_misc", reason = "position is undecided")] fn is_normal(self) -> bool; - /// Returns the category that this number falls into. + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// use std::num::{Float, FpCategory}; + /// use std::f32; + /// + /// let num = 12.4f32; + /// let inf = f32::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn classify(self) -> FpCategory; - /// Returns the mantissa, exponent and sign as integers, respectively. + /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. + /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. + /// The floating point encoding is documented in the [Reference][floating-point]. + /// + /// ``` + /// use std::num::Float; + /// + /// let num = 2.0f32; + /// + /// // (8388608u64, -22i16, 1i8) + /// let (mantissa, exponent, sign) = num.integer_decode(); + /// let sign_f = sign as f32; + /// let mantissa_f = mantissa as f32; + /// let exponent_f = num.powf(exponent as f32); + /// + /// // 1 * 8388608 * 2^(-22) == 2 + /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + /// [floating-point]: ../../../../../reference.html#machine-types #[unstable(feature = "std_misc", reason = "signature is undecided")] fn integer_decode(self) -> (u64, i16, i8); - /// Return the largest integer less than or equal to a number. + /// Returns the largest integer less than or equal to a number. + /// + /// ``` + /// use std::num::Float; + /// + /// let f = 3.99; + /// let g = 3.0; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn floor(self) -> Self; - /// Return the smallest integer greater than or equal to a number. + /// Returns the smallest integer greater than or equal to a number. + /// + /// ``` + /// use std::num::Float; + /// + /// let f = 3.01; + /// let g = 4.0; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn ceil(self) -> Self; - /// Return the nearest integer to a number. Round half-way cases away from + /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. + /// + /// ``` + /// use std::num::Float; + /// + /// let f = 3.3; + /// let g = -3.3; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn round(self) -> Self; /// Return the integer part of a number. + /// + /// ``` + /// use std::num::Float; + /// + /// let f = 3.3; + /// let g = -3.7; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), -3.0); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn trunc(self) -> Self; - /// Return the fractional part of a number. + /// Returns the fractional part of a number. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 3.5; + /// let y = -3.5; + /// let abs_difference_x = (x.fract() - 0.5).abs(); + /// let abs_difference_y = (y.fract() - (-0.5)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn fract(self) -> Self; - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let x = 3.5; + /// let y = -3.5; + /// + /// let abs_difference_x = (x.abs() - x).abs(); + /// let abs_difference_y = (y.abs() - (-y)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// + /// assert!(f64::NAN.abs().is_nan()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn abs(self) -> Self; /// Returns a number that represents the sign of `self`. @@ -175,24 +419,88 @@ pub trait Float /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` /// - `Float::nan()` if the number is `Float::nan()` + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let f = 3.5; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f64::NAN.signum().is_nan()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn signum(self) -> Self; /// Returns `true` if `self` is positive, including `+0.0` and /// `Float::infinity()`. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let nan: f64 = f64::NAN; + /// + /// let f = 7.0; + /// let g = -7.0; + /// + /// assert!(f.is_positive()); + /// assert!(!g.is_positive()); + /// // Requires both tests to determine if is `NaN` + /// assert!(!nan.is_positive() && !nan.is_negative()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn is_positive(self) -> bool; /// Returns `true` if `self` is negative, including `-0.0` and /// `Float::neg_infinity()`. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let nan = f64::NAN; + /// + /// let f = 7.0; + /// let g = -7.0; + /// + /// assert!(!f.is_negative()); + /// assert!(g.is_negative()); + /// // Requires both tests to determine if is `NaN`. + /// assert!(!nan.is_positive() && !nan.is_negative()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn is_negative(self) -> bool; /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than /// a separate multiplication operation followed by an add. + /// + /// ``` + /// use std::num::Float; + /// + /// let m = 10.0; + /// let x = 4.0; + /// let b = 60.0; + /// + /// // 100.0 + /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn mul_add(self, a: Self, b: Self) -> Self; /// Take the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 2.0; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn recip(self) -> Self; @@ -200,149 +508,576 @@ pub trait Float /// Raise a number to an integer power. /// /// Using this function is generally faster than using `powf` + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 2.0; + /// let abs_difference = (x.powi(2) - x*x).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn powi(self, n: i32) -> Self; /// Raise a number to a floating point power. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 2.0; + /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn powf(self, n: Self) -> Self; - /// Take the square root of a number. /// /// Returns NaN if `self` is a negative number. + /// + /// ``` + /// use std::num::Float; + /// + /// let positive = 4.0; + /// let negative = -4.0; + /// + /// let abs_difference = (positive.sqrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// assert!(negative.sqrt().is_nan()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn sqrt(self) -> Self; + /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. + /// + /// ``` + /// use std::num::Float; + /// + /// let f = 4.0; + /// + /// let abs_difference = (f.rsqrt() - 0.5).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn rsqrt(self) -> Self; /// Returns `e^(self)`, (the exponential function). + /// + /// ``` + /// use std::num::Float; + /// + /// let one = 1.0; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn exp(self) -> Self; - /// Returns 2 raised to the power of the number, `2^(self)`. + /// Returns `2^(self)`. + /// + /// ``` + /// use std::num::Float; + /// + /// let f = 2.0; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn exp2(self) -> Self; /// Returns the natural logarithm of the number. + /// + /// ``` + /// use std::num::Float; + /// + /// let one = 1.0; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn ln(self) -> Self; /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// ``` + /// use std::num::Float; + /// + /// let ten = 10.0; + /// let two = 2.0; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs(); + /// + /// // log2(2) - 1 == 0 + /// let abs_difference_2 = (two.log(2.0) - 1.0).abs(); + /// + /// assert!(abs_difference_10 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn log(self, base: Self) -> Self; /// Returns the base 2 logarithm of the number. + /// + /// ``` + /// use std::num::Float; + /// + /// let two = 2.0; + /// + /// // log2(2) - 1 == 0 + /// let abs_difference = (two.log2() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn log2(self) -> Self; /// Returns the base 10 logarithm of the number. + /// + /// ``` + /// use std::num::Float; + /// + /// let ten = 10.0; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference = (ten.log10() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn log10(self) -> Self; /// Convert radians to degrees. + /// + /// ``` + /// use std::num::Float; + /// use std::f64::consts; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "desirability is unclear")] fn to_degrees(self) -> Self; /// Convert degrees to radians. + /// + /// ``` + /// use std::num::Float; + /// use std::f64::consts; + /// + /// let angle = 180.0; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "desirability is unclear")] fn to_radians(self) -> Self; - - /// Constructs a floating point number created by multiplying `x` by 2 - /// raised to the power of `exp`. + /// Constructs a floating point number of `x*2^exp`. + /// + /// ``` + /// use std::num::Float; + /// + /// // 3*2^2 - 12 == 0 + /// let abs_difference = (Float::ldexp(3.0, 2) - 12.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "pending integer conventions")] fn ldexp(x: Self, exp: int) -> Self; /// Breaks the number into a normalized fraction and a base-2 exponent, /// satisfying: /// - /// * `self = x * pow(2, exp)` - /// + /// * `self = x * 2^exp` /// * `0.5 <= abs(x) < 1.0` + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 4.0; + /// + /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 + /// let f = x.frexp(); + /// let abs_difference_0 = (f.0 - 0.5).abs(); + /// let abs_difference_1 = (f.1 as f64 - 3.0).abs(); + /// + /// assert!(abs_difference_0 < 1e-10); + /// assert!(abs_difference_1 < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "pending integer conventions")] fn frexp(self) -> (Self, int); - /// Returns the next representable floating-point value in the direction of /// `other`. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 1.0f32; + /// + /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs(); + /// + /// assert!(abs_diff < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn next_after(self, other: Self) -> Self; /// Returns the maximum of the two numbers. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 1.0; + /// let y = 2.0; + /// + /// assert_eq!(x.max(y), y); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn max(self, other: Self) -> Self; /// Returns the minimum of the two numbers. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 1.0; + /// let y = 2.0; + /// + /// assert_eq!(x.min(y), x); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn min(self, other: Self) -> Self; - /// The positive difference of two numbers. Returns `0.0` if the number is - /// less than or equal to `other`, otherwise the difference between`self` - /// and `other` is returned. + /// The positive difference of two numbers. + /// + /// * If `self <= other`: `0:0` + /// * Else: `self - other` + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 3.0; + /// let y = -3.0; + /// + /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); + /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "may be renamed")] fn abs_sub(self, other: Self) -> Self; - /// Take the cubic root of a number. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 8.0; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "may be renamed")] fn cbrt(self) -> Self; /// Calculate the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 2.0; + /// let y = 3.0; + /// + /// // sqrt(x^2 + y^2) + /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn hypot(self, other: Self) -> Self; /// Computes the sine of a number (in radians). + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let x = f64::consts::PI/2.0; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn sin(self) -> Self; /// Computes the cosine of a number (in radians). + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let x = 2.0*f64::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn cos(self) -> Self; /// Computes the tangent of a number (in radians). + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-14); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn tan(self) -> Self; - /// Computes the arcsine of a number. Return value is in radians in /// the range [-pi/2, pi/2] or NaN if the number is outside the range /// [-1, 1]. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let f = f64::consts::PI / 2.0; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn asin(self) -> Self; /// Computes the arccosine of a number. Return value is in radians in /// the range [0, pi] or NaN if the number is outside the range /// [-1, 1]. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let f = f64::consts::PI / 4.0; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn acos(self) -> Self; /// Computes the arctangent of a number. Return value is in radians in the /// range [-pi/2, pi/2]; + /// + /// ``` + /// use std::num::Float; + /// + /// let f = 1.0; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn atan(self) -> Self; - /// Computes the four quadrant arctangent of a number, `y`, and another - /// number `x`. Return value is in radians in the range [-pi, pi]. + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let pi = f64::consts::PI; + /// // All angles from horizontal right (+x) + /// // 45 deg counter-clockwise + /// let x1 = 3.0; + /// let y1 = -3.0; + /// + /// // 135 deg clockwise + /// let x2 = -3.0; + /// let y2 = 3.0; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// + /// assert!(abs_difference_1 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn atan2(self, other: Self) -> Self; /// Simultaneously computes the sine and cosine of the number, `x`. Returns /// `(sin(x), cos(x))`. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 < 1e-10); + /// assert!(abs_difference_0 < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn sin_cos(self) -> (Self, Self); - /// Returns the exponential of the number, minus 1, in a way that is - /// accurate even if the number is close to zero. + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 7.0; + /// + /// // e^(ln(7)) - 1 + /// let abs_difference = (x.ln().exp_m1() - 6.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "may be renamed")] fn exp_m1(self) -> Self; - /// Returns the natural logarithm of the number plus 1 (`ln(1+n)`) more - /// accurately than if the operations were performed separately. + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let x = f64::consts::E - 1.0; + /// + /// // ln(1 + (e - 1)) == ln(e) == 1 + /// let abs_difference = (x.ln_1p() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[unstable(feature = "std_misc", reason = "may be renamed")] fn ln_1p(self) -> Self; /// Hyperbolic sine function. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// + /// let f = x.sinh(); + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// let g = (e*e - 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn sinh(self) -> Self; /// Hyperbolic cosine function. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// let f = x.cosh(); + /// // Solving cosh() at 1 gives this result + /// let g = (e*e + 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// // Same result + /// assert!(abs_difference < 1.0e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn cosh(self) -> Self; /// Hyperbolic tangent function. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// + /// let f = x.tanh(); + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn tanh(self) -> Self; /// Inverse hyperbolic sine function. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 1.0; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn asinh(self) -> Self; /// Inverse hyperbolic cosine function. + /// + /// ``` + /// use std::num::Float; + /// + /// let x = 1.0; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn acosh(self) -> Self; /// Inverse hyperbolic tangent function. + /// + /// ``` + /// use std::num::Float; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let f = e.tanh().atanh(); + /// + /// let abs_difference = (f - e).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn atanh(self) -> Self; } diff --git a/src/libstd/old_io/comm_adapters.rs b/src/libstd/old_io/comm_adapters.rs index d8f9b1bb3feae..207d3d3916766 100644 --- a/src/libstd/old_io/comm_adapters.rs +++ b/src/libstd/old_io/comm_adapters.rs @@ -161,12 +161,12 @@ mod test { use sync::mpsc::channel; use super::*; use old_io; - use thread::Thread; + use thread; #[test] fn test_rx_reader() { let (tx, rx) = channel(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(vec![1u8, 2u8]).unwrap(); tx.send(vec![]).unwrap(); tx.send(vec![3u8, 4u8]).unwrap(); @@ -208,7 +208,7 @@ mod test { #[test] fn test_rx_buffer() { let (tx, rx) = channel(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(b"he".to_vec()).unwrap(); tx.send(b"llo wo".to_vec()).unwrap(); tx.send(b"".to_vec()).unwrap(); @@ -234,10 +234,7 @@ mod test { writer.write_be_u32(42).unwrap(); let wanted = vec![0u8, 0u8, 0u8, 42u8]; - let got = match Thread::scoped(move|| { rx.recv().unwrap() }).join() { - Ok(got) => got, - Err(_) => panic!(), - }; + let got = thread::scoped(move|| { rx.recv().unwrap() }).join(); assert_eq!(wanted, got); match writer.write_u8(1) { diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs index 3b35444df318f..4bd0662232fec 100644 --- a/src/libstd/old_io/mod.rs +++ b/src/libstd/old_io/mod.rs @@ -124,7 +124,7 @@ //! # #![allow(dead_code)] //! use std::old_io::{TcpListener, TcpStream}; //! use std::old_io::{Acceptor, Listener}; -//! use std::thread::Thread; +//! use std::thread; //! //! let listener = TcpListener::bind("127.0.0.1:80"); //! @@ -140,7 +140,7 @@ //! match stream { //! Err(e) => { /* connection failed */ } //! Ok(stream) => { -//! Thread::spawn(move|| { +//! thread::spawn(move|| { //! // connection succeeded //! handle_client(stream) //! }); @@ -238,7 +238,7 @@ //! concerned with error handling; instead its caller is responsible for //! responding to errors that may occur while attempting to read the numbers. -#![unstable(feature = "io")] +#![unstable(feature = "old_io")] #![deny(unused_must_use)] pub use self::SeekStyle::*; diff --git a/src/libstd/old_io/net/pipe.rs b/src/libstd/old_io/net/pipe.rs index 8c4a10a55d489..6b32d936c05be 100644 --- a/src/libstd/old_io/net/pipe.rs +++ b/src/libstd/old_io/net/pipe.rs @@ -282,19 +282,19 @@ mod tests { use old_io::test::*; use super::*; use sync::mpsc::channel; - use thread::Thread; + use thread; use time::Duration; pub fn smalltest(server: F, client: G) where F : FnOnce(UnixStream), F : Send, - G : FnOnce(UnixStream), G : Send + G : FnOnce(UnixStream), G : Send + 'static { let path1 = next_test_unix(); let path2 = path1.clone(); let mut acceptor = UnixListener::bind(&path1).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { match UnixStream::connect(&path2) { Ok(c) => client(c), Err(e) => panic!("failed connect: {}", e), @@ -389,7 +389,7 @@ mod tests { Err(e) => panic!("failed listen: {}", e), }; - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { for _ in 0u..times { let mut stream = UnixStream::connect(&path2); match stream.write(&[100]) { @@ -423,7 +423,7 @@ mod tests { let addr = next_test_unix(); let mut acceptor = UnixListener::bind(&addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s = UnixStream::connect(&addr); let mut buf = [0, 0]; debug!("client reading"); @@ -439,7 +439,7 @@ mod tests { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; rx1.recv().unwrap(); debug!("writer writing"); @@ -462,7 +462,7 @@ mod tests { let (tx1, rx) = channel(); let tx2 = tx1.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s = UnixStream::connect(&addr); s.write(&[1]).unwrap(); rx.recv().unwrap(); @@ -474,7 +474,7 @@ mod tests { let s2 = s1.clone(); let (done, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; let mut buf = [0, 0]; s2.read(&mut buf).unwrap(); @@ -493,7 +493,7 @@ mod tests { let addr = next_test_unix(); let mut acceptor = UnixListener::bind(&addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s = UnixStream::connect(&addr); let buf = &mut [0, 1]; s.read(buf).unwrap(); @@ -504,7 +504,7 @@ mod tests { let s2 = s1.clone(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; s2.write(&[1]).unwrap(); tx.send(()).unwrap(); @@ -551,7 +551,7 @@ mod tests { // continue to receive any pending connections. let (tx, rx) = channel(); let addr2 = addr.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { tx.send(UnixStream::connect(&addr2).unwrap()).unwrap(); }); let l = rx.recv().unwrap(); @@ -561,7 +561,7 @@ mod tests { Err(ref e) if e.kind == TimedOut => {} Err(e) => panic!("error: {}", e), } - ::thread::Thread::yield_now(); + ::thread::yield_now(); if i == 1000 { panic!("should have a pending connection") } } drop(l); @@ -569,7 +569,7 @@ mod tests { // Unset the timeout and make sure that this always blocks. a.set_timeout(None); let addr2 = addr.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(UnixStream::connect(&addr2).unwrap()); }); a.accept().unwrap(); @@ -607,7 +607,7 @@ mod tests { let addr = next_test_unix(); let a = UnixListener::bind(&addr).listen().unwrap(); let (_tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut a = a; let _s = a.accept().unwrap(); let _ = rx.recv(); @@ -644,7 +644,7 @@ mod tests { let addr = next_test_unix(); let a = UnixListener::bind(&addr).listen().unwrap(); let (_tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut a = a; let _s = a.accept().unwrap(); let _ = rx.recv(); @@ -653,7 +653,7 @@ mod tests { let mut s = UnixStream::connect(&addr).unwrap(); let s2 = s.clone(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; assert!(s2.read(&mut [0]).is_err()); tx.send(()).unwrap(); @@ -670,7 +670,7 @@ mod tests { let addr = next_test_unix(); let mut a = UnixListener::bind(&addr).listen().unwrap(); let (tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut s = UnixStream::connect(&addr).unwrap(); rx.recv().unwrap(); assert!(s.write(&[0]).is_ok()); @@ -708,7 +708,7 @@ mod tests { let addr = next_test_unix(); let mut a = UnixListener::bind(&addr).listen().unwrap(); let (tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut s = UnixStream::connect(&addr).unwrap(); rx.recv().unwrap(); let mut amt = 0; @@ -737,7 +737,7 @@ mod tests { let addr = next_test_unix(); let mut a = UnixListener::bind(&addr).listen().unwrap(); let (tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut s = UnixStream::connect(&addr).unwrap(); rx.recv().unwrap(); assert!(s.write(&[0]).is_ok()); @@ -764,7 +764,7 @@ mod tests { let addr = next_test_unix(); let mut a = UnixListener::bind(&addr).listen().unwrap(); let (tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut s = UnixStream::connect(&addr).unwrap(); rx.recv().unwrap(); assert!(s.write(&[0]).is_ok()); @@ -774,7 +774,7 @@ mod tests { let mut s = a.accept().unwrap(); let s2 = s.clone(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; assert!(s2.read(&mut [0]).is_ok()); tx2.send(()).unwrap(); @@ -796,10 +796,10 @@ mod tests { let mut a2 = a.clone(); let addr2 = addr.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _ = UnixStream::connect(&addr2); }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _ = UnixStream::connect(&addr); }); @@ -819,20 +819,20 @@ mod tests { let (tx, rx) = channel(); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut a = a; tx.send(a.accept()).unwrap() }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut a = a2; tx2.send(a.accept()).unwrap() }); let addr2 = addr.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _ = UnixStream::connect(&addr2); }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _ = UnixStream::connect(&addr); }); @@ -858,7 +858,7 @@ mod tests { let mut a2 = a.clone(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut a = a; tx.send(a.accept()).unwrap(); }); diff --git a/src/libstd/old_io/net/tcp.rs b/src/libstd/old_io/net/tcp.rs index ebf7f6cc0f2a9..2afff9fc1c9b9 100644 --- a/src/libstd/old_io/net/tcp.rs +++ b/src/libstd/old_io/net/tcp.rs @@ -137,12 +137,12 @@ impl TcpStream { /// use std::old_io::timer; /// use std::old_io::TcpStream; /// use std::time::Duration; - /// use std::thread::Thread; + /// use std::thread; /// /// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); /// let stream2 = stream.clone(); /// - /// let _t = Thread::spawn(move|| { + /// let _t = thread::spawn(move|| { /// // close this stream after one second /// timer::sleep(Duration::seconds(1)); /// let mut stream = stream2; @@ -282,7 +282,7 @@ impl sys_common::AsInner for TcpStream { /// # fn foo() { /// use std::old_io::{TcpListener, TcpStream}; /// use std::old_io::{Acceptor, Listener}; -/// use std::thread::Thread; +/// use std::thread; /// /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); /// @@ -298,7 +298,7 @@ impl sys_common::AsInner for TcpStream { /// match stream { /// Err(e) => { /* connection failed */ } /// Ok(stream) => { -/// Thread::spawn(move|| { +/// thread::spawn(move|| { /// // connection succeeded /// handle_client(stream) /// }); @@ -421,12 +421,12 @@ impl TcpAcceptor { /// /// ``` /// use std::old_io::{TcpListener, Listener, Acceptor, EndOfFile}; - /// use std::thread::Thread; + /// use std::thread; /// /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); /// let a2 = a.clone(); /// - /// let _t = Thread::spawn(move|| { + /// let _t = thread::spawn(move|| { /// let mut a2 = a2; /// for socket in a2.incoming() { /// match socket { @@ -487,13 +487,14 @@ mod test { use prelude::v1::*; use sync::mpsc::channel; - use thread::Thread; + use thread; use old_io::net::tcp::*; use old_io::net::ip::*; use old_io::test::*; use old_io::{EndOfFile, TimedOut, ShortWrite, IoError}; use old_io::{ConnectionRefused, BrokenPipe, ConnectionAborted}; use old_io::{ConnectionReset, NotConnected, PermissionDenied, OtherIoError}; + use old_io::{InvalidInput}; use old_io::{Acceptor, Listener}; // FIXME #11530 this fails on android because tests are run as root @@ -510,7 +511,8 @@ mod test { fn connect_error() { match TcpStream::connect("0.0.0.0:1") { Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, ConnectionRefused), + Err(e) => assert!((e.kind == ConnectionRefused) + || (e.kind == InvalidInput)), } } @@ -520,7 +522,7 @@ mod test { let listener = TcpListener::bind(socket_addr); let mut acceptor = listener.listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = TcpStream::connect(("localhost", socket_addr.port)); stream.write(&[144]).unwrap(); }); @@ -536,7 +538,7 @@ mod test { let addr = next_test_ip4(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = TcpStream::connect(("localhost", addr.port)); stream.write(&[64]).unwrap(); }); @@ -552,7 +554,7 @@ mod test { let addr = next_test_ip4(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = TcpStream::connect(("127.0.0.1", addr.port)); stream.write(&[44]).unwrap(); }); @@ -568,7 +570,7 @@ mod test { let addr = next_test_ip6(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = TcpStream::connect(("::1", addr.port)); stream.write(&[66]).unwrap(); }); @@ -584,7 +586,7 @@ mod test { let addr = next_test_ip4(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = TcpStream::connect(addr); stream.write(&[99]).unwrap(); }); @@ -600,7 +602,7 @@ mod test { let addr = next_test_ip6(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = TcpStream::connect(addr); stream.write(&[99]).unwrap(); }); @@ -616,7 +618,7 @@ mod test { let addr = next_test_ip4(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _stream = TcpStream::connect(addr); // Close }); @@ -632,7 +634,7 @@ mod test { let addr = next_test_ip6(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _stream = TcpStream::connect(addr); // Close }); @@ -648,7 +650,7 @@ mod test { let addr = next_test_ip4(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _stream = TcpStream::connect(addr); // Close }); @@ -672,7 +674,7 @@ mod test { let addr = next_test_ip6(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _stream = TcpStream::connect(addr); // Close }); @@ -697,7 +699,7 @@ mod test { let mut acceptor = TcpListener::bind(addr).listen(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(TcpStream::connect(addr)); tx.send(()).unwrap(); }); @@ -722,7 +724,7 @@ mod test { let mut acceptor = TcpListener::bind(addr).listen(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(TcpStream::connect(addr)); tx.send(()).unwrap(); }); @@ -747,7 +749,7 @@ mod test { let max = 10u; let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { for _ in 0..max { let mut stream = TcpStream::connect(addr); stream.write(&[99]).unwrap(); @@ -767,7 +769,7 @@ mod test { let max = 10u; let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { for _ in 0..max { let mut stream = TcpStream::connect(addr); stream.write(&[99]).unwrap(); @@ -787,11 +789,11 @@ mod test { static MAX: int = 10; let acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut acceptor = acceptor; for (i, stream) in acceptor.incoming().enumerate().take(MAX as uint) { // Start another task to handle the connection - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = stream; let mut buf = [0]; stream.read(&mut buf).unwrap(); @@ -806,7 +808,7 @@ mod test { fn connect(i: int, addr: SocketAddr) { if i == MAX { return } - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { debug!("connecting"); let mut stream = TcpStream::connect(addr); // Connect again before writing @@ -823,11 +825,11 @@ mod test { static MAX: int = 10; let acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut acceptor = acceptor; for (i, stream) in acceptor.incoming().enumerate().take(MAX as uint) { // Start another task to handle the connection - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = stream; let mut buf = [0]; stream.read(&mut buf).unwrap(); @@ -842,7 +844,7 @@ mod test { fn connect(i: int, addr: SocketAddr) { if i == MAX { return } - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { debug!("connecting"); let mut stream = TcpStream::connect(addr); // Connect again before writing @@ -859,11 +861,11 @@ mod test { let addr = next_test_ip4(); let acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut acceptor = acceptor; for stream in acceptor.incoming().take(MAX as uint) { // Start another task to handle the connection - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = stream; let mut buf = [0]; stream.read(&mut buf).unwrap(); @@ -878,7 +880,7 @@ mod test { fn connect(i: int, addr: SocketAddr) { if i == MAX { return } - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { debug!("connecting"); let mut stream = TcpStream::connect(addr); // Connect again before writing @@ -895,11 +897,11 @@ mod test { let addr = next_test_ip6(); let acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut acceptor = acceptor; for stream in acceptor.incoming().take(MAX as uint) { // Start another task to handle the connection - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut stream = stream; let mut buf = [0]; stream.read(&mut buf).unwrap(); @@ -914,7 +916,7 @@ mod test { fn connect(i: int, addr: SocketAddr) { if i == MAX { return } - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { debug!("connecting"); let mut stream = TcpStream::connect(addr); // Connect again before writing @@ -937,7 +939,7 @@ mod test { pub fn peer_name(addr: SocketAddr) { let acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut acceptor = acceptor; acceptor.accept().unwrap(); }); @@ -972,7 +974,7 @@ mod test { fn partial_read() { let addr = next_test_ip4(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut srv = TcpListener::bind(addr).listen().unwrap(); tx.send(()).unwrap(); let mut cl = srv.accept().unwrap(); @@ -1009,7 +1011,7 @@ mod test { let addr = next_test_ip4(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx.recv().unwrap(); let _stream = TcpStream::connect(addr).unwrap(); // Close @@ -1034,7 +1036,7 @@ mod test { let addr = next_test_ip4(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s = TcpStream::connect(addr); let mut buf = [0, 0]; assert_eq!(s.read(&mut buf), Ok(1)); @@ -1047,7 +1049,7 @@ mod test { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; rx1.recv().unwrap(); s2.write(&[1]).unwrap(); @@ -1066,7 +1068,7 @@ mod test { let (tx1, rx) = channel(); let tx2 = tx1.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s = TcpStream::connect(addr); s.write(&[1]).unwrap(); rx.recv().unwrap(); @@ -1078,7 +1080,7 @@ mod test { let s2 = s1.clone(); let (done, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; let mut buf = [0, 0]; s2.read(&mut buf).unwrap(); @@ -1097,7 +1099,7 @@ mod test { let addr = next_test_ip4(); let mut acceptor = TcpListener::bind(addr).listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s = TcpStream::connect(addr); let mut buf = [0, 1]; s.read(&mut buf).unwrap(); @@ -1108,7 +1110,7 @@ mod test { let s2 = s1.clone(); let (done, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; s2.write(&[1]).unwrap(); done.send(()).unwrap(); @@ -1122,7 +1124,7 @@ mod test { fn shutdown_smoke() { let addr = next_test_ip4(); let a = TcpListener::bind(addr).unwrap().listen(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut a = a; let mut c = a.accept().unwrap(); assert_eq!(c.read_to_end(), Ok(vec!())); @@ -1156,7 +1158,7 @@ mod test { // flakiness. if !cfg!(target_os = "freebsd") { let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { tx.send(TcpStream::connect(addr).unwrap()).unwrap(); }); let _l = rx.recv().unwrap(); @@ -1166,14 +1168,14 @@ mod test { Err(ref e) if e.kind == TimedOut => {} Err(e) => panic!("error: {}", e), } - ::thread::Thread::yield_now(); + ::thread::yield_now(); if i == 1000 { panic!("should have a pending connection") } } } // Unset the timeout and make sure that this always blocks. a.set_timeout(None); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(TcpStream::connect(addr).unwrap()); }); a.accept().unwrap(); @@ -1184,7 +1186,7 @@ mod test { let addr = next_test_ip4(); let a = TcpListener::bind(addr).listen().unwrap(); let (_tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut a = a; let _s = a.accept().unwrap(); let _ = rx.recv().unwrap(); @@ -1221,7 +1223,7 @@ mod test { let addr = next_test_ip4(); let a = TcpListener::bind(addr).listen().unwrap(); let (_tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut a = a; let _s = a.accept().unwrap(); let _ = rx.recv().unwrap(); @@ -1230,7 +1232,7 @@ mod test { let mut s = TcpStream::connect(addr).unwrap(); let s2 = s.clone(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; assert!(s2.read(&mut [0]).is_err()); tx.send(()).unwrap(); @@ -1247,7 +1249,7 @@ mod test { let addr = next_test_ip6(); let mut a = TcpListener::bind(addr).listen().unwrap(); let (tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut s = TcpStream::connect(addr).unwrap(); rx.recv().unwrap(); assert!(s.write(&[0]).is_ok()); @@ -1280,7 +1282,7 @@ mod test { let addr = next_test_ip6(); let mut a = TcpListener::bind(addr).listen().unwrap(); let (tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut s = TcpStream::connect(addr).unwrap(); rx.recv().unwrap(); let mut amt = 0; @@ -1309,7 +1311,7 @@ mod test { let addr = next_test_ip6(); let mut a = TcpListener::bind(addr).listen().unwrap(); let (tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut s = TcpStream::connect(addr).unwrap(); rx.recv().unwrap(); assert!(s.write(&[0]).is_ok()); @@ -1337,7 +1339,7 @@ mod test { let addr = next_test_ip6(); let mut a = TcpListener::bind(addr).listen().unwrap(); let (tx, rx) = channel::<()>(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut s = TcpStream::connect(addr).unwrap(); rx.recv().unwrap(); assert_eq!(s.write(&[0]), Ok(())); @@ -1347,7 +1349,7 @@ mod test { let mut s = a.accept().unwrap(); let s2 = s.clone(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut s2 = s2; assert_eq!(s2.read(&mut [0]), Ok(1)); tx2.send(()).unwrap(); @@ -1370,7 +1372,7 @@ mod test { let (tx, rx) = channel(); let (txdone, rxdone) = channel(); let txdone2 = txdone.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut tcp = TcpStream::connect(addr).unwrap(); rx.recv().unwrap(); tcp.write_u8(0).unwrap(); @@ -1381,7 +1383,7 @@ mod test { let tcp = accept.accept().unwrap(); let tcp2 = tcp.clone(); let txdone3 = txdone.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut tcp2 = tcp2; tcp2.read_u8().unwrap(); txdone3.send(()).unwrap(); @@ -1389,7 +1391,7 @@ mod test { // Try to ensure that the reading clone is indeed reading for _ in 0..50 { - ::thread::Thread::yield_now(); + ::thread::yield_now(); } // clone the handle again while it's reading, then let it finish the @@ -1407,10 +1409,10 @@ mod test { let mut a = l.listen().unwrap(); let mut a2 = a.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _ = TcpStream::connect(addr); }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _ = TcpStream::connect(addr); }); @@ -1428,19 +1430,19 @@ mod test { let (tx, rx) = channel(); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut a = a; tx.send(a.accept()).unwrap(); }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut a = a2; tx2.send(a.accept()).unwrap(); }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _ = TcpStream::connect(addr); }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _ = TcpStream::connect(addr); }); @@ -1466,7 +1468,7 @@ mod test { let mut a2 = a.clone(); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut a = a; tx.send(a.accept()).unwrap(); }); diff --git a/src/libstd/old_io/net/udp.rs b/src/libstd/old_io/net/udp.rs index 8dc19047de08e..7171198e7a4aa 100644 --- a/src/libstd/old_io/net/udp.rs +++ b/src/libstd/old_io/net/udp.rs @@ -186,7 +186,7 @@ mod test { use old_io::test::*; use old_io::{IoError, TimedOut, PermissionDenied, ShortWrite}; use super::*; - use thread::Thread; + use thread; // FIXME #11530 this fails on android because tests are run as root #[cfg_attr(any(windows, target_os = "android"), ignore)] @@ -206,7 +206,7 @@ mod test { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { match UdpSocket::bind(client_ip) { Ok(ref mut client) => { rx1.recv().unwrap(); @@ -241,7 +241,7 @@ mod test { let client_ip = next_test_ip6(); let (tx, rx) = channel::<()>(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { match UdpSocket::bind(client_ip) { Ok(ref mut client) => { rx.recv().unwrap(); @@ -298,7 +298,7 @@ mod test { let mut sock1 = UdpSocket::bind(addr1).unwrap(); let sock2 = UdpSocket::bind(addr2).unwrap(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut sock2 = sock2; let mut buf = [0, 0]; assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1))); @@ -310,7 +310,7 @@ mod test { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut sock3 = sock3; rx1.recv().unwrap(); sock3.send_to(&[1], addr2).unwrap(); @@ -331,7 +331,7 @@ mod test { let (tx1, rx) = channel(); let tx2 = tx1.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut sock2 = sock2; sock2.send_to(&[1], addr1).unwrap(); rx.recv().unwrap(); @@ -342,7 +342,7 @@ mod test { let sock3 = sock1.clone(); let (done, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut sock3 = sock3; let mut buf = [0, 0]; sock3.recv_from(&mut buf).unwrap(); @@ -366,7 +366,7 @@ mod test { let (tx, rx) = channel(); let (serv_tx, serv_rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut sock2 = sock2; let mut buf = [0, 1]; @@ -382,7 +382,7 @@ mod test { let (done, rx) = channel(); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut sock3 = sock3; match sock3.send_to(&[1], addr2) { Ok(..) => { let _ = tx2.send(()); } @@ -410,7 +410,7 @@ mod test { let (tx, rx) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut a = a2; assert_eq!(a.recv_from(&mut [0]), Ok((1, addr1))); assert_eq!(a.send_to(&[0], addr1), Ok(())); diff --git a/src/libstd/old_io/pipe.rs b/src/libstd/old_io/pipe.rs index 5843b1ba1b13f..b7b626db034e1 100644 --- a/src/libstd/old_io/pipe.rs +++ b/src/libstd/old_io/pipe.rs @@ -115,7 +115,7 @@ mod test { use prelude::v1::*; use sync::mpsc::channel; - use thread::Thread; + use thread; #[test] fn partial_read() { @@ -126,7 +126,7 @@ mod test { let out = PipeStream::open(writer); let mut input = PipeStream::open(reader); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut out = out; out.write(&[10]).unwrap(); rx.recv().unwrap(); // don't close the pipe until the other read has finished diff --git a/src/libstd/old_io/process.rs b/src/libstd/old_io/process.rs index 195d33c41a68e..ea6510c61b76b 100644 --- a/src/libstd/old_io/process.rs +++ b/src/libstd/old_io/process.rs @@ -30,7 +30,7 @@ use sync::mpsc::{channel, Receiver}; use sys::fs::FileDesc; use sys::process::Process as ProcessImp; use sys; -use thread::Thread; +use thread; #[cfg(windows)] use hash; #[cfg(windows)] use str; @@ -703,7 +703,7 @@ impl Process { let (tx, rx) = channel(); match stream { Some(stream) => { - Thread::spawn(move || { + thread::spawn(move || { let mut stream = stream; tx.send(stream.read_to_end()).unwrap(); }); @@ -764,7 +764,7 @@ mod tests { use super::{CreatePipe}; use super::{InheritFd, Process, PleaseExitSignal, Command, ProcessOutput}; use sync::mpsc::channel; - use thread::Thread; + use thread; use time::Duration; // FIXME(#10380) these tests should not all be ignored on android. @@ -800,12 +800,12 @@ mod tests { #[cfg(all(unix, not(target_os="android")))] #[test] fn signal_reported_right() { - let p = Command::new("/bin/sh").arg("-c").arg("kill -1 $$").spawn(); + let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn(); assert!(p.is_ok()); let mut p = p.unwrap(); match p.wait().unwrap() { - process::ExitSignal(1) => {}, - result => panic!("not terminated by signal 1 (instead, {})", result), + process::ExitSignal(9) => {}, + result => panic!("not terminated by signal 9 (instead, {})", result), } } @@ -1169,14 +1169,14 @@ mod tests { fn wait_timeout2() { let (tx, rx) = channel(); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut p = sleeper(); p.set_timeout(Some(10)); assert_eq!(p.wait().err().unwrap().kind, TimedOut); p.signal_kill().unwrap(); tx.send(()).unwrap(); }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut p = sleeper(); p.set_timeout(Some(10)); assert_eq!(p.wait().err().unwrap().kind, TimedOut); diff --git a/src/libstd/old_io/stdio.rs b/src/libstd/old_io/stdio.rs index 70cce1f7e769e..e3d0232684fcc 100644 --- a/src/libstd/old_io/stdio.rs +++ b/src/libstd/old_io/stdio.rs @@ -530,7 +530,7 @@ mod tests { use super::*; use sync::mpsc::channel; - use thread::Thread; + use thread; #[test] fn smoke() { @@ -546,7 +546,7 @@ mod tests { let (tx, rx) = channel(); let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx)); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { set_stdout(box w); println!("hello!"); }); @@ -559,7 +559,7 @@ mod tests { let (tx, rx) = channel(); let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx)); - let _t = Thread::spawn(move || -> () { + let _t = thread::spawn(move || -> () { set_stderr(box w); panic!("my special message"); }); diff --git a/src/libstd/old_io/timer.rs b/src/libstd/old_io/timer.rs index 35f0bcb21d94b..8b84e27eae1ba 100644 --- a/src/libstd/old_io/timer.rs +++ b/src/libstd/old_io/timer.rs @@ -224,13 +224,13 @@ fn in_ms_u64(d: Duration) -> u64 { #[cfg(test)] mod test { use super::Timer; - use thread::Thread; + use thread; use time::Duration; #[test] fn test_timer_send() { let mut timer = Timer::new().unwrap(); - Thread::spawn(move || timer.sleep(Duration::milliseconds(1))); + thread::spawn(move || timer.sleep(Duration::milliseconds(1))); } #[test] @@ -360,7 +360,7 @@ mod test { let mut timer = Timer::new().unwrap(); let timer_rx = timer.periodic(Duration::milliseconds(1000)); - Thread::spawn(move|| { + thread::spawn(move|| { let _ = timer_rx.recv(); }); @@ -374,7 +374,7 @@ mod test { let mut timer = Timer::new().unwrap(); let timer_rx = timer.periodic(Duration::milliseconds(1000)); - Thread::spawn(move|| { + thread::spawn(move|| { let _ = timer_rx.recv(); }); @@ -387,7 +387,7 @@ mod test { let mut timer = Timer::new().unwrap(); let timer_rx = timer.periodic(Duration::milliseconds(1000)); - Thread::spawn(move|| { + thread::spawn(move|| { let _ = timer_rx.recv(); }); diff --git a/src/libstd/old_path/mod.rs b/src/libstd/old_path/mod.rs index 17cfe1c82972f..37de2993c4d0f 100644 --- a/src/libstd/old_path/mod.rs +++ b/src/libstd/old_path/mod.rs @@ -59,7 +59,7 @@ //! println!("path exists: {}", path.exists()); //! ``` -#![unstable(feature = "path")] +#![unstable(feature = "old_path")] use core::marker::Sized; use ffi::CString; diff --git a/src/libstd/old_path/posix.rs b/src/libstd/old_path/posix.rs index 6bf2a30b7b184..440d17cfd50f7 100644 --- a/src/libstd/old_path/posix.rs +++ b/src/libstd/old_path/posix.rs @@ -518,18 +518,18 @@ mod tests { #[test] fn test_null_byte() { - use thread::Thread; - let result = Thread::scoped(move|| { - Path::new(b"foo/bar\0") + use thread; + let result = thread::spawn(move|| { + Path::new(b"foo/bar\0"); }).join(); assert!(result.is_err()); - let result = Thread::scoped(move|| { + let result = thread::spawn(move|| { Path::new("test").set_filename(b"f\0o") }).join(); assert!(result.is_err()); - let result = Thread::scoped(move|| { + let result = thread::spawn(move|| { Path::new("test").push(b"f\0o"); }).join(); assert!(result.is_err()); diff --git a/src/libstd/old_path/windows.rs b/src/libstd/old_path/windows.rs index 54c070e1b7db8..07c5e10992b63 100644 --- a/src/libstd/old_path/windows.rs +++ b/src/libstd/old_path/windows.rs @@ -1305,18 +1305,18 @@ mod tests { #[test] fn test_null_byte() { - use thread::Thread; - let result = Thread::scoped(move|| { - Path::new(b"foo/bar\0") + use thread; + let result = thread::spawn(move|| { + Path::new(b"foo/bar\0"); }).join(); assert!(result.is_err()); - let result = Thread::scoped(move|| { + let result = thread::spawn(move|| { Path::new("test").set_filename(b"f\0o") }).join(); assert!(result.is_err()); - let result = Thread::scoped(move || { + let result = thread::spawn(move || { Path::new("test").push(b"f\0o"); }).join(); assert!(result.is_err()); diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index e485c6a63c6f1..35221a7e647cc 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -17,7 +17,7 @@ use cell::RefCell; use old_io::IoResult; use rt::{backtrace, unwind}; use rt::util::{Stderr, Stdio}; -use thread::Thread; +use thread; // Defined in this module instead of old_io::stdio so that the unwinding thread_local! { @@ -42,7 +42,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: uint) { } }; let mut err = Stderr; - let thread = Thread::current(); + let thread = thread::current(); let name = thread.name().unwrap_or(""); let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take()); match prev { diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 1f6d39fb1b3f4..1d992668900f0 100755 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -107,6 +107,7 @@ use core::prelude::*; +use ascii::*; use borrow::BorrowFrom; use cmp; use iter; @@ -118,7 +119,7 @@ use fmt; use ffi::{OsStr, OsString, AsOsStr}; -use self::platform::{is_sep, is_verbatim_sep, MAIN_SEP_STR, parse_prefix, Prefix}; +use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; //////////////////////////////////////////////////////////////////////////////// // GENERAL NOTES @@ -139,11 +140,12 @@ use self::platform::{is_sep, is_verbatim_sep, MAIN_SEP_STR, parse_prefix, Prefix #[cfg(unix)] mod platform { + use super::Prefix; use core::prelude::*; use ffi::OsStr; #[inline] - pub fn is_sep(b: u8) -> bool { + pub fn is_sep_byte(b: u8) -> bool { b == b'/' } @@ -156,34 +158,21 @@ mod platform { None } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] - pub struct Prefix<'a>; - - impl<'a> Prefix<'a> { - #[inline] - pub fn len(&self) -> usize { 0 } - #[inline] - pub fn is_verbatim(&self) -> bool { false } - #[inline] - pub fn is_drive(&self) -> bool { false } - #[inline] - pub fn has_implicit_root(&self) -> bool { false } - } - pub const MAIN_SEP_STR: &'static str = "/"; + pub const MAIN_SEP: char = '/'; } #[cfg(windows)] mod platform { use core::prelude::*; + use ascii::*; use char::CharExt as UnicodeCharExt; - use super::{os_str_as_u8_slice, u8_slice_as_os_str}; - use ascii::*; + use super::{os_str_as_u8_slice, u8_slice_as_os_str, Prefix}; use ffi::OsStr; #[inline] - pub fn is_sep(b: u8) -> bool { + pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' } @@ -193,7 +182,7 @@ mod platform { } pub fn parse_prefix<'a>(path: &'a OsStr) -> Option { - use self::Prefix::*; + use super::Prefix::*; unsafe { // The unsafety here stems from converting between &OsStr and &[u8] // and back. This is safe to do because (1) we only look at ASCII @@ -224,8 +213,7 @@ mod platform { let c = path[0]; if c.is_ascii() && (c as char).is_alphabetic() { // \\?\C:\ path - let slice = u8_slice_as_os_str(&path[0..1]); - return Some(VerbatimDisk(slice)); + return Some(VerbatimDisk(c.to_ascii_uppercase())); } } let slice = &path[.. idx.unwrap_or(path.len())]; @@ -237,7 +225,7 @@ mod platform { let slice = &path[.. path.position_elem(&b'\\').unwrap_or(path.len())]; return Some(DeviceNS(u8_slice_as_os_str(slice))); } - match parse_two_comps(path, is_sep) { + match parse_two_comps(path, is_sep_byte) { Some((server, share)) if server.len() > 0 && share.len() > 0 => { // \\server\share return Some(UNC(u8_slice_as_os_str(server), @@ -249,7 +237,7 @@ mod platform { // C: let c = path[0]; if c.is_ascii() && (c as char).is_alphabetic() { - return Some(Disk(u8_slice_as_os_str(&path[0..1]))); + return Some(Disk(c.to_ascii_uppercase())); } } return None; @@ -267,99 +255,102 @@ mod platform { } } - /// Windows path prefixes. - /// - /// Windows uses a variety of path styles, including references to drive - /// volumes (like `C:`), network shared (like `\\server\share`) and - /// others. In addition, some path prefixes are "verbatim", in which case - /// `/` is *not* treated as a separator and essentially no normalization is - /// performed. - #[derive(Copy, Clone, Debug, Hash, Eq)] - pub enum Prefix<'a> { - /// Prefix `\\?\`, together with the given component immediately following it. - Verbatim(&'a OsStr), - - /// Prefix `\\?\UNC\`, with the "server" and "share" components following it. - VerbatimUNC(&'a OsStr, &'a OsStr), - - /// Prefix like `\\?\C:\`, for the given drive letter - VerbatimDisk(&'a OsStr), - - /// Prefix `\\.\`, together with the given component immediately following it. - DeviceNS(&'a OsStr), - - /// Prefix `\\server\share`, with the given "server" and "share" components. - UNC(&'a OsStr, &'a OsStr), - - /// Prefix `C:` for the given disk drive. - Disk(&'a OsStr), - } - - impl<'a> Prefix<'a> { - #[inline] - pub fn len(&self) -> usize { - use self::Prefix::*; - fn os_str_len(s: &OsStr) -> usize { - os_str_as_u8_slice(s).len() - } - match *self { - Verbatim(x) => 4 + os_str_len(x), - VerbatimUNC(x,y) => 8 + os_str_len(x) + - if os_str_len(y) > 0 { 1 + os_str_len(y) } - else { 0 }, - VerbatimDisk(_) => 6, - UNC(x,y) => 2 + os_str_len(x) + - if os_str_len(y) > 0 { 1 + os_str_len(y) } - else { 0 }, - DeviceNS(x) => 4 + os_str_len(x), - Disk(_) => 2 - } + pub const MAIN_SEP_STR: &'static str = "\\"; + pub const MAIN_SEP: char = '\\'; +} - } +//////////////////////////////////////////////////////////////////////////////// +// Windows Prefixes +//////////////////////////////////////////////////////////////////////////////// - #[inline] - pub fn is_verbatim(&self) -> bool { - use self::Prefix::*; - match *self { - Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(_, _) => true, - _ => false - } - } +/// Path prefixes (Windows only). +/// +/// Windows uses a variety of path styles, including references to drive +/// volumes (like `C:`), network shared (like `\\server\share`) and +/// others. In addition, some path prefixes are "verbatim", in which case +/// `/` is *not* treated as a separator and essentially no normalization is +/// performed. +#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] +pub enum Prefix<'a> { + /// Prefix `\\?\`, together with the given component immediately following it. + Verbatim(&'a OsStr), + + /// Prefix `\\?\UNC\`, with the "server" and "share" components following it. + VerbatimUNC(&'a OsStr, &'a OsStr), + + /// Prefix like `\\?\C:\`, for the given drive letter + VerbatimDisk(u8), + + /// Prefix `\\.\`, together with the given component immediately following it. + DeviceNS(&'a OsStr), + + /// Prefix `\\server\share`, with the given "server" and "share" components. + UNC(&'a OsStr, &'a OsStr), + + /// Prefix `C:` for the given disk drive. + Disk(u8), +} - #[inline] - pub fn is_drive(&self) -> bool { - match *self { - Prefix::Disk(_) => true, - _ => false, - } +impl<'a> Prefix<'a> { + #[inline] + fn len(&self) -> usize { + use self::Prefix::*; + fn os_str_len(s: &OsStr) -> usize { + os_str_as_u8_slice(s).len() + } + match *self { + Verbatim(x) => 4 + os_str_len(x), + VerbatimUNC(x,y) => 8 + os_str_len(x) + + if os_str_len(y) > 0 { 1 + os_str_len(y) } + else { 0 }, + VerbatimDisk(_) => 6, + UNC(x,y) => 2 + os_str_len(x) + + if os_str_len(y) > 0 { 1 + os_str_len(y) } + else { 0 }, + DeviceNS(x) => 4 + os_str_len(x), + Disk(_) => 2 } - #[inline] - pub fn has_implicit_root(&self) -> bool { - !self.is_drive() + } + + /// Determine if the prefix is verbatim, i.e. begins `\\?\`. + #[inline] + pub fn is_verbatim(&self) -> bool { + use self::Prefix::*; + match *self { + Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(_, _) => true, + _ => false } } - impl<'a> PartialEq for Prefix<'a> { - fn eq(&self, other: &Prefix<'a>) -> bool { - use self::Prefix::*; - match (*self, *other) { - (Verbatim(x), Verbatim(y)) => x == y, - (VerbatimUNC(x1, x2), VerbatimUNC(y1, y2)) => x1 == y1 && x2 == y2, - (VerbatimDisk(x), VerbatimDisk(y)) => - os_str_as_u8_slice(x).eq_ignore_ascii_case(os_str_as_u8_slice(y)), - (DeviceNS(x), DeviceNS(y)) => x == y, - (UNC(x1, x2), UNC(y1, y2)) => x1 == y1 && x2 == y2, - (Disk(x), Disk(y)) => - os_str_as_u8_slice(x).eq_ignore_ascii_case(os_str_as_u8_slice(y)), - _ => false, - } + #[inline] + fn is_drive(&self) -> bool { + match *self { + Prefix::Disk(_) => true, + _ => false, } } - pub const MAIN_SEP_STR: &'static str = "\\"; + #[inline] + fn has_implicit_root(&self) -> bool { + !self.is_drive() + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Exposed parsing helpers +//////////////////////////////////////////////////////////////////////////////// + +/// Determine whether the character is one of the permitted path +/// separators for the current platform. +pub fn is_separator(c: char) -> bool { + use ascii::*; + c.is_ascii() && is_sep_byte(c as u8) } +/// The primary sperator for the current platform +pub const MAIN_SEPARATOR: char = platform::MAIN_SEP; + //////////////////////////////////////////////////////////////////////////////// // Misc helpers //////////////////////////////////////////////////////////////////////////////// @@ -403,7 +394,7 @@ fn has_suffix(s: &[u8], prefix: Option) -> bool { (p.len(), p.is_verbatim()) } else { (0, false) }; if prefix_len > 0 && prefix_len == s.len() && !verbatim { return true; } - let mut splits = s[prefix_len..].split(|b| is_sep(*b)); + let mut splits = s[prefix_len..].split(|b| is_sep_byte(*b)); let last = splits.next_back().unwrap(); let more = splits.next_back().is_some(); more && last == b"" @@ -412,7 +403,7 @@ fn has_suffix(s: &[u8], prefix: Option) -> bool { /// Says whether the first byte after the prefix is a separator. fn has_physical_root(s: &[u8], prefix: Option) -> bool { let path = if let Some(p) = prefix { &s[p.len()..] } else { s }; - path.len() > 0 && is_sep(path[0]) + path.len() > 0 && is_sep_byte(path[0]) } fn parse_single_component(comp: &[u8]) -> Option { @@ -473,8 +464,16 @@ enum State { /// their role in the API. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Component<'a> { - /// A Windows path prefix, e.g. `C:` or `\server\share` - Prefix(&'a OsStr), + /// A Windows path prefix, e.g. `C:` or `\server\share`. + /// + /// Does not occur on Unix. + Prefix { + /// The prefix as an unparsed `OsStr` slice. + raw: &'a OsStr, + + /// The parsed prefix data. + parsed: Prefix<'a> + }, /// An empty component. Only used on Windows for the last component of /// verbatim paths ending with a separator (e.g. the last component of @@ -498,7 +497,7 @@ impl<'a> Component<'a> { /// Extract the underlying `OsStr` slice pub fn as_os_str(self) -> &'a OsStr { match self { - Component::Prefix(path) => path, + Component::Prefix { raw, .. } => &raw, Component::Empty => OsStr::from_str(""), Component::RootDir => OsStr::from_str(MAIN_SEP_STR), Component::CurDir => OsStr::from_str("."), @@ -568,11 +567,11 @@ impl<'a> Components<'a> { } #[inline] - fn is_sep(&self, b: u8) -> bool { + fn is_sep_byte(&self, b: u8) -> bool { if self.prefix_verbatim() { is_verbatim_sep(b) } else { - is_sep(b) + is_sep_byte(b) } } @@ -601,7 +600,7 @@ impl<'a> Components<'a> { // remove the component fn parse_next_component(&self) -> (usize, Option>) { debug_assert!(self.front == State::Body); - let (extra, comp) = match self.path.iter().position(|b| self.is_sep(*b)) { + let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) { None => (0, self.path), Some(i) => (1, &self.path[.. i]), }; @@ -613,7 +612,7 @@ impl<'a> Components<'a> { fn parse_next_component_back(&self) -> (usize, Option>) { debug_assert!(self.back == State::Body); let start = self.prefix_and_root(); - let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep(*b)) { + let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep_byte(*b)) { None => (0, &self.path[start ..]), Some(i) => (1, &self.path[start + i + 1 ..]), }; @@ -680,9 +679,12 @@ impl<'a> Iterator for Components<'a> { State::Prefix if self.prefix_len() > 0 => { self.front = State::Root; debug_assert!(self.prefix_len() <= self.path.len()); - let prefix = &self.path[.. self.prefix_len()]; + let raw = &self.path[.. self.prefix_len()]; self.path = &self.path[self.prefix_len() .. ]; - return Some(Component::Prefix(unsafe { u8_slice_as_os_str(prefix) })) + return Some(Component::Prefix { + raw: unsafe { u8_slice_as_os_str(raw) }, + parsed: self.prefix.unwrap() + }) } State::Prefix => { self.front = State::Root; @@ -755,9 +757,10 @@ impl<'a> DoubleEndedIterator for Components<'a> { } State::Prefix if self.prefix_len() > 0 => { self.back = State::Done; - return Some(Component::Prefix(unsafe { - u8_slice_as_os_str(self.path) - })) + return Some(Component::Prefix { + raw: unsafe { u8_slice_as_os_str(self.path) }, + parsed: self.prefix.unwrap() + }) } State::Prefix => { self.back = State::Done; @@ -844,7 +847,7 @@ impl PathBuf { /// * if `path` has a prefix but no root, it replaces `self. pub fn push(&mut self, path: &P) where P: AsPath { // in general, a separator is needed if the rightmost byte is not a separator - let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep(*c)).unwrap_or(false); + let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); // in the special case of `C:` on Windows, do *not* add a separator { @@ -1142,11 +1145,11 @@ impl Path { match (comp, comps.next_back()) { (Some(Component::CurDir), Some(Component::RootDir)) => None, - (Some(Component::CurDir), Some(Component::Prefix(_))) => None, + (Some(Component::CurDir), Some(Component::Prefix { .. })) => None, (Some(Component::Empty), Some(Component::RootDir)) => None, - (Some(Component::Empty), Some(Component::Prefix(_))) => None, - (Some(Component::Prefix(_)), None) => None, - (Some(Component::RootDir), Some(Component::Prefix(_))) => None, + (Some(Component::Empty), Some(Component::Prefix { .. })) => None, + (Some(Component::Prefix { .. }), None) => None, + (Some(Component::RootDir), Some(Component::Prefix { .. })) => None, _ => rest } } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d2b98ec89390b..5baa095d35985 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -27,7 +27,7 @@ use sys::process2::Process as ProcessImp; use sys::process2::Command as CommandImp; use sys::process2::ExitStatus as ExitStatusImp; use sys_common::{AsInner, AsInnerMut}; -use thread::Thread; +use thread; /// Representation of a running or exited child process. /// @@ -458,11 +458,11 @@ impl Child { /// the parent waits for the child to exit. pub fn wait_with_output(mut self) -> io::Result { drop(self.stdin.take()); - fn read(stream: Option) -> Receiver>> { + fn read(stream: Option) -> Receiver>> { let (tx, rx) = channel(); match stream { Some(stream) => { - Thread::spawn(move || { + thread::spawn(move || { let mut stream = stream; let mut ret = Vec::new(); let res = stream.read_to_end(&mut ret); @@ -499,7 +499,7 @@ mod tests { use str; use super::{Child, Command, Output, ExitStatus, Stdio}; use sync::mpsc::channel; - use thread::Thread; + use thread; use time::Duration; // FIXME(#10380) these tests should not all be ignored on android. @@ -537,12 +537,12 @@ mod tests { fn signal_reported_right() { use os::unix::ExitStatusExt; - let p = Command::new("/bin/sh").arg("-c").arg("kill -1 $$").spawn(); + let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn(); assert!(p.is_ok()); let mut p = p.unwrap(); match p.wait().unwrap().signal() { - Some(1) => {}, - result => panic!("not terminated by signal 1 (instead, {:?})", result), + Some(9) => {}, + result => panic!("not terminated by signal 9 (instead, {:?})", result), } } diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 535af08c96c70..0feacf5581c97 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -360,7 +360,7 @@ mod test { use sync::mpsc::channel; use rand::Rng; use super::OsRng; - use thread::Thread; + use thread; #[test] fn test_os_rng() { @@ -381,23 +381,23 @@ mod test { let (tx, rx) = channel(); txs.push(tx); - Thread::spawn(move|| { + thread::spawn(move|| { // wait until all the tasks are ready to go. rx.recv().unwrap(); // deschedule to attempt to interleave things as much // as possible (XXX: is this a good test?) let mut r = OsRng::new().unwrap(); - Thread::yield_now(); + thread::yield_now(); let mut v = [0u8; 1000]; for _ in 0u..100 { r.next_u32(); - Thread::yield_now(); + thread::yield_now(); r.next_u64(); - Thread::yield_now(); + thread::yield_now(); r.fill_bytes(&mut v); - Thread::yield_now(); + thread::yield_now(); } }); } diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs index 3f15cf71ec3f7..72486fc55d48e 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -20,7 +20,7 @@ use mem; use thunk::Thunk; use sys_common::mutex::{Mutex, MUTEX_INIT}; -type Queue = Vec; +type Queue = Vec>; // NB these are specifically not types from `std::sync` as they currently rely // on poisoning and this module needs to operate at a lower level than requiring @@ -65,7 +65,7 @@ pub fn cleanup() { } } -pub fn push(f: Thunk) { +pub fn push(f: Thunk<'static>) { unsafe { LOCK.lock(); init(); diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 00088d6d99a0a..42cca73e5e241 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -148,7 +148,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { /// /// It is forbidden for procedures to register more `at_exit` handlers when they /// are running, and doing so will lead to a process abort. -pub fn at_exit(f: F) { +pub fn at_exit(f: F) { at_exit_imp::push(Thunk::new(f)); } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index c9bbea27e4ad6..1f5eb3af695be 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -74,7 +74,7 @@ use rt::libunwind as uw; struct Exception { uwe: uw::_Unwind_Exception, - cause: Option>, + cause: Option>, } pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: uint); @@ -161,7 +161,7 @@ pub fn panicking() -> bool { #[inline(never)] #[no_mangle] #[allow(private_no_mangle_fns)] -fn rust_panic(cause: Box) -> ! { +fn rust_panic(cause: Box) -> ! { rtdebug!("begin_unwind()"); unsafe { diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index d445c29902801..a304f1f844d74 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -149,7 +149,7 @@ pub fn abort(args: fmt::Arguments) -> ! { } pub unsafe fn report_overflow() { - use thread::Thread; + use thread; // See the message below for why this is not emitted to the // ^ Where did the message below go? @@ -159,5 +159,5 @@ pub unsafe fn report_overflow() { // and the FFI call needs 2MB of stack when we just ran out. rterrln!("\nthread '{}' has overflowed its stack", - Thread::current().name().unwrap_or("")); + thread::current().name().unwrap_or("")); } diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index cca376f7b6d05..fc781eb4bece4 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -15,14 +15,14 @@ use sync::{Mutex, Condvar}; /// /// ```rust /// use std::sync::{Arc, Barrier}; -/// use std::thread::Thread; +/// use std::thread; /// /// let barrier = Arc::new(Barrier::new(10)); /// for _ in 0u..10 { /// let c = barrier.clone(); /// // The same messages will be printed together. /// // You will NOT see any interleaving. -/// Thread::spawn(move|| { +/// thread::spawn(move|| { /// println!("before wait"); /// c.wait(); /// println!("after wait"); @@ -111,7 +111,7 @@ mod tests { use sync::{Arc, Barrier}; use sync::mpsc::{channel, TryRecvError}; - use thread::Thread; + use thread; #[test] fn test_barrier() { @@ -123,7 +123,7 @@ mod tests { for _ in 0u..N - 1 { let c = barrier.clone(); let tx = tx.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(c.wait().is_leader()).unwrap(); }); } diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index d4d722cab3d92..52561d482c39d 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -38,13 +38,13 @@ use sync::{mutex, MutexGuard, PoisonError}; /// /// ``` /// use std::sync::{Arc, Mutex, Condvar}; -/// use std::thread::Thread; +/// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = pair.clone(); /// /// // Inside of our lock, spawn a new thread, and then wait for it to start -/// Thread::spawn(move|| { +/// thread::spawn(move|| { /// let &(ref lock, ref cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; @@ -353,7 +353,7 @@ mod tests { use sync::mpsc::channel; use sync::{StaticMutex, MUTEX_INIT, Condvar, Mutex, Arc}; use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - use thread::Thread; + use thread; use time::Duration; #[test] @@ -377,7 +377,7 @@ mod tests { static M: StaticMutex = MUTEX_INIT; let g = M.lock().unwrap(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _g = M.lock().unwrap(); C.notify_one(); }); @@ -395,7 +395,7 @@ mod tests { for _ in 0..N { let data = data.clone(); let tx = tx.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { let &(ref lock, ref cond) = &*data; let mut cnt = lock.lock().unwrap(); *cnt += 1; @@ -431,7 +431,7 @@ mod tests { let (g, _no_timeout) = C.wait_timeout(g, Duration::nanoseconds(1000)).unwrap(); // spurious wakeups mean this isn't necessarily true // assert!(!no_timeout); - let _t = Thread::spawn(move || { + let _t = thread::spawn(move || { let _g = M.lock().unwrap(); C.notify_one(); }); @@ -452,7 +452,7 @@ mod tests { assert!(!success); let (tx, rx) = channel(); - let _t = Thread::scoped(move || { + let _t = thread::spawn(move || { rx.recv().unwrap(); let g = M.lock().unwrap(); S.store(1, Ordering::SeqCst); @@ -492,7 +492,7 @@ mod tests { static C: StaticCondvar = CONDVAR_INIT; let mut g = M1.lock().unwrap(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _g = M1.lock().unwrap(); C.notify_one(); }); diff --git a/src/libstd/sync/future.rs b/src/libstd/sync/future.rs index a230e35dac8c3..d60e273880864 100644 --- a/src/libstd/sync/future.rs +++ b/src/libstd/sync/future.rs @@ -38,7 +38,7 @@ use core::mem::replace; use self::FutureState::*; use sync::mpsc::{Receiver, channel}; use thunk::{Thunk}; -use thread::Thread; +use thread; /// A type encapsulating the result of a computation which may not be complete pub struct Future { @@ -46,7 +46,7 @@ pub struct Future { } enum FutureState { - Pending(Thunk<(),A>), + Pending(Thunk<'static,(),A>), Evaluating, Forced(A) } @@ -103,7 +103,7 @@ impl Future { } pub fn from_fn(f: F) -> Future - where F : FnOnce() -> A, F : Send + where F : FnOnce() -> A, F : Send + 'static { /*! * Create a future from a function. @@ -117,7 +117,7 @@ impl Future { } } -impl Future { +impl Future { pub fn from_receiver(rx: Receiver) -> Future { /*! * Create a future from a port @@ -132,7 +132,7 @@ impl Future { } pub fn spawn(blk: F) -> Future - where F : FnOnce() -> A, F : Send + where F : FnOnce() -> A, F : Send + 'static { /*! * Create a future from a unique closure. @@ -143,7 +143,7 @@ impl Future { let (tx, rx) = channel(); - Thread::spawn(move || { + thread::spawn(move || { // Don't panic if the other end has hung up let _ = tx.send(blk()); }); @@ -157,7 +157,7 @@ mod test { use prelude::v1::*; use sync::mpsc::channel; use sync::Future; - use thread::Thread; + use thread; #[test] fn test_from_value() { @@ -215,7 +215,7 @@ mod test { let expected = "schlorf"; let (tx, rx) = channel(); let f = Future::spawn(move|| { expected }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut f = f; tx.send(f.get()).unwrap(); }); diff --git a/src/libstd/sync/mpsc/blocking.rs b/src/libstd/sync/mpsc/blocking.rs index 61ffb532d36ad..69b1e242b154d 100644 --- a/src/libstd/sync/mpsc/blocking.rs +++ b/src/libstd/sync/mpsc/blocking.rs @@ -10,7 +10,7 @@ //! Generic support for building blocking abstractions. -use thread::Thread; +use thread::{self, Thread}; use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; use sync::Arc; use marker::{Sync, Send}; @@ -40,7 +40,7 @@ impl !Sync for WaitToken {} pub fn tokens() -> (WaitToken, SignalToken) { let inner = Arc::new(Inner { - thread: Thread::current(), + thread: thread::current(), woken: ATOMIC_BOOL_INIT, }); let wait_token = WaitToken { @@ -80,7 +80,7 @@ impl SignalToken { impl WaitToken { pub fn wait(self) { while !self.inner.woken.load(Ordering::SeqCst) { - Thread::park() + thread::park() } } } diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index d783acd57ac04..410d3c0ecd5e4 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -53,12 +53,12 @@ //! Simple usage: //! //! ``` -//! use std::thread::Thread; +//! use std::thread; //! use std::sync::mpsc::channel; //! //! // Create a simple streaming channel //! let (tx, rx) = channel(); -//! Thread::spawn(move|| { +//! thread::spawn(move|| { //! tx.send(10).unwrap(); //! }); //! assert_eq!(rx.recv().unwrap(), 10); @@ -67,7 +67,7 @@ //! Shared usage: //! //! ``` -//! use std::thread::Thread; +//! use std::thread; //! use std::sync::mpsc::channel; //! //! // Create a shared channel that can be sent along from many threads @@ -76,7 +76,7 @@ //! let (tx, rx) = channel(); //! for i in 0..10 { //! let tx = tx.clone(); -//! Thread::spawn(move|| { +//! thread::spawn(move|| { //! tx.send(i).unwrap(); //! }); //! } @@ -102,11 +102,11 @@ //! Synchronous channels: //! //! ``` -//! use std::thread::Thread; +//! use std::thread; //! use std::sync::mpsc::sync_channel; //! //! let (tx, rx) = sync_channel::(0); -//! Thread::spawn(move|| { +//! thread::spawn(move|| { //! // This will wait for the parent task to start receiving //! tx.send(53).unwrap(); //! }); @@ -345,7 +345,7 @@ pub struct Receiver { // The receiver port can be sent from place to place, so long as it // is not used to receive non-sendable things. -unsafe impl Send for Receiver { } +unsafe impl Send for Receiver { } /// An iterator over messages on a receiver, this iterator will block /// whenever `next` is called, waiting for a new message, and `None` will be @@ -364,7 +364,7 @@ pub struct Sender { // The send port can be sent from place to place, so long as it // is not used to send non-sendable things. -unsafe impl Send for Sender { } +unsafe impl Send for Sender { } /// The sending-half of Rust's synchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. @@ -373,7 +373,7 @@ pub struct SyncSender { inner: Arc>>, } -unsafe impl Send for SyncSender {} +unsafe impl Send for SyncSender {} impl !Sync for SyncSender {} @@ -467,14 +467,14 @@ impl UnsafeFlavor for Receiver { /// /// ``` /// use std::sync::mpsc::channel; -/// use std::thread::Thread; +/// use std::thread; /// /// // tx is is the sending half (tx for transmission), and rx is the receiving /// // half (rx for receiving). /// let (tx, rx) = channel(); /// /// // Spawn off an expensive computation -/// Thread::spawn(move|| { +/// thread::spawn(move|| { /// # fn expensive_computation() {} /// tx.send(expensive_computation()).unwrap(); /// }); @@ -485,7 +485,7 @@ impl UnsafeFlavor for Receiver { /// println!("{:?}", rx.recv().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub fn channel() -> (Sender, Receiver) { +pub fn channel() -> (Sender, Receiver) { let a = Arc::new(UnsafeCell::new(oneshot::Packet::new())); (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a))) } @@ -509,14 +509,14 @@ pub fn channel() -> (Sender, Receiver) { /// /// ``` /// use std::sync::mpsc::sync_channel; -/// use std::thread::Thread; +/// use std::thread; /// /// let (tx, rx) = sync_channel(1); /// /// // this returns immediately /// tx.send(1).unwrap(); /// -/// Thread::spawn(move|| { +/// thread::spawn(move|| { /// // this will block until the previous message has been received /// tx.send(2).unwrap(); /// }); @@ -525,7 +525,7 @@ pub fn channel() -> (Sender, Receiver) { /// assert_eq!(rx.recv().unwrap(), 2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub fn sync_channel(bound: uint) -> (SyncSender, Receiver) { +pub fn sync_channel(bound: uint) -> (SyncSender, Receiver) { let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound))); (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a))) } @@ -534,7 +534,7 @@ pub fn sync_channel(bound: uint) -> (SyncSender, Receiver) { // Sender //////////////////////////////////////////////////////////////////////////////// -impl Sender { +impl Sender { fn new(inner: Flavor) -> Sender { Sender { inner: UnsafeCell::new(inner), @@ -616,7 +616,7 @@ impl Sender { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Sender { +impl Clone for Sender { fn clone(&self) -> Sender { let (packet, sleeper, guard) = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { @@ -662,7 +662,7 @@ impl Clone for Sender { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Sender { +impl Drop for Sender { fn drop(&mut self) { match *unsafe { self.inner_mut() } { Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); }, @@ -677,7 +677,7 @@ impl Drop for Sender { // SyncSender //////////////////////////////////////////////////////////////////////////////// -impl SyncSender { +impl SyncSender { fn new(inner: Arc>>) -> SyncSender { SyncSender { inner: inner } } @@ -717,7 +717,7 @@ impl SyncSender { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for SyncSender { +impl Clone for SyncSender { fn clone(&self) -> SyncSender { unsafe { (*self.inner.get()).clone_chan(); } return SyncSender::new(self.inner.clone()); @@ -726,7 +726,7 @@ impl Clone for SyncSender { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for SyncSender { +impl Drop for SyncSender { fn drop(&mut self) { unsafe { (*self.inner.get()).drop_chan(); } } @@ -736,7 +736,7 @@ impl Drop for SyncSender { // Receiver //////////////////////////////////////////////////////////////////////////////// -impl Receiver { +impl Receiver { fn new(inner: Flavor) -> Receiver { Receiver { inner: UnsafeCell::new(inner) } } @@ -855,7 +855,7 @@ impl Receiver { } } -impl select::Packet for Receiver { +impl select::Packet for Receiver { fn can_recv(&self) -> bool { loop { let new_port = match *unsafe { self.inner() } { @@ -942,7 +942,7 @@ impl select::Packet for Receiver { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Send> Iterator for Iter<'a, T> { +impl<'a, T: Send + 'static> Iterator for Iter<'a, T> { type Item = T; fn next(&mut self) -> Option { self.rx.recv().ok() } @@ -950,7 +950,7 @@ impl<'a, T: Send> Iterator for Iter<'a, T> { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Receiver { +impl Drop for Receiver { fn drop(&mut self) { match *unsafe { self.inner_mut() } { Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); }, @@ -1026,7 +1026,7 @@ mod test { use std::env; use super::*; - use thread::Thread; + use thread; pub fn stress_factor() -> uint { match env::var("RUST_TEST_STRESS") { @@ -1069,7 +1069,7 @@ mod test { #[test] fn smoke_threads() { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { tx.send(1).unwrap(); }); assert_eq!(rx.recv().unwrap(), 1); @@ -1101,7 +1101,7 @@ mod test { #[test] fn port_gone_concurrent() { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx.recv().unwrap(); }); while tx.send(1).is_ok() {} @@ -1111,7 +1111,7 @@ mod test { fn port_gone_concurrent_shared() { let (tx, rx) = channel::(); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx.recv().unwrap(); }); while tx.send(1).is_ok() && tx2.send(1).is_ok() {} @@ -1136,7 +1136,7 @@ mod test { #[test] fn chan_gone_concurrent() { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { tx.send(1).unwrap(); tx.send(1).unwrap(); }); @@ -1146,7 +1146,7 @@ mod test { #[test] fn stress() { let (tx, rx) = channel::(); - let t = Thread::scoped(move|| { + let t = thread::spawn(move|| { for _ in 0u..10000 { tx.send(1).unwrap(); } }); for _ in 0u..10000 { @@ -1161,7 +1161,7 @@ mod test { static NTHREADS: uint = 8; let (tx, rx) = channel::(); - let t = Thread::scoped(move|| { + let t = thread::spawn(move|| { for _ in 0..AMT * NTHREADS { assert_eq!(rx.recv().unwrap(), 1); } @@ -1173,7 +1173,7 @@ mod test { for _ in 0..NTHREADS { let tx = tx.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { for _ in 0..AMT { tx.send(1).unwrap(); } }); } @@ -1185,14 +1185,14 @@ mod test { fn send_from_outside_runtime() { let (tx1, rx1) = channel::<()>(); let (tx2, rx2) = channel::(); - let t1 = Thread::scoped(move|| { + let t1 = thread::spawn(move|| { tx1.send(()).unwrap(); for _ in 0..40 { assert_eq!(rx2.recv().unwrap(), 1); } }); rx1.recv().unwrap(); - let t2 = Thread::scoped(move|| { + let t2 = thread::spawn(move|| { for _ in 0..40 { tx2.send(1).unwrap(); } @@ -1204,7 +1204,7 @@ mod test { #[test] fn recv_from_outside_runtime() { let (tx, rx) = channel::(); - let t = Thread::scoped(move|| { + let t = thread::spawn(move|| { for _ in 0..40 { assert_eq!(rx.recv().unwrap(), 1); } @@ -1219,11 +1219,11 @@ mod test { fn no_runtime() { let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::(); - let t1 = Thread::scoped(move|| { + let t1 = thread::spawn(move|| { assert_eq!(rx1.recv().unwrap(), 1); tx2.send(2).unwrap(); }); - let t2 = Thread::scoped(move|| { + let t2 = thread::spawn(move|| { tx1.send(1).unwrap(); assert_eq!(rx2.recv().unwrap(), 2); }); @@ -1256,7 +1256,7 @@ mod test { #[test] fn oneshot_single_thread_recv_chan_close() { // Receiving on a closed chan will panic - let res = Thread::scoped(move|| { + let res = thread::spawn(move|| { let (tx, rx) = channel::(); drop(tx); rx.recv().unwrap(); @@ -1325,7 +1325,7 @@ mod test { #[test] fn oneshot_multi_task_recv_then_send() { let (tx, rx) = channel::>(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { assert!(rx.recv().unwrap() == box 10); }); @@ -1335,10 +1335,10 @@ mod test { #[test] fn oneshot_multi_task_recv_then_close() { let (tx, rx) = channel::>(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(tx); }); - let res = Thread::scoped(move|| { + let res = thread::spawn(move|| { assert!(rx.recv().unwrap() == box 10); }).join(); assert!(res.is_err()); @@ -1348,7 +1348,7 @@ mod test { fn oneshot_multi_thread_close_stress() { for _ in 0..stress_factor() { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(rx); }); drop(tx); @@ -1359,10 +1359,10 @@ mod test { fn oneshot_multi_thread_send_close_stress() { for _ in 0..stress_factor() { let (tx, rx) = channel::(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(rx); }); - let _ = Thread::scoped(move|| { + let _ = thread::spawn(move|| { tx.send(1).unwrap(); }).join(); } @@ -1372,14 +1372,14 @@ mod test { fn oneshot_multi_thread_recv_close_stress() { for _ in 0..stress_factor() { let (tx, rx) = channel::(); - Thread::spawn(move|| { - let res = Thread::scoped(move|| { + thread::spawn(move|| { + let res = thread::spawn(move|| { rx.recv().unwrap(); }).join(); assert!(res.is_err()); }); - let _t = Thread::spawn(move|| { - Thread::spawn(move|| { + let _t = thread::spawn(move|| { + thread::spawn(move|| { drop(tx); }); }); @@ -1390,7 +1390,7 @@ mod test { fn oneshot_multi_thread_send_recv_stress() { for _ in 0..stress_factor() { let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { tx.send(box 10).unwrap(); }); assert!(rx.recv().unwrap() == box 10); @@ -1408,7 +1408,7 @@ mod test { fn send(tx: Sender>, i: int) { if i == 10 { return } - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(box i).unwrap(); send(tx, i + 1); }); @@ -1417,7 +1417,7 @@ mod test { fn recv(rx: Receiver>, i: int) { if i == 10 { return } - Thread::spawn(move|| { + thread::spawn(move|| { assert!(rx.recv().unwrap() == box i); recv(rx, i + 1); }); @@ -1439,7 +1439,7 @@ mod test { let total = stress_factor() + 100; for _ in 0..total { let tx = tx.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(()).unwrap(); }); } @@ -1454,7 +1454,7 @@ mod test { let (tx, rx) = channel::(); let (total_tx, total_rx) = channel::(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut acc = 0; for x in rx.iter() { acc += x; @@ -1474,7 +1474,7 @@ mod test { let (tx, rx) = channel::(); let (count_tx, count_rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut count = 0; for x in rx.iter() { if count >= 3 { @@ -1499,7 +1499,7 @@ mod test { let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::<()>(); let (tx3, rx3) = channel::<()>(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx2.recv().unwrap(); tx1.send(1).unwrap(); tx3.send(()).unwrap(); @@ -1524,13 +1524,13 @@ mod test { fn destroy_upgraded_shared_port_when_sender_still_active() { let (tx, rx) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx.recv().unwrap(); // wait on a oneshot drop(rx); // destroy a shared tx2.send(()).unwrap(); }); // make sure the other task has gone to sleep - for _ in 0u..5000 { Thread::yield_now(); } + for _ in 0u..5000 { thread::yield_now(); } // upgrade to a shared chan and send a message let t = tx.clone(); @@ -1547,7 +1547,7 @@ mod sync_tests { use prelude::v1::*; use std::env; - use thread::Thread; + use thread; use super::*; pub fn stress_factor() -> uint { @@ -1583,7 +1583,7 @@ mod sync_tests { #[test] fn smoke_threads() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { tx.send(1).unwrap(); }); assert_eq!(rx.recv().unwrap(), 1); @@ -1608,7 +1608,7 @@ mod sync_tests { #[test] fn port_gone_concurrent() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx.recv().unwrap(); }); while tx.send(1).is_ok() {} @@ -1618,7 +1618,7 @@ mod sync_tests { fn port_gone_concurrent_shared() { let (tx, rx) = sync_channel::(0); let tx2 = tx.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx.recv().unwrap(); }); while tx.send(1).is_ok() && tx2.send(1).is_ok() {} @@ -1643,7 +1643,7 @@ mod sync_tests { #[test] fn chan_gone_concurrent() { let (tx, rx) = sync_channel::(0); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(1).unwrap(); tx.send(1).unwrap(); }); @@ -1653,7 +1653,7 @@ mod sync_tests { #[test] fn stress() { let (tx, rx) = sync_channel::(0); - Thread::spawn(move|| { + thread::spawn(move|| { for _ in 0u..10000 { tx.send(1).unwrap(); } }); for _ in 0u..10000 { @@ -1668,7 +1668,7 @@ mod sync_tests { let (tx, rx) = sync_channel::(0); let (dtx, drx) = sync_channel::<()>(0); - Thread::spawn(move|| { + thread::spawn(move|| { for _ in 0..AMT * NTHREADS { assert_eq!(rx.recv().unwrap(), 1); } @@ -1681,7 +1681,7 @@ mod sync_tests { for _ in 0..NTHREADS { let tx = tx.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { for _ in 0..AMT { tx.send(1).unwrap(); } }); } @@ -1714,7 +1714,7 @@ mod sync_tests { #[test] fn oneshot_single_thread_recv_chan_close() { // Receiving on a closed chan will panic - let res = Thread::scoped(move|| { + let res = thread::spawn(move|| { let (tx, rx) = sync_channel::(0); drop(tx); rx.recv().unwrap(); @@ -1789,7 +1789,7 @@ mod sync_tests { #[test] fn oneshot_multi_task_recv_then_send() { let (tx, rx) = sync_channel::>(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { assert!(rx.recv().unwrap() == box 10); }); @@ -1799,10 +1799,10 @@ mod sync_tests { #[test] fn oneshot_multi_task_recv_then_close() { let (tx, rx) = sync_channel::>(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(tx); }); - let res = Thread::scoped(move|| { + let res = thread::spawn(move|| { assert!(rx.recv().unwrap() == box 10); }).join(); assert!(res.is_err()); @@ -1812,7 +1812,7 @@ mod sync_tests { fn oneshot_multi_thread_close_stress() { for _ in 0..stress_factor() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(rx); }); drop(tx); @@ -1823,10 +1823,10 @@ mod sync_tests { fn oneshot_multi_thread_send_close_stress() { for _ in 0..stress_factor() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { drop(rx); }); - let _ = Thread::scoped(move || { + let _ = thread::spawn(move || { tx.send(1).unwrap(); }).join(); } @@ -1836,14 +1836,14 @@ mod sync_tests { fn oneshot_multi_thread_recv_close_stress() { for _ in 0..stress_factor() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { - let res = Thread::scoped(move|| { + let _t = thread::spawn(move|| { + let res = thread::spawn(move|| { rx.recv().unwrap(); }).join(); assert!(res.is_err()); }); - let _t = Thread::spawn(move|| { - Thread::spawn(move|| { + let _t = thread::spawn(move|| { + thread::spawn(move|| { drop(tx); }); }); @@ -1854,7 +1854,7 @@ mod sync_tests { fn oneshot_multi_thread_send_recv_stress() { for _ in 0..stress_factor() { let (tx, rx) = sync_channel::>(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { tx.send(box 10).unwrap(); }); assert!(rx.recv().unwrap() == box 10); @@ -1872,7 +1872,7 @@ mod sync_tests { fn send(tx: SyncSender>, i: int) { if i == 10 { return } - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(box i).unwrap(); send(tx, i + 1); }); @@ -1881,7 +1881,7 @@ mod sync_tests { fn recv(rx: Receiver>, i: int) { if i == 10 { return } - Thread::spawn(move|| { + thread::spawn(move|| { assert!(rx.recv().unwrap() == box i); recv(rx, i + 1); }); @@ -1903,7 +1903,7 @@ mod sync_tests { let total = stress_factor() + 100; for _ in 0..total { let tx = tx.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(()).unwrap(); }); } @@ -1918,7 +1918,7 @@ mod sync_tests { let (tx, rx) = sync_channel::(0); let (total_tx, total_rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut acc = 0; for x in rx.iter() { acc += x; @@ -1938,7 +1938,7 @@ mod sync_tests { let (tx, rx) = sync_channel::(0); let (count_tx, count_rx) = sync_channel(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let mut count = 0; for x in rx.iter() { if count >= 3 { @@ -1963,7 +1963,7 @@ mod sync_tests { let (tx1, rx1) = sync_channel::(1); let (tx2, rx2) = sync_channel::<()>(1); let (tx3, rx3) = sync_channel::<()>(1); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx2.recv().unwrap(); tx1.send(1).unwrap(); tx3.send(()).unwrap(); @@ -1988,13 +1988,13 @@ mod sync_tests { fn destroy_upgraded_shared_port_when_sender_still_active() { let (tx, rx) = sync_channel::<()>(0); let (tx2, rx2) = sync_channel::<()>(0); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx.recv().unwrap(); // wait on a oneshot drop(rx); // destroy a shared tx2.send(()).unwrap(); }); // make sure the other task has gone to sleep - for _ in 0u..5000 { Thread::yield_now(); } + for _ in 0u..5000 { thread::yield_now(); } // upgrade to a shared chan and send a message let t = tx.clone(); @@ -2008,14 +2008,14 @@ mod sync_tests { #[test] fn send1() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { rx.recv().unwrap(); }); + let _t = thread::spawn(move|| { rx.recv().unwrap(); }); assert_eq!(tx.send(1), Ok(())); } #[test] fn send2() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { drop(rx); }); + let _t = thread::spawn(move|| { drop(rx); }); assert!(tx.send(1).is_err()); } @@ -2023,7 +2023,7 @@ mod sync_tests { fn send3() { let (tx, rx) = sync_channel::(1); assert_eq!(tx.send(1), Ok(())); - let _t =Thread::spawn(move|| { drop(rx); }); + let _t =thread::spawn(move|| { drop(rx); }); assert!(tx.send(1).is_err()); } @@ -2033,11 +2033,11 @@ mod sync_tests { let tx2 = tx.clone(); let (done, donerx) = channel(); let done2 = done.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { assert!(tx.send(1).is_err()); done.send(()).unwrap(); }); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { assert!(tx2.send(2).is_err()); done2.send(()).unwrap(); }); @@ -2073,7 +2073,7 @@ mod sync_tests { let (tx1, rx1) = sync_channel::<()>(3); let (tx2, rx2) = sync_channel::<()>(3); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx1.recv().unwrap(); tx2.try_send(()).unwrap(); }); diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 3980d2a1fefb5..0a4ff8769abf4 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -78,7 +78,7 @@ pub struct Queue { } unsafe impl Send for Queue { } -unsafe impl Sync for Queue { } +unsafe impl Sync for Queue { } impl Node { unsafe fn new(v: Option) -> *mut Node { @@ -89,7 +89,7 @@ impl Node { } } -impl Queue { +impl Queue { /// Creates a new queue that is safe to share among multiple producers and /// one consumer. pub fn new() -> Queue { @@ -140,7 +140,7 @@ impl Queue { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Queue { +impl Drop for Queue { fn drop(&mut self) { unsafe { let mut cur = *self.tail.get(); @@ -160,7 +160,7 @@ mod tests { use sync::mpsc::channel; use super::{Queue, Data, Empty, Inconsistent}; use sync::Arc; - use thread::Thread; + use thread; #[test] fn test_full() { @@ -184,7 +184,7 @@ mod tests { for _ in 0..nthreads { let tx = tx.clone(); let q = q.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { for i in 0..nmsgs { q.push(i); } diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index eb45681fa626d..55b2caf7c6d4c 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -88,7 +88,7 @@ enum MyUpgrade { GoUp(Receiver), } -impl Packet { +impl Packet { pub fn new() -> Packet { Packet { data: None, @@ -368,7 +368,7 @@ impl Packet { } #[unsafe_destructor] -impl Drop for Packet { +impl Drop for Packet { fn drop(&mut self) { assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED); } diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index 87b2fe8f100c3..4756ef612f947 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -134,7 +134,7 @@ impl Select { /// Creates a new handle into this receiver set for a new receiver. Note /// that this does *not* add the receiver to the receiver set, for that you /// must call the `add` method on the handle itself. - pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver) -> Handle<'a, T> { + pub fn handle<'a, T: Send + 'static>(&'a self, rx: &'a Receiver) -> Handle<'a, T> { let id = self.next_id.get(); self.next_id.set(id + 1); Handle { @@ -251,7 +251,7 @@ impl Select { fn iter(&self) -> Packets { Packets { cur: self.head } } } -impl<'rx, T: Send> Handle<'rx, T> { +impl<'rx, T: Send + 'static> Handle<'rx, T> { /// Retrieve the id of this handle. #[inline] pub fn id(&self) -> uint { self.id } @@ -322,7 +322,7 @@ impl Drop for Select { } #[unsafe_destructor] -impl<'rx, T: Send> Drop for Handle<'rx, T> { +impl<'rx, T: Send + 'static> Drop for Handle<'rx, T> { fn drop(&mut self) { unsafe { self.remove() } } @@ -347,7 +347,7 @@ impl Iterator for Packets { mod test { use prelude::v1::*; - use thread::Thread; + use thread; use sync::mpsc::*; // Don't use the libstd version so we can pull in the right Select structure @@ -427,11 +427,11 @@ mod test { let (_tx2, rx2) = channel::(); let (tx3, rx3) = channel::(); - let _t = Thread::spawn(move|| { - for _ in 0u..20 { Thread::yield_now(); } + let _t = thread::spawn(move|| { + for _ in 0u..20 { thread::yield_now(); } tx1.send(1).unwrap(); rx3.recv().unwrap(); - for _ in 0u..20 { Thread::yield_now(); } + for _ in 0u..20 { thread::yield_now(); } }); select! { @@ -451,8 +451,8 @@ mod test { let (tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); - let _t = Thread::spawn(move|| { - for _ in 0u..20 { Thread::yield_now(); } + let _t = thread::spawn(move|| { + for _ in 0u..20 { thread::yield_now(); } tx1.send(1).unwrap(); tx2.send(2).unwrap(); rx3.recv().unwrap(); @@ -478,7 +478,7 @@ mod test { let (tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { for i in 0..AMT { if i % 2 == 0 { tx1.send(i).unwrap(); @@ -504,7 +504,7 @@ mod test { let (_tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx3.recv().unwrap(); tx1.clone(); assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); @@ -526,7 +526,7 @@ mod test { let (_tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { rx3.recv().unwrap(); tx1.clone(); assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); @@ -547,7 +547,7 @@ mod test { let (tx1, rx1) = channel::<()>(); let (tx2, rx2) = channel::<()>(); let (tx3, rx3) = channel::<()>(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let s = Select::new(); let mut h1 = s.handle(&rx1); let mut h2 = s.handle(&rx2); @@ -557,7 +557,7 @@ mod test { tx3.send(()).unwrap(); }); - for _ in 0u..1000 { Thread::yield_now(); } + for _ in 0u..1000 { thread::yield_now(); } drop(tx1.clone()); tx2.send(()).unwrap(); rx3.recv().unwrap(); @@ -663,14 +663,14 @@ mod test { fn oneshot_data_waiting() { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { select! { _n = rx1.recv() => {} } tx2.send(()).unwrap(); }); - for _ in 0u..100 { Thread::yield_now() } + for _ in 0u..100 { thread::yield_now() } tx1.send(()).unwrap(); rx2.recv().unwrap(); } @@ -683,14 +683,14 @@ mod test { tx1.send(()).unwrap(); rx1.recv().unwrap(); rx1.recv().unwrap(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { select! { _n = rx1.recv() => {} } tx2.send(()).unwrap(); }); - for _ in 0u..100 { Thread::yield_now() } + for _ in 0u..100 { thread::yield_now() } tx1.send(()).unwrap(); rx2.recv().unwrap(); } @@ -702,14 +702,14 @@ mod test { drop(tx1.clone()); tx1.send(()).unwrap(); rx1.recv().unwrap(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { select! { _n = rx1.recv() => {} } tx2.send(()).unwrap(); }); - for _ in 0u..100 { Thread::yield_now() } + for _ in 0u..100 { thread::yield_now() } tx1.send(()).unwrap(); rx2.recv().unwrap(); } @@ -726,8 +726,8 @@ mod test { #[test] fn sync2() { let (tx, rx) = sync_channel::(0); - let _t = Thread::spawn(move|| { - for _ in 0u..100 { Thread::yield_now() } + let _t = thread::spawn(move|| { + for _ in 0u..100 { thread::yield_now() } tx.send(1).unwrap(); }); select! { @@ -739,8 +739,8 @@ mod test { fn sync3() { let (tx1, rx1) = sync_channel::(0); let (tx2, rx2): (Sender, Receiver) = channel(); - let _t = Thread::spawn(move|| { tx1.send(1).unwrap(); }); - let _t = Thread::spawn(move|| { tx2.send(2).unwrap(); }); + let _t = thread::spawn(move|| { tx1.send(1).unwrap(); }); + let _t = thread::spawn(move|| { tx2.send(2).unwrap(); }); select! { n = rx1.recv() => { let n = n.unwrap(); diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index 6c31fb925911e..bc9c73585c21f 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -31,7 +31,7 @@ use sync::mpsc::mpsc_queue as mpsc; use sync::mpsc::select::StartResult::*; use sync::mpsc::select::StartResult; use sync::{Mutex, MutexGuard}; -use thread::Thread; +use thread; const DISCONNECTED: isize = isize::MIN; const FUDGE: isize = 1024; @@ -64,7 +64,7 @@ pub enum Failure { Disconnected, } -impl Packet { +impl Packet { // Creation of a packet *must* be followed by a call to postinit_lock // and later by inherit_blocker pub fn new() -> Packet { @@ -194,7 +194,7 @@ impl Packet { match self.queue.pop() { mpsc::Data(..) => {} mpsc::Empty => break, - mpsc::Inconsistent => Thread::yield_now(), + mpsc::Inconsistent => thread::yield_now(), } } // maybe we're done, if we're not the last ones @@ -283,7 +283,7 @@ impl Packet { mpsc::Inconsistent => { let data; loop { - Thread::yield_now(); + thread::yield_now(); match self.queue.pop() { mpsc::Data(t) => { data = t; break } mpsc::Empty => panic!("inconsistent => empty"), @@ -460,7 +460,7 @@ impl Packet { drop(self.take_to_wake()); } else { while self.to_wake.load(Ordering::SeqCst) != 0 { - Thread::yield_now(); + thread::yield_now(); } } // if the number of steals is -1, it was the pre-emptive -1 steal @@ -474,7 +474,7 @@ impl Packet { } #[unsafe_destructor] -impl Drop for Packet { +impl Drop for Packet { fn drop(&mut self) { // Note that this load is not only an assert for correctness about // disconnection, but also a proper fence before the read of diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index f0558c33d1ec8..b8f835bde5191 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -74,11 +74,11 @@ pub struct Queue { cache_subtractions: AtomicUsize, } -unsafe impl Send for Queue { } +unsafe impl Send for Queue { } -unsafe impl Sync for Queue { } +unsafe impl Sync for Queue { } -impl Node { +impl Node { fn new() -> *mut Node { unsafe { mem::transmute(box Node { @@ -89,7 +89,7 @@ impl Node { } } -impl Queue { +impl Queue { /// Creates a new queue. /// /// This is unsafe as the type system doesn't enforce a single @@ -227,7 +227,7 @@ impl Queue { } #[unsafe_destructor] -impl Drop for Queue { +impl Drop for Queue { fn drop(&mut self) { unsafe { let mut cur = *self.first.get(); @@ -246,7 +246,7 @@ mod test { use sync::Arc; use super::Queue; - use thread::Thread; + use thread; use sync::mpsc::channel; #[test] @@ -324,7 +324,7 @@ mod test { let (tx, rx) = channel(); let q2 = q.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { for _ in 0u..100000 { loop { match q2.pop() { diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index ab9bd6b2ed7f6..a194c99669263 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -26,7 +26,7 @@ use core::prelude::*; use core::cmp; use core::isize; -use thread::Thread; +use thread; use sync::atomic::{AtomicIsize, AtomicUsize, Ordering, AtomicBool}; use sync::mpsc::Receiver; @@ -74,7 +74,7 @@ enum Message { GoUp(Receiver), } -impl Packet { +impl Packet { pub fn new() -> Packet { Packet { queue: unsafe { spsc::Queue::new(128) }, @@ -440,7 +440,7 @@ impl Packet { drop(self.take_to_wake()); } else { while self.to_wake.load(Ordering::SeqCst) != 0 { - Thread::yield_now(); + thread::yield_now(); } } assert_eq!(self.steals, 0); @@ -472,7 +472,7 @@ impl Packet { } #[unsafe_destructor] -impl Drop for Packet { +impl Drop for Packet { fn drop(&mut self) { // Note that this load is not only an assert for correctness about // disconnection, but also a proper fence before the read of diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index da3ce51a652f7..ae96a2491dc26 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -55,9 +55,9 @@ pub struct Packet { lock: Mutex>, } -unsafe impl Send for Packet { } +unsafe impl Send for Packet { } -unsafe impl Sync for Packet { } +unsafe impl Sync for Packet { } struct State { disconnected: bool, // Is the channel disconnected yet? @@ -75,7 +75,7 @@ struct State { canceled: Option<&'static mut bool>, } -unsafe impl Send for State {} +unsafe impl Send for State {} /// Possible flavors of threads who can be blocked on this channel. enum Blocker { @@ -113,7 +113,7 @@ pub enum Failure { /// Atomically blocks the current thread, placing it into `slot`, unlocking `lock` /// in the meantime. This re-locks the mutex upon returning. -fn wait<'a, 'b, T: Send>(lock: &'a Mutex>, +fn wait<'a, 'b, T: Send + 'static>(lock: &'a Mutex>, mut guard: MutexGuard<'b, State>, f: fn(SignalToken) -> Blocker) -> MutexGuard<'a, State> @@ -136,7 +136,7 @@ fn wakeup(token: SignalToken, guard: MutexGuard>) { token.signal(); } -impl Packet { +impl Packet { pub fn new(cap: uint) -> Packet { Packet { channels: AtomicUsize::new(1), @@ -412,7 +412,7 @@ impl Packet { } #[unsafe_destructor] -impl Drop for Packet { +impl Drop for Packet { fn drop(&mut self) { assert_eq!(self.channels.load(Ordering::SeqCst), 0); let mut guard = self.lock.lock().unwrap(); diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 74692c1273c27..65cae90857e44 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -47,7 +47,7 @@ use sys_common::mutex as sys; /// /// ```rust /// use std::sync::{Arc, Mutex}; -/// use std::thread::Thread; +/// use std::thread; /// use std::sync::mpsc::channel; /// /// const N: uint = 10; @@ -62,7 +62,7 @@ use sys_common::mutex as sys; /// let (tx, rx) = channel(); /// for _ in 0u..10 { /// let (data, tx) = (data.clone(), tx.clone()); -/// Thread::spawn(move || { +/// thread::spawn(move || { /// // The shared static can only be accessed once the lock is held. /// // Our non-atomic increment is safe because we're the only thread /// // which can access the shared state when the lock is held. @@ -85,12 +85,12 @@ use sys_common::mutex as sys; /// /// ```rust /// use std::sync::{Arc, Mutex}; -/// use std::thread::Thread; +/// use std::thread; /// /// let lock = Arc::new(Mutex::new(0u)); /// let lock2 = lock.clone(); /// -/// let _ = Thread::scoped(move || -> () { +/// let _ = thread::spawn(move || -> () { /// // This thread will acquire the mutex first, unwrapping the result of /// // `lock` because the lock has not been poisoned. /// let _lock = lock2.lock().unwrap(); @@ -120,9 +120,9 @@ pub struct Mutex { data: UnsafeCell, } -unsafe impl Send for Mutex { } +unsafe impl Send for Mutex { } -unsafe impl Sync for Mutex { } +unsafe impl Sync for Mutex { } /// The static mutex type is provided to allow for static allocation of mutexes. /// @@ -180,7 +180,7 @@ pub const MUTEX_INIT: StaticMutex = StaticMutex { poison: poison::FLAG_INIT, }; -impl Mutex { +impl Mutex { /// Creates a new mutex in an unlocked state ready for use. #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> Mutex { @@ -243,7 +243,7 @@ impl Mutex { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Mutex { +impl Drop for Mutex { fn drop(&mut self) { // This is actually safe b/c we know that there is no further usage of // this mutex (it's up to the user to arrange for a mutex to get @@ -350,7 +350,7 @@ mod test { use sync::mpsc::channel; use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar}; - use thread::Thread; + use thread; struct Packet(Arc<(Mutex, Condvar)>); @@ -393,9 +393,9 @@ mod test { let (tx, rx) = channel(); for _ in 0..K { let tx2 = tx.clone(); - Thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); + thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); let tx2 = tx.clone(); - Thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); + thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); } drop(tx); @@ -419,7 +419,7 @@ mod test { let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); let packet2 = Packet(packet.0.clone()); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { // wait until parent gets in rx.recv().unwrap(); let &(ref lock, ref cvar) = &*packet2.0; @@ -443,7 +443,7 @@ mod test { let packet2 = Packet(packet.0.clone()); let (tx, rx) = channel(); - let _t = Thread::spawn(move || -> () { + let _t = thread::spawn(move || -> () { rx.recv().unwrap(); let &(ref lock, ref cvar) = &*packet2.0; let _g = lock.lock().unwrap(); @@ -471,7 +471,7 @@ mod test { let arc = Arc::new(Mutex::new(1)); assert!(!arc.is_poisoned()); let arc2 = arc.clone(); - let _ = Thread::scoped(move|| { + let _ = thread::spawn(move|| { let lock = arc2.lock().unwrap(); assert_eq!(*lock, 2); }).join(); @@ -486,7 +486,7 @@ mod test { let arc = Arc::new(Mutex::new(1)); let arc2 = Arc::new(Mutex::new(arc)); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let lock = arc2.lock().unwrap(); let lock2 = lock.lock().unwrap(); assert_eq!(*lock2, 1); @@ -499,7 +499,7 @@ mod test { fn test_mutex_arc_access_in_unwind() { let arc = Arc::new(Mutex::new(1)); let arc2 = arc.clone(); - let _ = Thread::scoped(move|| -> () { + let _ = thread::spawn(move|| -> () { struct Unwinder { i: Arc>, } diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 29c2051e5adc4..1e87c0d612bdc 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -127,7 +127,7 @@ impl Once { mod test { use prelude::v1::*; - use thread::Thread; + use thread; use super::{ONCE_INIT, Once}; use sync::mpsc::channel; @@ -149,8 +149,8 @@ mod test { let (tx, rx) = channel(); for _ in 0u..10 { let tx = tx.clone(); - Thread::spawn(move|| { - for _ in 0u..4 { Thread::yield_now() } + thread::spawn(move|| { + for _ in 0u..4 { thread::yield_now() } unsafe { O.call_once(|| { assert!(!run); diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs index a93bd31f5ae38..32c8150ba4070 100644 --- a/src/libstd/sync/poison.rs +++ b/src/libstd/sync/poison.rs @@ -13,7 +13,7 @@ use prelude::v1::*; use cell::UnsafeCell; use error::{Error, FromError}; use fmt; -use thread::Thread; +use thread; pub struct Flag { failed: UnsafeCell } pub const FLAG_INIT: Flag = Flag { failed: UnsafeCell { value: false } }; @@ -21,7 +21,7 @@ pub const FLAG_INIT: Flag = Flag { failed: UnsafeCell { value: false } }; impl Flag { #[inline] pub fn borrow(&self) -> LockResult { - let ret = Guard { panicking: Thread::panicking() }; + let ret = Guard { panicking: thread::panicking() }; if unsafe { *self.failed.get() } { Err(PoisonError::new(ret)) } else { @@ -31,7 +31,7 @@ impl Flag { #[inline] pub fn done(&self, guard: &Guard) { - if !guard.panicking && Thread::panicking() { + if !guard.panicking && thread::panicking() { unsafe { *self.failed.get() = true; } } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index c4f1f2ccadddd..b8d157d341e03 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -400,7 +400,7 @@ mod tests { use rand::{self, Rng}; use sync::mpsc::channel; - use thread::Thread; + use thread; use sync::{Arc, RwLock, StaticRwLock, RW_LOCK_INIT}; #[test] @@ -425,13 +425,13 @@ mod tests { #[test] fn frob() { static R: StaticRwLock = RW_LOCK_INIT; - static N: uint = 10; - static M: uint = 1000; + static N: usize = 10; + static M: usize = 1000; let (tx, rx) = channel::<()>(); for _ in 0..N { let tx = tx.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut rng = rand::thread_rng(); for _ in 0..M { if rng.gen_weighted_bool(N) { @@ -452,7 +452,7 @@ mod tests { fn test_rw_arc_poison_wr() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); - let _: Result = Thread::scoped(move|| { + let _: Result<(), _> = thread::spawn(move|| { let _lock = arc2.write().unwrap(); panic!(); }).join(); @@ -464,7 +464,7 @@ mod tests { let arc = Arc::new(RwLock::new(1)); assert!(!arc.is_poisoned()); let arc2 = arc.clone(); - let _: Result = Thread::scoped(move|| { + let _: Result<(), _> = thread::spawn(move|| { let _lock = arc2.write().unwrap(); panic!(); }).join(); @@ -476,7 +476,7 @@ mod tests { fn test_rw_arc_no_poison_rr() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); - let _: Result = Thread::scoped(move|| { + let _: Result<(), _> = thread::spawn(move|| { let _lock = arc2.read().unwrap(); panic!(); }).join(); @@ -487,7 +487,7 @@ mod tests { fn test_rw_arc_no_poison_rw() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); - let _: Result = Thread::scoped(move|| { + let _: Result<(), _> = thread::spawn(move|| { let _lock = arc2.read().unwrap(); panic!() }).join(); @@ -501,12 +501,12 @@ mod tests { let arc2 = arc.clone(); let (tx, rx) = channel(); - Thread::spawn(move|| { + thread::spawn(move|| { let mut lock = arc2.write().unwrap(); for _ in 0u..10 { let tmp = *lock; *lock = -1; - Thread::yield_now(); + thread::yield_now(); *lock = tmp + 1; } tx.send(()).unwrap(); @@ -516,7 +516,7 @@ mod tests { let mut children = Vec::new(); for _ in 0u..5 { let arc3 = arc.clone(); - children.push(Thread::scoped(move|| { + children.push(thread::spawn(move|| { let lock = arc3.read().unwrap(); assert!(*lock >= 0); })); @@ -537,7 +537,7 @@ mod tests { fn test_rw_arc_access_in_unwind() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); - let _ = Thread::scoped(move|| -> () { + let _ = thread::spawn(move|| -> () { struct Unwinder { i: Arc>, } diff --git a/src/libstd/sync/semaphore.rs b/src/libstd/sync/semaphore.rs index 0304b898884cc..410e1c11bb9a9 100644 --- a/src/libstd/sync/semaphore.rs +++ b/src/libstd/sync/semaphore.rs @@ -114,7 +114,7 @@ mod tests { use sync::Arc; use super::Semaphore; use sync::mpsc::channel; - use thread::Thread; + use thread; #[test] fn test_sem_acquire_release() { @@ -134,7 +134,7 @@ mod tests { fn test_sem_as_mutex() { let s = Arc::new(Semaphore::new(1)); let s2 = s.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _g = s2.access(); }); let _g = s.access(); @@ -146,7 +146,7 @@ mod tests { let (tx, rx) = channel(); let s = Arc::new(Semaphore::new(0)); let s2 = s.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { s2.acquire(); tx.send(()).unwrap(); }); @@ -157,7 +157,7 @@ mod tests { let (tx, rx) = channel(); let s = Arc::new(Semaphore::new(0)); let s2 = s.clone(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { s2.release(); let _ = rx.recv(); }); @@ -173,7 +173,7 @@ mod tests { let s2 = s.clone(); let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _g = s2.access(); let _ = rx2.recv(); tx1.send(()).unwrap(); @@ -190,7 +190,7 @@ mod tests { let (tx, rx) = channel(); { let _g = s.access(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(()).unwrap(); drop(s2.access()); tx.send(()).unwrap(); diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index 684a46fd6ff5f..f4274dd91cc7a 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -20,16 +20,16 @@ use core::prelude::*; use sync::{Arc, Mutex}; use sync::mpsc::{channel, Sender, Receiver}; -use thread::Thread; +use thread; use thunk::Thunk; struct Sentinel<'a> { - jobs: &'a Arc>>, + jobs: &'a Arc>>>, active: bool } impl<'a> Sentinel<'a> { - fn new(jobs: &Arc>>) -> Sentinel { + fn new(jobs: &'a Arc>>>) -> Sentinel<'a> { Sentinel { jobs: jobs, active: true @@ -80,7 +80,7 @@ pub struct TaskPool { // // This is the only such Sender, so when it is dropped all subthreads will // quit. - jobs: Sender + jobs: Sender> } impl TaskPool { @@ -105,14 +105,14 @@ impl TaskPool { /// Executes the function `job` on a thread in the pool. pub fn execute(&self, job: F) - where F : FnOnce(), F : Send + where F : FnOnce(), F : Send + 'static { self.jobs.send(Thunk::new(job)).unwrap(); } } -fn spawn_in_pool(jobs: Arc>>) { - Thread::spawn(move || { +fn spawn_in_pool(jobs: Arc>>>) { + thread::spawn(move || { // Will spawn a new thread on panic unless it is cancelled. let sentinel = Sentinel::new(&jobs); diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index 255f474d4f4af..dc1ae85efe033 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -30,7 +30,7 @@ use sync::{StaticMutex, StaticCondvar}; use sync::mpsc::{channel, Sender, Receiver}; use sys::helper_signal; -use thread::Thread; +use thread; /// A structure for management of a helper thread. /// @@ -81,7 +81,7 @@ impl Helper { /// /// This function is safe to be called many times. pub fn boot(&'static self, f: F, helper: fn(helper_signal::signal, Receiver, T)) where - T: Send, + T: Send + 'static, F: FnOnce() -> T, { unsafe { @@ -95,7 +95,7 @@ impl Helper { let receive = RaceBox(receive); let t = f(); - Thread::spawn(move || { + thread::spawn(move || { helper(receive.0, rx, t); let _g = self.lock.lock().unwrap(); *self.shutdown.get() = true; diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index 92b936e74f654..65c706033f213 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -29,7 +29,7 @@ thread_local! { static THREAD_INFO: RefCell> = RefCell::new(N impl ThreadInfo { fn with(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R { if THREAD_INFO.state() == State::Destroyed { - panic!("Use of std::thread::Thread::current() is not possible after \ + panic!("Use of std::thread::current() is not possible after \ the thread's local data has been destroyed"); } @@ -63,7 +63,7 @@ pub fn set(stack_bounds: (uint, uint), stack_guard: uint, thread: Thread) { })); } -// a hack to get around privacy restrictions; implemented by `std::thread::Thread` +// a hack to get around privacy restrictions; implemented by `std::thread` pub trait NewThread { fn new(name: Option) -> Self; } diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index 905fac07c5d5d..27b8784e3943a 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -24,7 +24,7 @@ //! # Usage //! //! This module should likely not be used directly unless other primitives are -//! being built on. types such as `thread_local::scoped::Key` are likely much +//! being built on. types such as `thread_local::spawn::Key` are likely much //! more useful in practice than this OS-based version which likely requires //! unsafe code to interoperate with. //! diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 6047f94b3b459..b610f6c370bb3 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -817,7 +817,9 @@ impl<'a, S: Writer + Hasher> Hash for Wtf8 { } } -impl AsciiExt for Wtf8 { +impl AsciiExt for Wtf8 { + type Owned = Wtf8Buf; + fn is_ascii(&self) -> bool { self.bytes.is_ascii() } @@ -830,6 +832,9 @@ impl AsciiExt for Wtf8 { fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { self.bytes.eq_ignore_ascii_case(&other.bytes) } + + fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } + fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() } } #[cfg(test)] diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 8a6ef17818a09..df03841276e9e 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -247,6 +247,10 @@ impl Iterator for Args { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.iter.len() } +} + /// Returns the command line arguments /// /// Returns a list of the command line arguments. diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 6f030ee91fe2d..82c52471d1097 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -10,6 +10,7 @@ use core::prelude::*; +use io; use boxed::Box; use cmp; use mem; @@ -191,7 +192,7 @@ pub mod guard { } } -pub unsafe fn create(stack: uint, p: Thunk) -> rust_thread { +pub unsafe fn create(stack: uint, p: Thunk) -> io::Result { let mut native: libc::pthread_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed(); assert_eq!(pthread_attr_init(&mut attr), 0); @@ -226,9 +227,10 @@ pub unsafe fn create(stack: uint, p: Thunk) -> rust_thread { if ret != 0 { // be sure to not leak the closure let _p: Box> = mem::transmute(arg); - panic!("failed to spawn native thread: {}", ret); + Err(io::Error::from_os_error(ret)) + } else { + Ok(native) } - native } #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 7e684c5234141..502d70d4e1a16 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -18,7 +18,7 @@ use os::windows::*; use error::Error as StdError; use ffi::{OsString, OsStr, AsOsStr}; use fmt; -use iter::Range; +use ops::Range; use libc::types::os::arch::extra::LPWCH; use libc::{self, c_int, c_void}; use mem; @@ -303,6 +303,10 @@ impl Iterator for Args { fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } } +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.range.len() } +} + impl Drop for Args { fn drop(&mut self) { unsafe { c::LocalFree(self.cur as *mut c_void); } @@ -315,7 +319,7 @@ pub fn args() -> Args { let lpCmdLine = c::GetCommandLineW(); let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs); - Args { cur: szArgList, range: range(0, nArgs as isize) } + Args { cur: szArgList, range: 0..(nArgs as isize) } } } diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index a38dc9b2d3407..f3a27877e5c58 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use boxed::Box; +use prelude::v1::*; + use cmp; +use io; use mem; use ptr; use libc; @@ -42,7 +44,7 @@ pub mod guard { } } -pub unsafe fn create(stack: uint, p: Thunk) -> rust_thread { +pub unsafe fn create(stack: uint, p: Thunk) -> io::Result { let arg: *mut libc::c_void = mem::transmute(box p); // FIXME On UNIX, we guard against stack sizes that are too small but // that's because pthreads enforces that stacks are at least @@ -60,9 +62,10 @@ pub unsafe fn create(stack: uint, p: Thunk) -> rust_thread { if ret as uint == 0 { // be sure to not leak the closure let _p: Box = mem::transmute(arg); - panic!("failed to spawn native thread: {:?}", ret); + Err(io::Error::last_os_error()) + } else { + Ok(ret) } - return ret; } pub unsafe fn set_name(_name: &str) { diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index cc9d7492441cd..3137d779c4071 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -42,32 +42,32 @@ //! Already-running threads are represented via the `Thread` type, which you can //! get in one of two ways: //! -//! * By spawning a new thread, e.g. using the `Thread::spawn` constructor; -//! * By requesting the current thread, using the `Thread::current` function. +//! * By spawning a new thread, e.g. using the `thread::spawn` constructor; +//! * By requesting the current thread, using the `thread::current` function. //! //! Threads can be named, and provide some built-in support for low-level //! synchronization described below. //! -//! The `Thread::current()` function is available even for threads not spawned +//! The `thread::current()` function is available even for threads not spawned //! by the APIs of this module. //! //! ## Spawning a thread //! -//! A new thread can be spawned using the `Thread::spawn` function: +//! A new thread can be spawned using the `thread::spawn` function: //! //! ```rust -//! use std::thread::Thread; +//! use std::thread; //! -//! let thread = Thread::spawn(move || { +//! thread::spawn(move || { //! println!("Hello, World!"); //! // some computation here //! }); //! ``` //! -//! The spawned thread is "detached" from the current thread, meaning that it -//! can outlive the thread that spawned it. (Note, however, that when the main -//! thread terminates all detached threads are terminated as well.) The returned -//! `Thread` handle can be used for low-level synchronization as described below. +//! In this example, the spawned thread is "detached" from the current +//! thread, meaning that it can outlive the thread that spawned +//! it. (Note, however, that when the main thread terminates all +//! detached threads are terminated as well.) //! //! ## Scoped threads //! @@ -76,23 +76,23 @@ //! For this scenario, use the `scoped` constructor: //! //! ```rust -//! use std::thread::Thread; +//! use std::thread; //! -//! let guard = Thread::scoped(move || { +//! let guard = thread::scoped(move || { //! println!("Hello, World!"); //! // some computation here //! }); //! // do some other work in the meantime -//! let result = guard.join(); +//! let output = guard.join(); //! ``` //! -//! The `scoped` function doesn't return a `Thread` directly; instead, it -//! returns a *join guard* from which a `Thread` can be extracted. The join -//! guard is an RAII-style guard that will automatically join the child thread -//! (block until it terminates) when it is dropped. You can join the child -//! thread in advance by calling the `join` method on the guard, which will also -//! return the result produced by the thread. A handle to the thread itself is -//! available via the `thread` method on the join guard. +//! The `scoped` function doesn't return a `Thread` directly; instead, +//! it returns a *join guard*. The join guard is an RAII-style guard +//! that will automatically join the child thread (block until it +//! terminates) when it is dropped. You can join the child thread in +//! advance by calling the `join` method on the guard, which will also +//! return the result produced by the thread. A handle to the thread +//! itself is available via the `thread` method on the join guard. //! //! (Note: eventually, the `scoped` constructor will allow the parent and child //! threads to data that lives on the parent thread's stack, but some language @@ -120,10 +120,10 @@ //! Conceptually, each `Thread` handle has an associated token, which is //! initially not present: //! -//! * The `Thread::park()` function blocks the current thread unless or until +//! * The `thread::park()` function blocks the current thread unless or until //! the token is available for its thread handle, at which point It atomically //! consumes the token. It may also return *spuriously*, without consuming the -//! token. `Thread::park_timeout()` does the same, but allows specifying a +//! token. `thread::park_timeout()` does the same, but allows specifying a //! maximum time to block the thread for. //! //! * The `unpark()` method on a `Thread` atomically makes the token available @@ -147,19 +147,16 @@ #![stable(feature = "rust1", since = "1.0.0")] +use prelude::v1::*; + use any::Any; -use boxed::Box; use cell::UnsafeCell; -use clone::Clone; -use marker::{Send, Sync}; -use ops::{Drop, FnOnce}; -use option::Option::{self, Some, None}; -use result::Result::{Err, Ok}; -use sync::{Mutex, Condvar, Arc}; -use str::Str; -use string::String; +use fmt; +use io; +use marker; +use old_io::stdio; use rt::{self, unwind}; -use old_io::{Writer, stdio}; +use sync::{Mutex, Condvar, Arc}; use thunk::Thunk; use time::Duration; @@ -175,9 +172,9 @@ pub struct Builder { // The size of the stack for the spawned thread stack_size: Option, // Thread-local stdout - stdout: Option>, + stdout: Option>, // Thread-local stderr - stderr: Option>, + stderr: Option>, } impl Builder { @@ -211,7 +208,7 @@ impl Builder { /// Redirect thread-local stdout. #[unstable(feature = "std_misc", reason = "Will likely go away after proc removal")] - pub fn stdout(mut self, stdout: Box) -> Builder { + pub fn stdout(mut self, stdout: Box) -> Builder { self.stdout = Some(stdout); self } @@ -219,54 +216,65 @@ impl Builder { /// Redirect thread-local stderr. #[unstable(feature = "std_misc", reason = "Will likely go away after proc removal")] - pub fn stderr(mut self, stderr: Box) -> Builder { + pub fn stderr(mut self, stderr: Box) -> Builder { self.stderr = Some(stderr); self } - /// Spawn a new detached thread, and return a handle to it. + /// Spawn a new thread, and return a join handle for it. /// - /// See `Thead::spawn` and the module doc for more details. - #[unstable(feature = "std_misc", - reason = "may change with specifics of new Send semantics")] - pub fn spawn(self, f: F) -> Thread where F: FnOnce(), F: Send + 'static { - let (native, thread) = self.spawn_inner(Thunk::new(f), Thunk::with_arg(|_| {})); - unsafe { imp::detach(native) }; - thread + /// The child thread may outlive the parent (unless the parent thread + /// is the main thread; the whole process is terminated when the main + /// thread finishes.) The join handle can be used to block on + /// termination of the child thread, including recovering its panics. + /// + /// # Errors + /// + /// Unlike the `spawn` free function, this method yields an + /// `io::Result` to capture any failure to create the thread at + /// the OS level. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn spawn(self, f: F) -> io::Result where + F: FnOnce(), F: Send + 'static + { + self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i)) } /// Spawn a new child thread that must be joined within a given /// scope, and return a `JoinGuard`. /// - /// See `Thead::scoped` and the module doc for more details. - #[unstable(feature = "std_misc", - reason = "may change with specifics of new Send semantics")] - pub fn scoped<'a, T, F>(self, f: F) -> JoinGuard<'a, T> where + /// The join guard can be used to explicitly join the child thread (via + /// `join`), returning `Result`, or it will implicitly join the child + /// upon being dropped. Because the child thread may refer to data on the + /// current thread's stack (hence the "scoped" name), it cannot be detached; + /// it *must* be joined before the relevant stack frame is popped. See the + /// module documentation for additional details. + /// + /// # Errors + /// + /// Unlike the `scoped` free function, this method yields an + /// `io::Result` to capture any failure to create the thread at + /// the OS level. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { - let my_packet = Packet(Arc::new(UnsafeCell::new(None))); - let their_packet = Packet(my_packet.0.clone()); - let (native, thread) = self.spawn_inner(Thunk::new(f), Thunk::with_arg(move |ret| unsafe { - *their_packet.0.get() = Some(ret); - })); - - JoinGuard { - native: native, - joined: false, - packet: my_packet, - thread: thread, - } + self.spawn_inner(Thunk::new(f)).map(|inner| { + JoinGuard { inner: inner, _marker: marker::CovariantType } + }) } - fn spawn_inner(self, f: Thunk<(), T>, finish: Thunk, ()>) - -> (imp::rust_thread, Thread) - { + fn spawn_inner(self, f: Thunk<(), T>) -> io::Result> { let Builder { name, stack_size, stdout, stderr } = self; let stack_size = stack_size.unwrap_or(rt::min_stack()); + let my_thread = Thread::new(name); let their_thread = my_thread.clone(); + let my_packet = Packet(Arc::new(UnsafeCell::new(None))); + let their_packet = Packet(my_packet.0.clone()); + // Spawning a new OS thread guarantees that __morestack will never get // triggered, but we must manually set up the actual stack bounds once // this function starts executing. This raises the lower limit by a bit @@ -316,17 +324,120 @@ impl Builder { unwind::try(move || *ptr = Some(f.invoke(()))) } }; - finish.invoke(match (output, try_result) { - (Some(data), Ok(_)) => Ok(data), - (None, Err(cause)) => Err(cause), - _ => unreachable!() - }); + unsafe { + *their_packet.0.get() = Some(match (output, try_result) { + (Some(data), Ok(_)) => Ok(data), + (None, Err(cause)) => Err(cause), + _ => unreachable!() + }); + } }; - (unsafe { imp::create(stack_size, Thunk::new(main)) }, my_thread) + Ok(JoinInner { + native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }), + thread: my_thread, + packet: my_packet, + joined: false, + }) + } +} + +/// Spawn a new, returning a join handle for it. +/// +/// The child thread may outlive the parent (unless the parent thread +/// is the main thread; the whole process is terminated when the main +/// thread finishes.) The join handle can be used to block on +/// termination of the child thread, including recovering its panics. +/// +/// # Panics +/// +/// Panicks if the OS fails to create a thread; use `Builder::spawn` +/// to recover from such errors. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn spawn(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static { + Builder::new().spawn(f).unwrap() +} + +/// Spawn a new *scoped* thread, returning a `JoinGuard` for it. +/// +/// The join guard can be used to explicitly join the child thread (via +/// `join`), returning `Result`, or it will implicitly join the child +/// upon being dropped. Because the child thread may refer to data on the +/// current thread's stack (hence the "scoped" name), it cannot be detached; +/// it *must* be joined before the relevant stack frame is popped. See the +/// module documentation for additional details. +/// +/// # Panics +/// +/// Panicks if the OS fails to create a thread; use `Builder::scoped` +/// to recover from such errors. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where + T: Send + 'a, F: FnOnce() -> T, F: Send + 'a +{ + Builder::new().scoped(f).unwrap() +} + +/// Gets a handle to the thread that invokes it. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn current() -> Thread { + thread_info::current_thread() +} + +/// Cooperatively give up a timeslice to the OS scheduler. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn yield_now() { + unsafe { imp::yield_now() } +} + +/// Determines whether the current thread is unwinding because of panic. +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn panicking() -> bool { + unwind::panicking() +} + +/// Block unless or until the current thread's token is made available (may wake spuriously). +/// +/// See the module doc for more detail. +// +// The implementation currently uses the trivial strategy of a Mutex+Condvar +// with wakeup flag, which does not actually allow spurious wakeups. In the +// future, this will be implemented in a more efficient way, perhaps along the lines of +// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp +// or futuxes, and in either case may allow spurious wakeups. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn park() { + let thread = current(); + let mut guard = thread.inner.lock.lock().unwrap(); + while !*guard { + guard = thread.inner.cvar.wait(guard).unwrap(); } + *guard = false; +} + +/// Block 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 +/// +/// See the module doc for more detail. +#[unstable(feature = "std_misc", reason = "recently introduced, depends 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(guard, dur).unwrap(); + guard = g; + } + *guard = false; } +/// The internal representation of a `Thread` handle struct Inner { name: Option, lock: Mutex, // true when there is a buffered unpark @@ -354,65 +465,51 @@ impl Thread { } } - /// Spawn a new detached thread, returning a handle to it. - /// - /// The child thread may outlive the parent (unless the parent thread is the - /// main thread; the whole process is terminated when the main thread - /// finishes.) The thread handle can be used for low-level - /// synchronization. See the module documentation for additional details. + /// Deprecated: use module-level free fucntion. + #[deprecated(since = "1.0.0", reason = "use module-level free fucntion")] #[unstable(feature = "std_misc", reason = "may change with specifics of new Send semantics")] pub fn spawn(f: F) -> Thread where F: FnOnce(), F: Send + 'static { - Builder::new().spawn(f) + Builder::new().spawn(f).unwrap().thread().clone() } - /// Spawn a new *scoped* thread, returning a `JoinGuard` for it. - /// - /// The join guard can be used to explicitly join the child thread (via - /// `join`), returning `Result`, or it will implicitly join the child - /// upon being dropped. Because the child thread may refer to data on the - /// current thread's stack (hence the "scoped" name), it cannot be detached; - /// it *must* be joined before the relevant stack frame is popped. See the - /// module documentation for additional details. + /// Deprecated: use module-level free fucntion. + #[deprecated(since = "1.0.0", reason = "use module-level free fucntion")] #[unstable(feature = "std_misc", reason = "may change with specifics of new Send semantics")] pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { - Builder::new().scoped(f) + Builder::new().scoped(f).unwrap() } - /// Gets a handle to the thread that invokes it. + /// Deprecated: use module-level free fucntion. + #[deprecated(since = "1.0.0", reason = "use module-level free fucntion")] #[stable(feature = "rust1", since = "1.0.0")] pub fn current() -> Thread { thread_info::current_thread() } - /// Cooperatively give up a timeslice to the OS scheduler. + /// Deprecated: use module-level free fucntion. + #[deprecated(since = "1.0.0", reason = "use module-level free fucntion")] #[unstable(feature = "std_misc", reason = "name may change")] pub fn yield_now() { unsafe { imp::yield_now() } } - /// Determines whether the current thread is unwinding because of panic. + /// Deprecated: use module-level free fucntion. + #[deprecated(since = "1.0.0", reason = "use module-level free fucntion")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn panicking() -> bool { unwind::panicking() } - /// Block unless or until the current thread's token is made available (may wake spuriously). - /// - /// See the module doc for more detail. - // - // The implementation currently uses the trivial strategy of a Mutex+Condvar - // with wakeup flag, which does not actually allow spurious wakeups. In the - // future, this will be implemented in a more efficient way, perhaps along the lines of - // http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp - // or futuxes, and in either case may allow spurious wakeups. + /// Deprecated: use module-level free fucntion. + #[deprecated(since = "1.0.0", reason = "use module-level free fucntion")] #[unstable(feature = "std_misc", reason = "recently introduced")] pub fn park() { - let thread = Thread::current(); + let thread = current(); let mut guard = thread.inner.lock.lock().unwrap(); while !*guard { guard = thread.inner.cvar.wait(guard).unwrap(); @@ -420,19 +517,11 @@ impl Thread { *guard = false; } - /// Block 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 - /// - /// See the module doc for more detail. + /// Deprecated: use module-level free fucntion. + #[deprecated(since = "1.0.0", reason = "use module-level free fucntion")] #[unstable(feature = "std_misc", reason = "recently introduced")] pub fn park_timeout(dur: Duration) { - let thread = Thread::current(); + let thread = current(); let mut guard = thread.inner.lock.lock().unwrap(); if !*guard { let (g, _) = thread.inner.cvar.wait_timeout(guard, dur).unwrap(); @@ -444,7 +533,7 @@ impl Thread { /// Atomically makes the handle's token available if it is not already. /// /// See the module doc for more detail. - #[unstable(feature = "std_misc", reason = "recently introduced")] + #[stable(feature = "rust1", since = "1.0.0")] pub fn unpark(&self) { let mut guard = self.inner.lock.lock().unwrap(); if !*guard { @@ -460,6 +549,13 @@ impl Thread { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Thread { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.name(), f) + } +} + // a hack to get around privacy restrictions impl thread_info::NewThread for Thread { fn new(name: Option) -> Thread { Thread::new(name) } @@ -469,24 +565,84 @@ impl thread_info::NewThread for Thread { /// /// A thread that completes without panicking is considered to exit successfully. #[stable(feature = "rust1", since = "1.0.0")] -pub type Result = ::result::Result>; +pub type Result = ::result::Result>; struct Packet(Arc>>>); -unsafe impl Send for Packet {} +unsafe impl Send for Packet {} unsafe impl Sync for Packet {} +/// Inner representation for JoinHandle and JoinGuard +struct JoinInner { + native: imp::rust_thread, + thread: Thread, + packet: Packet, + joined: bool, +} + +impl JoinInner { + fn join(&mut self) -> Result { + assert!(!self.joined); + unsafe { imp::join(self.native) }; + self.joined = true; + unsafe { + (*self.packet.0.get()).take().unwrap() + } + } +} + +/// An owned permission to join on a thread (block on its termination). +/// +/// Unlike a `JoinGuard`, a `JoinHandle` *detaches* the child thread +/// when it is dropped, rather than automatically joining on drop. +/// +/// Due to platform restrictions, it is not possible to `Clone` this +/// handle: the ability to join a child thread is a uniquely-owned +/// permission. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct JoinHandle(JoinInner<()>); + +impl JoinHandle { + /// Extract a handle to the underlying thread + #[stable(feature = "rust1", since = "1.0.0")] + pub fn thread(&self) -> &Thread { + &self.0.thread + } + + /// Wait for the associated thread to finish. + /// + /// If the child thread panics, `Err` is returned with the parameter given + /// to `panic`. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn join(mut self) -> Result<()> { + self.0.join() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for JoinHandle { + fn drop(&mut self) { + if !self.0.joined { + unsafe { imp::detach(self.0.native) } + } + } +} + /// An RAII-style guard that will block until thread termination when dropped. /// /// The type `T` is the return type for the thread's main function. +/// +/// Joining on drop is necessary to ensure memory safety when stack +/// data is shared between a parent and child thread. +/// +/// Due to platform restrictions, it is not possible to `Clone` this +/// handle: the ability to join a child thread is a uniquely-owned +/// permission. #[must_use] -#[unstable(feature = "std_misc", - reason = "may change with specifics of new Send semantics")] +#[stable(feature = "rust1", since = "1.0.0")] pub struct JoinGuard<'a, T: 'a> { - native: imp::rust_thread, - thread: Thread, - joined: bool, - packet: Packet, + inner: JoinInner, + _marker: marker::CovariantType<&'a T>, } #[stable(feature = "rust1", since = "1.0.0")] @@ -496,32 +652,32 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> { /// Extract a handle to the thread this guard will join on. #[stable(feature = "rust1", since = "1.0.0")] pub fn thread(&self) -> &Thread { - &self.thread + &self.inner.thread } /// Wait for the associated thread to finish, returning the result of the thread's /// calculation. /// - /// If the child thread panics, `Err` is returned with the parameter given - /// to `panic`. + /// # Panics + /// + /// Panics on the child thread are propagated by panicking the parent. #[stable(feature = "rust1", since = "1.0.0")] - pub fn join(mut self) -> Result { - assert!(!self.joined); - unsafe { imp::join(self.native) }; - self.joined = true; - unsafe { - (*self.packet.0.get()).take().unwrap() + pub fn join(mut self) -> T { + match self.inner.join() { + Ok(res) => res, + Err(_) => panic!("child thread {:?} panicked", self.thread()), } } } +#[stable(feature = "rust1", since = "1.0.0")] impl JoinGuard<'static, T> { /// Detaches the child thread, allowing it to outlive its parent. - #[unstable(feature = "std_misc", - reason = "unsure whether this API imposes limitations elsewhere")] + #[deprecated(since = "1.0.0", reason = "use spawn instead")] + #[unstable(feature = "std_misc")] pub fn detach(mut self) { - unsafe { imp::detach(self.native) }; - self.joined = true; // avoid joining in the destructor + unsafe { imp::detach(self.inner.native) }; + self.inner.joined = true; // avoid joining in the destructor } } @@ -529,8 +685,10 @@ impl JoinGuard<'static, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { fn drop(&mut self) { - if !self.joined { - unsafe { imp::join(self.native) }; + if !self.inner.joined { + if self.inner.join().is_err() { + panic!("child thread {:?} panicked", self.thread()); + } } } } @@ -545,6 +703,7 @@ mod test { use result; use std::old_io::{ChanReader, ChanWriter}; use super::{Thread, Builder}; + use thread; use thunk::Thunk; use time::Duration; @@ -553,22 +712,22 @@ mod test { #[test] fn test_unnamed_thread() { - Thread::scoped(move|| { - assert!(Thread::current().name().is_none()); + thread::spawn(move|| { + assert!(thread::current().name().is_none()); }).join().ok().unwrap(); } #[test] fn test_named_thread() { Builder::new().name("ada lovelace".to_string()).scoped(move|| { - assert!(Thread::current().name().unwrap() == "ada lovelace".to_string()); - }).join().ok().unwrap(); + assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); + }).unwrap().join(); } #[test] fn test_run_basic() { let (tx, rx) = channel(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(()).unwrap(); }); rx.recv().unwrap(); @@ -576,17 +735,14 @@ mod test { #[test] fn test_join_success() { - match Thread::scoped(move|| -> String { + assert!(thread::scoped(move|| -> String { "Success!".to_string() - }).join().as_ref().map(|s| &**s) { - result::Result::Ok("Success!") => (), - _ => panic!() - } + }).join() == "Success!"); } #[test] fn test_join_panic() { - match Thread::scoped(move|| { + match thread::spawn(move|| { panic!() }).join() { result::Result::Err(_) => (), @@ -594,6 +750,26 @@ mod test { } } + #[test] + fn test_scoped_success() { + let res = thread::scoped(move|| -> String { + "Success!".to_string() + }).join(); + assert!(res == "Success!"); + } + + #[test] + #[should_fail] + fn test_scoped_panic() { + thread::scoped(|| panic!()).join(); + } + + #[test] + #[should_fail] + fn test_scoped_implicit_panic() { + thread::scoped(|| panic!()); + } + #[test] fn test_spawn_sched() { use clone::Clone; @@ -602,7 +778,7 @@ mod test { fn f(i: int, tx: Sender<()>) { let tx = tx.clone(); - Thread::spawn(move|| { + thread::spawn(move|| { if i == 0 { tx.send(()).unwrap(); } else { @@ -619,8 +795,8 @@ mod test { fn test_spawn_sched_childs_on_default_sched() { let (tx, rx) = channel(); - Thread::spawn(move|| { - Thread::spawn(move|| { + thread::spawn(move|| { + thread::spawn(move|| { tx.send(()).unwrap(); }); }); @@ -628,7 +804,7 @@ mod test { rx.recv().unwrap(); } - fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Thunk) { + fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Thunk<'static>) { let (tx, rx) = channel::(); let x = box 1; @@ -646,14 +822,14 @@ mod test { #[test] fn test_avoid_copying_the_body_spawn() { avoid_copying_the_body(|v| { - Thread::spawn(move || v.invoke(())); + thread::spawn(move || v.invoke(())); }); } #[test] fn test_avoid_copying_the_body_thread_spawn() { avoid_copying_the_body(|f| { - Thread::spawn(move|| { + thread::spawn(move|| { f.invoke(()); }); }) @@ -662,7 +838,7 @@ mod test { #[test] fn test_avoid_copying_the_body_join() { avoid_copying_the_body(|f| { - let _ = Thread::scoped(move|| { + let _ = thread::spawn(move|| { f.invoke(()) }).join(); }) @@ -675,24 +851,24 @@ mod test { // (well, it would if the constant were 8000+ - I lowered it to be more // valgrind-friendly. try this at home, instead..!) static GENERATIONS: uint = 16; - fn child_no(x: uint) -> Thunk { + fn child_no(x: uint) -> Thunk<'static> { return Thunk::new(move|| { if x < GENERATIONS { - Thread::spawn(move|| child_no(x+1).invoke(())); + thread::spawn(move|| child_no(x+1).invoke(())); } }); } - Thread::spawn(|| child_no(0).invoke(())); + thread::spawn(|| child_no(0).invoke(())); } #[test] fn test_simple_newsched_spawn() { - Thread::spawn(move || {}); + thread::spawn(move || {}); } #[test] fn test_try_panic_message_static_str() { - match Thread::scoped(move|| { + match thread::spawn(move|| { panic!("static string"); }).join() { Err(e) => { @@ -706,7 +882,7 @@ mod test { #[test] fn test_try_panic_message_owned_str() { - match Thread::scoped(move|| { + match thread::spawn(move|| { panic!("owned string".to_string()); }).join() { Err(e) => { @@ -720,7 +896,7 @@ mod test { #[test] fn test_try_panic_message_any() { - match Thread::scoped(move|| { + match thread::spawn(move|| { panic!(box 413u16 as Box); }).join() { Err(e) => { @@ -738,7 +914,7 @@ mod test { fn test_try_panic_message_unit_struct() { struct Juju; - match Thread::scoped(move|| { + match thread::spawn(move|| { panic!(Juju) }).join() { Err(ref e) if e.is::() => {} @@ -752,10 +928,9 @@ mod test { let mut reader = ChanReader::new(rx); let stdout = ChanWriter::new(tx); - let r = Builder::new().stdout(box stdout as Box).scoped(move|| { + Builder::new().stdout(box stdout as Box).scoped(move|| { print!("Hello, world!"); - }).join(); - assert!(r.is_ok()); + }).unwrap().join(); let output = reader.read_to_string().unwrap(); assert_eq!(output, "Hello, world!".to_string()); @@ -764,15 +939,15 @@ mod test { #[test] fn test_park_timeout_unpark_before() { for _ in 0..10 { - Thread::current().unpark(); - Thread::park_timeout(Duration::seconds(10_000_000)); + thread::current().unpark(); + thread::park_timeout(Duration::seconds(10_000_000)); } } #[test] fn test_park_timeout_unpark_not_called() { for _ in 0..10 { - Thread::park_timeout(Duration::milliseconds(10)); + thread::park_timeout(Duration::milliseconds(10)); } } @@ -781,14 +956,14 @@ mod test { use std::old_io; for _ in 0..10 { - let th = Thread::current(); + let th = thread::current(); - let _guard = Thread::scoped(move || { + let _guard = thread::spawn(move || { old_io::timer::sleep(Duration::milliseconds(50)); th.unpark(); }); - Thread::park_timeout(Duration::seconds(10_000_000)); + thread::park_timeout(Duration::seconds(10_000_000)); } } diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index eab9cd84539ed..2ed296e081c90 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -72,7 +72,7 @@ pub mod __impl { /// /// ``` /// use std::cell::RefCell; -/// use std::thread::Thread; +/// use std::thread; /// /// thread_local!(static FOO: RefCell = RefCell::new(1)); /// @@ -82,7 +82,7 @@ pub mod __impl { /// }); /// /// // each thread starts out with the initial value of 1 -/// Thread::spawn(move|| { +/// thread::spawn(move|| { /// FOO.with(|f| { /// assert_eq!(*f.borrow(), 1); /// *f.borrow_mut() = 3; @@ -548,7 +548,7 @@ mod tests { use sync::mpsc::{channel, Sender}; use cell::UnsafeCell; use super::State; - use thread::Thread; + use thread; struct Foo(Sender<()>); @@ -568,7 +568,7 @@ mod tests { *f.get() = 2; }); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { FOO.with(|f| unsafe { assert_eq!(*f.get(), 1); }); @@ -595,7 +595,7 @@ mod tests { } thread_local!(static FOO: Foo = foo()); - Thread::scoped(|| { + thread::spawn(|| { assert!(FOO.state() == State::Uninitialized); FOO.with(|_| { assert!(FOO.state() == State::Valid); @@ -611,7 +611,7 @@ mod tests { }); let (tx, rx) = channel(); - let _t = Thread::spawn(move|| unsafe { + let _t = thread::spawn(move|| unsafe { let mut tx = Some(tx); FOO.with(|f| { *f.get() = Some(Foo(tx.take().unwrap())); @@ -659,7 +659,7 @@ mod tests { } } - Thread::scoped(move|| { + thread::spawn(move|| { drop(S1); }).join().ok().unwrap(); } @@ -677,7 +677,7 @@ mod tests { } } - Thread::scoped(move|| unsafe { + thread::spawn(move|| unsafe { K1.with(|s| *s.get() = Some(S1)); }).join().ok().unwrap(); } @@ -704,7 +704,7 @@ mod tests { } let (tx, rx) = channel(); - let _t = Thread::spawn(move|| unsafe { + let _t = thread::spawn(move|| unsafe { let mut tx = Some(tx); K1.with(|s| *s.get() = Some(S1(tx.take().unwrap()))); }); diff --git a/src/libstd/thunk.rs b/src/libstd/thunk.rs index 0831242f954cf..fe39954f0d446 100644 --- a/src/libstd/thunk.rs +++ b/src/libstd/thunk.rs @@ -16,21 +16,24 @@ use alloc::boxed::Box; use core::marker::Send; use core::ops::FnOnce; -pub struct Thunk { - invoke: Box+Send> +pub struct Thunk<'a, A=(),R=()> { + #[cfg(stage0)] + invoke: Box+Send>, + #[cfg(not(stage0))] + invoke: Box+Send + 'a>, } -impl Thunk<(),R> { - pub fn new(func: F) -> Thunk<(),R> - where F : FnOnce() -> R, F : Send +impl<'a, R> Thunk<'a,(),R> { + pub fn new(func: F) -> Thunk<'a,(),R> + where F : FnOnce() -> R, F : Send + 'a { Thunk::with_arg(move|()| func()) } } -impl Thunk { - pub fn with_arg(func: F) -> Thunk - where F : FnOnce(A) -> R, F : Send +impl<'a,A,R> Thunk<'a,A,R> { + pub fn with_arg(func: F) -> Thunk<'a,A,R> + where F : FnOnce(A) -> R, F : Send + 'a { Thunk { invoke: box func diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index 1ceda2e08dd82..d8cba139fb597 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -18,6 +18,7 @@ use codemap; use codemap::Span; use ext::base; use ext::base::*; +use feature_gate; use parse::token::InternedString; use parse::token; use ptr::P; @@ -48,6 +49,12 @@ static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { + if !cx.ecfg.enable_asm() { + feature_gate::emit_feature_err( + &cx.parse_sess.span_diagnostic, "asm", sp, feature_gate::EXPLAIN_ASM); + return DummyResult::expr(sp); + } + let mut p = cx.new_parser_from_tts(tts); let mut asm = InternedString::new(""); let mut asm_str_style = None; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 083039995ee95..8800ffd1e9b5f 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -439,7 +439,8 @@ impl BlockInfo { /// The base map of methods for expanding syntax extension /// AST nodes into full ASTs -fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv { +fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) + -> SyntaxEnv { // utility function to simplify creating NormalTT syntax extensions fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension { NormalTT(box f, None) @@ -470,7 +471,7 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv { syntax_expanders.insert(intern("deriving"), Decorator(box ext::deriving::expand_deprecated_deriving)); - if ecfg.enable_quotes { + if ecfg.enable_quotes() { // Quasi-quoting expanders syntax_expanders.insert(intern("quote_tokens"), builtin_normal_expander( @@ -541,7 +542,7 @@ pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, pub cfg: ast::CrateConfig, pub backtrace: ExpnId, - pub ecfg: expand::ExpansionConfig, + pub ecfg: expand::ExpansionConfig<'a>, pub use_std: bool, pub mod_path: Vec , @@ -554,7 +555,7 @@ pub struct ExtCtxt<'a> { impl<'a> ExtCtxt<'a> { pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, - ecfg: expand::ExpansionConfig) -> ExtCtxt<'a> { + ecfg: expand::ExpansionConfig<'a>) -> ExtCtxt<'a> { let env = initial_syntax_expander_table(&ecfg); ExtCtxt { parse_sess: parse_sess, diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 364cacd735cc7..63a8bd9ddf1b3 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -12,12 +12,21 @@ use ast; use codemap::Span; use ext::base::*; use ext::base; +use feature_gate; use parse::token; use parse::token::{str_to_ident}; use ptr::P; pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { + if !cx.ecfg.enable_concat_idents() { + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "concat_idents", + sp, + feature_gate::EXPLAIN_CONCAT_IDENTS); + return base::DummyResult::expr(sp); + } + let mut res_str = String::new(); for (i, e) in tts.iter().enumerate() { if i & 1 == 1 { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fd98f42c2ab03..6b7cecee81576 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -22,6 +22,7 @@ use attr::AttrMetaMethods; use codemap; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use ext::base::*; +use feature_gate::{Features}; use fold; use fold::*; use parse; @@ -1408,28 +1409,63 @@ fn new_span(cx: &ExtCtxt, sp: Span) -> Span { } } -pub struct ExpansionConfig { +pub struct ExpansionConfig<'feat> { pub crate_name: String, - pub enable_quotes: bool, + pub features: Option<&'feat Features>, pub recursion_limit: usize, } -impl ExpansionConfig { - pub fn default(crate_name: String) -> ExpansionConfig { +impl<'feat> ExpansionConfig<'feat> { + pub fn default(crate_name: String) -> ExpansionConfig<'static> { ExpansionConfig { crate_name: crate_name, - enable_quotes: false, + features: None, recursion_limit: 64, } } + + pub fn enable_quotes(&self) -> bool { + match self.features { + Some(&Features { allow_quote: true, .. }) => true, + _ => false, + } + } + + pub fn enable_asm(&self) -> bool { + match self.features { + Some(&Features { allow_asm: true, .. }) => true, + _ => false, + } + } + + pub fn enable_log_syntax(&self) -> bool { + match self.features { + Some(&Features { allow_log_syntax: true, .. }) => true, + _ => false, + } + } + + pub fn enable_concat_idents(&self) -> bool { + match self.features { + Some(&Features { allow_concat_idents: true, .. }) => true, + _ => false, + } + } + + pub fn enable_trace_macros(&self) -> bool { + match self.features { + Some(&Features { allow_trace_macros: true, .. }) => true, + _ => false, + } + } } -pub fn expand_crate(parse_sess: &parse::ParseSess, - cfg: ExpansionConfig, - // these are the macros being imported to this crate: - imported_macros: Vec, - user_exts: Vec, - c: Crate) -> Crate { +pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess, + cfg: ExpansionConfig<'feat>, + // these are the macros being imported to this crate: + imported_macros: Vec, + user_exts: Vec, + c: Crate) -> Crate { let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg); cx.use_std = std_inject::use_std(&c); @@ -1598,7 +1634,7 @@ mod test { // these following tests are quite fragile, in that they don't test what // *kind* of failure occurs. - fn test_ecfg() -> ExpansionConfig { + fn test_ecfg() -> ExpansionConfig<'static> { ExpansionConfig::default("test".to_string()) } diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 30301e3b8cc92..8173dd93f7468 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -11,12 +11,20 @@ use ast; use codemap; use ext::base; +use feature_gate; use print; pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box { + if !cx.ecfg.enable_log_syntax() { + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "log_syntax", + sp, + feature_gate::EXPLAIN_LOG_SYNTAX); + return base::DummyResult::any(sp); + } cx.print_backtrace(); diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index 76f7b7b0d7b3b..3fcc6a8d69241 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -12,6 +12,7 @@ use ast; use codemap::Span; use ext::base::ExtCtxt; use ext::base; +use feature_gate; use parse::token::keywords; @@ -19,6 +20,15 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt, sp: Span, tt: &[ast::TokenTree]) -> Box { + if !cx.ecfg.enable_trace_macros() { + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "trace_macros", + sp, + feature_gate::EXPLAIN_TRACE_MACROS); + return base::DummyResult::any(sp); + } + + match tt { [ast::TtToken(_, ref tok)] if tok.is_keyword(keywords::True) => { cx.set_trace_macros(true); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fd1ca11818c98..3bebba15a572b 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -23,6 +23,7 @@ //! becomes stable. use self::Status::*; +use self::AttributeType::*; use abi::RustIntrinsic; use ast::NodeId; @@ -35,7 +36,6 @@ use visit; use visit::Visitor; use parse::token::{self, InternedString}; -use std::slice; use std::ascii::AsciiExt; // If you change this list without updating src/doc/reference.md, @cmr will be sad @@ -133,6 +133,12 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows using the unsafe_no_drop_flag attribute (unlikely to // switch to Accepted; see RFC 320) ("unsafe_no_drop_flag", "1.0.0", Active), + + // Allows the use of custom attributes; RFC 572 + ("custom_attribute", "1.0.0", Active), + + // Allows the use of rustc_* attributes; RFC 572 + ("rustc_attrs", "1.0.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -152,12 +158,148 @@ enum Status { Accepted, } +// Attributes that have a special meaning to rustc or rustdoc +pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ + // Normal attributes + + ("warn", Normal), + ("allow", Normal), + ("forbid", Normal), + ("deny", Normal), + + ("macro_reexport", Normal), + ("macro_use", Normal), + ("macro_export", Normal), + ("plugin_registrar", Normal), + + ("cfg", Normal), + ("main", Normal), + ("start", Normal), + ("test", Normal), + ("bench", Normal), + ("simd", Normal), + ("repr", Normal), + ("path", Normal), + ("abi", Normal), + ("unsafe_destructor", Normal), + ("automatically_derived", Normal), + ("no_mangle", Normal), + ("no_link", Normal), + ("derive", Normal), + ("should_fail", Normal), + ("ignore", Normal), + ("no_implicit_prelude", Normal), + ("reexport_test_harness_main", Normal), + ("link_args", Normal), + ("macro_escape", Normal), + + + ("staged_api", Gated("staged_api", + "staged_api is for use by rustc only")), + ("plugin", Gated("plugin", + "compiler plugins are experimental \ + and possibly buggy")), + ("no_std", Gated("no_std", + "no_std is experimental")), + ("lang", Gated("lang_items", + "language items are subject to change")), + ("linkage", Gated("linkage", + "the `linkage` attribute is experimental \ + and not portable across platforms")), + ("thread_local", Gated("thread_local", + "`#[thread_local]` is an experimental feature, and does not \ + currently handle destructors. There is no corresponding \ + `#[task_local]` mapping to the task model")), + + ("rustc_on_unimplemented", Gated("on_unimplemented", + "the `#[rustc_on_unimplemented]` attribute \ + is an experimental feature")), + ("rustc_variance", Gated("rustc_attrs", + "the `#[rustc_variance]` attribute \ + is an experimental feature")), + ("rustc_error", Gated("rustc_attrs", + "the `#[rustc_error]` attribute \ + is an experimental feature")), + ("rustc_move_fragments", Gated("rustc_attrs", + "the `#[rustc_move_fragments]` attribute \ + is an experimental feature")), + + // FIXME: #14408 whitelist docs since rustdoc looks at them + ("doc", Whitelisted), + + // FIXME: #14406 these are processed in trans, which happens after the + // lint pass + ("cold", Whitelisted), + ("export_name", Whitelisted), + ("inline", Whitelisted), + ("link", Whitelisted), + ("link_name", Whitelisted), + ("link_section", Whitelisted), + ("no_builtins", Whitelisted), + ("no_mangle", Whitelisted), + ("no_split_stack", Whitelisted), + ("no_stack_check", Whitelisted), + ("packed", Whitelisted), + ("static_assert", Whitelisted), + ("no_debug", Whitelisted), + ("omit_gdb_pretty_printer_section", Whitelisted), + ("unsafe_no_drop_flag", Whitelisted), + + // used in resolve + ("prelude_import", Whitelisted), + + // FIXME: #14407 these are only looked at on-demand so we can't + // guarantee they'll have already been checked + ("deprecated", Whitelisted), + ("must_use", Whitelisted), + ("stable", Whitelisted), + ("unstable", Whitelisted), + + // FIXME: #19470 this shouldn't be needed forever + ("old_orphan_check", Whitelisted), + ("old_impl_check", Whitelisted), + ("rustc_paren_sugar", Whitelisted), // FIXME: #18101 temporary unboxed closure hack + + // Crate level attributes + ("crate_name", CrateLevel), + ("crate_type", CrateLevel), + ("crate_id", CrateLevel), + ("feature", CrateLevel), + ("no_start", CrateLevel), + ("no_main", CrateLevel), + ("no_builtins", CrateLevel), + ("recursion_limit", CrateLevel), +]; + +#[derive(PartialEq, Copy)] +pub enum AttributeType { + /// Normal, builtin attribute that is consumed + /// by the compiler before the unused_attribute check + Normal, + + /// Builtin attribute that may not be consumed by the compiler + /// before the unused_attribute check. These attributes + /// will be ignored by the unused_attribute lint + Whitelisted, + + /// Is gated by a given feature gate and reason + /// These get whitelisted too + Gated(&'static str, &'static str), + + /// Builtin attribute that is only allowed at the crate level + CrateLevel, +} + /// A set of features to be used by later passes. pub struct Features { pub unboxed_closures: bool, pub rustc_diagnostic_macros: bool, pub visible_private_types: bool, - pub quote: bool, + pub allow_quote: bool, + pub allow_asm: bool, + pub allow_log_syntax: bool, + pub allow_concat_idents: bool, + pub allow_trace_macros: bool, pub old_orphan_check: bool, pub simd_ffi: bool, pub unmarked_api: bool, @@ -173,7 +315,11 @@ impl Features { unboxed_closures: false, rustc_diagnostic_macros: false, visible_private_types: false, - quote: false, + allow_quote: false, + allow_asm: false, + allow_log_syntax: false, + allow_concat_idents: false, + allow_trace_macros: false, old_orphan_check: false, simd_ffi: false, unmarked_api: false, @@ -222,6 +368,18 @@ pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: } } +pub const EXPLAIN_ASM: &'static str = + "inline assembly is not stable enough for use and is subject to change"; + +pub const EXPLAIN_LOG_SYNTAX: &'static str = + "`log_syntax!` is not stable enough for use and is subject to change"; + +pub const EXPLAIN_CONCAT_IDENTS: &'static str = + "`concat_idents` is not stable enough for use and is subject to change"; + +pub const EXPLAIN_TRACE_MACROS: &'static str = + "`trace_macros` is not stable enough for use and is subject to change"; + struct MacroVisitor<'a> { context: &'a Context<'a> } @@ -231,24 +389,28 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { let ast::MacInvocTT(ref path, _, _) = mac.node; let id = path.segments.last().unwrap().identifier; + // Issue 22234: If you add a new case here, make sure to also + // add code to catch the macro during or after expansion. + // + // We still keep this MacroVisitor (rather than *solely* + // relying on catching cases during or after expansion) to + // catch uses of these macros within conditionally-compiled + // code, e.g. `#[cfg]`-guarded functions. + if id == token::str_to_ident("asm") { - self.context.gate_feature("asm", path.span, "inline assembly is not \ - stable enough for use and is subject to change"); + self.context.gate_feature("asm", path.span, EXPLAIN_ASM); } else if id == token::str_to_ident("log_syntax") { - self.context.gate_feature("log_syntax", path.span, "`log_syntax!` is not \ - stable enough for use and is subject to change"); + self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX); } else if id == token::str_to_ident("trace_macros") { - self.context.gate_feature("trace_macros", path.span, "`trace_macros` is not \ - stable enough for use and is subject to change"); + self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS); } else if id == token::str_to_ident("concat_idents") { - self.context.gate_feature("concat_idents", path.span, "`concat_idents` is not \ - stable enough for use and is subject to change"); + self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS); } } } @@ -274,22 +436,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_item(&mut self, i: &ast::Item) { - for attr in &i.attrs { - if attr.name() == "thread_local" { - self.gate_feature("thread_local", i.span, - "`#[thread_local]` is an experimental feature, and does not \ - currently handle destructors. There is no corresponding \ - `#[task_local]` mapping to the task model"); - } else if attr.name() == "linkage" { - self.gate_feature("linkage", i.span, - "the `linkage` attribute is experimental \ - and not portable across platforms") - } else if attr.name() == "rustc_on_unimplemented" { - self.gate_feature("on_unimplemented", i.span, - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature") - } - } match i.node { ast::ItemExternCrate(_) => { if attr::contains_name(&i.attrs[], "macro_reexport") { @@ -463,30 +609,27 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_attribute(&mut self, attr: &ast::Attribute) { - if attr.check_name("staged_api") { - self.gate_feature("staged_api", attr.span, - "staged_api is for use by rustc only"); - } else if attr.check_name("plugin") { - self.gate_feature("plugin", attr.span, - "compiler plugins are experimental \ - and possibly buggy"); - } - - if attr::contains_name(slice::ref_slice(attr), "lang") { - self.gate_feature("lang_items", - attr.span, - "language items are subject to change"); - } - - if attr.check_name("no_std") { - self.gate_feature("no_std", attr.span, - "no_std is experimental"); + let name = &*attr.name(); + for &(n, ty) in KNOWN_ATTRIBUTES { + if n == name { + if let Gated(gate, desc) = ty { + self.gate_feature(gate, attr.span, desc); + } + return; + } } - - if attr.check_name("unsafe_no_drop_flag") { - self.gate_feature("unsafe_no_drop_flag", attr.span, - "unsafe_no_drop_flag has unstable semantics \ - and may be removed in the future"); + if name.starts_with("rustc_") { + self.gate_feature("rustc_attrs", attr.span, + "unless otherwise specified, attributes \ + with the prefix `rustc_` \ + are reserved for internal compiler diagnostics"); + } else { + self.gate_feature("custom_attribute", attr.span, + format!("The attribute `{}` is currently \ + unknown to the the compiler and \ + may have meaning \ + added to it in the future", + name).as_slice()); } } @@ -591,11 +734,18 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C check(&mut cx, krate); + // FIXME (pnkfelix): Before adding the 99th entry below, change it + // to a single-pass (instead of N calls to `.has_feature`). + Features { unboxed_closures: cx.has_feature("unboxed_closures"), rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"), visible_private_types: cx.has_feature("visible_private_types"), - quote: cx.has_feature("quote"), + allow_quote: cx.has_feature("quote"), + allow_asm: cx.has_feature("asm"), + allow_log_syntax: cx.has_feature("log_syntax"), + allow_concat_idents: cx.has_feature("concat_idents"), + allow_trace_macros: cx.has_feature("trace_macros"), old_orphan_check: cx.has_feature("old_orphan_check"), simd_ffi: cx.has_feature("simd_ffi"), unmarked_api: cx.has_feature("unmarked_api"), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index f4b0c867f42c6..e8bdcd62b588b 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -30,9 +30,9 @@ #![feature(env)] #![feature(hash)] #![feature(int_uint)] -#![feature(io)] +#![feature(old_io)] #![feature(libc)] -#![feature(path)] +#![feature(old_path)] #![feature(quote, unsafe_destructor)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 583095e157427..4b021f2434f05 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2761,15 +2761,13 @@ impl<'a> State<'a> { ast::LitStr(ref st, style) => self.print_string(&st, style), ast::LitByte(byte) => { let mut res = String::from_str("b'"); - ascii::escape_default(byte, |c| res.push(c as char)); + res.extend(ascii::escape_default(byte).map(|c| c as char)); res.push('\''); word(&mut self.s, &res[]) } ast::LitChar(ch) => { let mut res = String::from_str("'"); - for c in ch.escape_default() { - res.push(c); - } + res.extend(ch.escape_default()); res.push('\''); word(&mut self.s, &res[]) } @@ -2809,8 +2807,8 @@ impl<'a> State<'a> { ast::LitBinary(ref v) => { let mut escaped: String = String::new(); for &ch in &**v { - ascii::escape_default(ch as u8, - |ch| escaped.push(ch as char)); + escaped.extend(ascii::escape_default(ch as u8) + .map(|c| c as char)); } word(&mut self.s, &format!("b\"{}\"", escaped)[]) } diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index c4b3d2813afe4..304f370a1993e 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -54,12 +54,12 @@ #![feature(box_syntax)] #![feature(collections)] #![feature(int_uint)] -#![feature(io)] -#![feature(path)] +#![feature(old_io)] +#![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(std_misc)] #![feature(unicode)] +#![feature(std_misc)] #![feature(env)] #![cfg_attr(windows, feature(libc))] diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs index 758191a6e1107..b978d2d8054e5 100644 --- a/src/libterm/terminfo/mod.rs +++ b/src/libterm/terminfo/mod.rs @@ -72,7 +72,7 @@ pub struct TerminfoTerminal { ti: Box } -impl Terminal for TerminfoTerminal { +impl Terminal for TerminfoTerminal { fn fg(&mut self, color: color::Color) -> IoResult { let color = self.dim_if_necessary(color); if self.num_colors > color { @@ -164,11 +164,11 @@ impl Terminal for TerminfoTerminal { fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out } } -impl UnwrappableTerminal for TerminfoTerminal { +impl UnwrappableTerminal for TerminfoTerminal { fn unwrap(self) -> T { self.out } } -impl TerminfoTerminal { +impl TerminfoTerminal { /// Returns `None` whenever the terminal cannot be created for some /// reason. pub fn new(out: T) -> Option+Send+'static>> { @@ -229,4 +229,3 @@ impl Writer for TerminfoTerminal { self.out.flush() } } - diff --git a/src/libterm/win.rs b/src/libterm/win.rs index a56613681c8ca..e93b956dc7c83 100644 --- a/src/libterm/win.rs +++ b/src/libterm/win.rs @@ -86,7 +86,7 @@ fn bits_to_color(bits: u16) -> color::Color { color | (bits & 0x8) // copy the hi-intensity bit } -impl WinConsole { +impl WinConsole { fn apply(&mut self) { let _unused = self.buf.flush(); let mut accum: libc::WORD = 0; @@ -139,7 +139,7 @@ impl Writer for WinConsole { } } -impl Terminal for WinConsole { +impl Terminal for WinConsole { fn fg(&mut self, color: color::Color) -> IoResult { self.foreground = color; self.apply(); @@ -192,6 +192,6 @@ impl Terminal for WinConsole { fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf } } -impl UnwrappableTerminal for WinConsole { +impl UnwrappableTerminal for WinConsole { fn unwrap(self) -> T { self.buf } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 860ce209d451f..2cb30ad9804c6 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -39,8 +39,8 @@ #![feature(env)] #![feature(hash)] #![feature(int_uint)] -#![feature(io)] -#![feature(path)] +#![feature(old_io)] +#![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(std_misc)] @@ -75,7 +75,7 @@ use std::iter::repeat; use std::num::{Float, Int}; use std::env; use std::sync::mpsc::{channel, Sender}; -use std::thread::{self, Thread}; +use std::thread; use std::thunk::{Thunk, Invoke}; use std::time::Duration; @@ -154,7 +154,7 @@ pub enum TestFn { StaticTestFn(fn()), StaticBenchFn(fn(&mut Bencher)), StaticMetricFn(fn(&mut MetricMap)), - DynTestFn(Thunk), + DynTestFn(Thunk<'static>), DynMetricFn(Box Invoke<&'a mut MetricMap>+'static>), DynBenchFn(Box) } @@ -878,8 +878,8 @@ pub fn run_test(opts: &TestOpts, fn run_test_inner(desc: TestDesc, monitor_ch: Sender, nocapture: bool, - testfn: Thunk) { - Thread::spawn(move || { + testfn: Thunk<'static>) { + thread::spawn(move || { let (tx, rx) = channel(); let mut reader = ChanReader::new(rx); let stdout = ChanWriter::new(tx.clone()); @@ -895,7 +895,7 @@ pub fn run_test(opts: &TestOpts, cfg = cfg.stderr(box stderr as Box); } - let result_guard = cfg.scoped(move || { testfn.invoke(()) }); + let result_guard = cfg.spawn(move || { testfn.invoke(()) }).unwrap(); let stdout = reader.read_to_end().unwrap().into_iter().collect(); let test_result = calc_result(&desc, result_guard.join()); monitor_ch.send((desc.clone(), test_result, stdout)).unwrap(); diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs index 89b310d494971..791886be1ce5b 100644 --- a/src/libunicode/lib.rs +++ b/src/libunicode/lib.rs @@ -77,16 +77,3 @@ pub mod str { pub use u_str::{utf8_char_width, is_utf16, Utf16Items, Utf16Item}; pub use u_str::{utf16_items, Utf16Encoder}; } - -// NOTE: remove after next snapshot -// this lets us use #[derive(..)] -#[cfg(stage0)] -mod std { - pub use core::clone; - pub use core::cmp; - pub use core::fmt; - pub use core::marker; - // for-loops - pub use core::iter; - pub use core::option; -} diff --git a/src/llvm b/src/llvm index 4891e6382e3e8..2089cab13e7f9 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 4891e6382e3e8aa89d530aa18427836428c47157 +Subproject commit 2089cab13e7f92b487ba0dc1df9f6c05116b004a diff --git a/src/rustbook/build.rs b/src/rustbook/build.rs index 3c9c4bdedcc87..6f5fc5c1969f0 100644 --- a/src/rustbook/build.rs +++ b/src/rustbook/build.rs @@ -11,6 +11,7 @@ //! Implementation of the `build` subcommand, used to compile a book. use std::os; +use std::env; use std::old_io; use std::old_io::{fs, File, BufferedWriter, TempDir, IoResult}; @@ -80,10 +81,10 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { let out_path = tgt.join(item.path.dirname()); let src; - if os::args().len() < 3 { + if env::args().len() < 3 { src = os::getcwd().unwrap().clone(); } else { - src = Path::new(os::args()[2].clone()); + src = Path::new(env::args().nth(2).unwrap().clone()); } // preprocess the markdown, rerouting markdown references to html references let markdown_data = try!(File::open(&src.join(&item.path)).read_to_string()); @@ -153,16 +154,16 @@ impl Subcommand for Build { let src; let tgt; - if os::args().len() < 3 { + if env::args().len() < 3 { src = cwd.clone(); } else { - src = Path::new(os::args()[2].clone()); + src = Path::new(env::args().nth(2).unwrap().clone()); } - if os::args().len() < 4 { + if env::args().len() < 4 { tgt = cwd.join("_book"); } else { - tgt = Path::new(os::args()[3].clone()); + tgt = Path::new(env::args().nth(3).unwrap().clone()); } try!(fs::mkdir(&tgt, old_io::USER_DIR)); diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs index a8466465f871b..ace57f0ac2c0b 100644 --- a/src/rustbook/main.rs +++ b/src/rustbook/main.rs @@ -11,14 +11,15 @@ #![feature(box_syntax)] #![feature(collections)] #![feature(core)] -#![feature(io)] +#![feature(old_io)] #![feature(os)] -#![feature(path)] +#![feature(env)] +#![feature(old_path)] #![feature(rustdoc)] extern crate rustdoc; -use std::os; +use std::env; use subcommand::Subcommand; use term::Term; @@ -48,7 +49,7 @@ mod javascript; #[cfg(not(test))] // thanks #12327 fn main() { let mut term = Term::new(); - let cmd = os::args(); + let cmd: Vec<_> = env::args().collect(); if cmd.len() <= 1 { help::usage() diff --git a/src/rustbook/term.rs b/src/rustbook/term.rs index b922bf1cdd367..98aa3fca184dc 100644 --- a/src/rustbook/term.rs +++ b/src/rustbook/term.rs @@ -11,7 +11,7 @@ //! An abstraction of the terminal. Eventually, provide color and //! verbosity support. For now, just a wrapper around stdout/stderr. -use std::os; +use std::env; use std::old_io::stdio; pub struct Term { @@ -28,6 +28,6 @@ impl Term { pub fn err(&mut self, msg: &str) { // swallow any errors let _ = self.err.write_line(msg); - os::set_exit_status(101); + env::set_exit_status(101); } } diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 6bb6f1ad2c7e8..1317343712430 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2015-02-12 +2015-02-13 diff --git a/src/snapshots.txt b/src/snapshots.txt index 56948ea1219ea..4759c44259d52 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,12 @@ +S 2015-02-17 f1bb6c2 + freebsd-x86_64 59f3a2c6350c170804fb65838e1b504eeab89105 + linux-i386 191ed5ec4f17e32d36abeade55a1c6085e51245c + linux-x86_64 acec86045632f4f3f085c072ba696f889906dffe + macos-i386 9d9e622584bfa318f32bcb5b9ce6a365febff595 + macos-x86_64 e96c1e9860b186507cc75c186d1b96d44df12292 + winnt-i386 3f43e0e71311636f9143ad6f2ee7a514e9fa3f8e + winnt-x86_64 26ef3d9098ea346e5ff8945d5b224bb10c24341d + S 2015-02-04 ac134f7 freebsd-x86_64 483e37a02a7ebc12a872e3146145e342ba4a5c04 linux-i386 8af64e5df839cc945399484380a8b2ebe05a6751 diff --git a/src/test/auxiliary/cci_capture_clause.rs b/src/test/auxiliary/cci_capture_clause.rs index 673c38697b79c..b38e955231e4a 100644 --- a/src/test/auxiliary/cci_capture_clause.rs +++ b/src/test/auxiliary/cci_capture_clause.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::thread::Thread; +use std::thread; use std::sync::mpsc::{Receiver, channel}; -pub fn foo(x: T) -> Receiver { +pub fn foo(x: T) -> Receiver { let (tx, rx) = channel(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(x.clone()); }); rx diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index 7ac3925fb2476..01b2b748ba9d8 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -64,16 +64,6 @@ impl MethodTester { pub fn method_stable(&self) {} #[stable(feature = "rust1", since = "1.0.0", reason = "text")] pub fn method_stable_text(&self) {} - - #[locked] - pub fn method_locked(&self) {} - #[locked="text"] - pub fn method_locked_text(&self) {} - - #[frozen] - pub fn method_frozen(&self) {} - #[frozen="text"] - pub fn method_frozen_text(&self) {} } #[stable(feature = "test_feature", since = "1.0.0")] @@ -101,16 +91,6 @@ pub trait Trait { fn trait_stable(&self) {} #[stable(feature = "rust1", since = "1.0.0", reason = "text")] fn trait_stable_text(&self) {} - - #[locked] - fn trait_locked(&self) {} - #[locked="text"] - fn trait_locked_text(&self) {} - - #[frozen] - fn trait_frozen(&self) {} - #[frozen="text"] - fn trait_frozen_text(&self) {} } impl Trait for MethodTester {} diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 12c95e4c60c64..4909d84a34f12 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -11,7 +11,7 @@ #![feature(unboxed_closures)] use std::collections::{BTreeMap, HashMap, HashSet}; -use std::os; +use std::env; use std::rand::{Rng, IsaacRng, SeedableRng}; use std::time::Duration; @@ -20,33 +20,33 @@ fn timed(label: &str, f: F) where F: FnMut() { } trait MutableMap { - fn insert(&mut self, k: uint, v: uint); - fn remove(&mut self, k: &uint) -> bool; - fn find(&self, k: &uint) -> Option<&uint>; + fn insert(&mut self, k: usize, v: usize); + fn remove(&mut self, k: &usize) -> bool; + fn find(&self, k: &usize) -> Option<&usize>; } -impl MutableMap for BTreeMap { - fn insert(&mut self, k: uint, v: uint) { self.insert(k, v); } - fn remove(&mut self, k: &uint) -> bool { self.remove(k).is_some() } - fn find(&self, k: &uint) -> Option<&uint> { self.get(k) } +impl MutableMap for BTreeMap { + fn insert(&mut self, k: usize, v: usize) { self.insert(k, v); } + fn remove(&mut self, k: &usize) -> bool { self.remove(k).is_some() } + fn find(&self, k: &usize) -> Option<&usize> { self.get(k) } } -impl MutableMap for HashMap { - fn insert(&mut self, k: uint, v: uint) { self.insert(k, v); } - fn remove(&mut self, k: &uint) -> bool { self.remove(k).is_some() } - fn find(&self, k: &uint) -> Option<&uint> { self.get(k) } +impl MutableMap for HashMap { + fn insert(&mut self, k: usize, v: usize) { self.insert(k, v); } + fn remove(&mut self, k: &usize) -> bool { self.remove(k).is_some() } + fn find(&self, k: &usize) -> Option<&usize> { self.get(k) } } -fn ascending(map: &mut M, n_keys: uint) { +fn ascending(map: &mut M, n_keys: usize) { println!(" Ascending integers:"); timed("insert", || { - for i in 0u..n_keys { + for i in 0..n_keys { map.insert(i, i + 1); } }); timed("search", || { - for i in 0u..n_keys { + for i in 0..n_keys { assert_eq!(map.find(&i).unwrap(), &(i + 1)); } }); @@ -58,7 +58,7 @@ fn ascending(map: &mut M, n_keys: uint) { }); } -fn descending(map: &mut M, n_keys: uint) { +fn descending(map: &mut M, n_keys: usize) { println!(" Descending integers:"); timed("insert", || { @@ -80,32 +80,31 @@ fn descending(map: &mut M, n_keys: uint) { }); } -fn vector(map: &mut M, n_keys: uint, dist: &[uint]) { +fn vector(map: &mut M, n_keys: usize, dist: &[usize]) { timed("insert", || { - for i in 0u..n_keys { + for i in 0..n_keys { map.insert(dist[i], i + 1); } }); timed("search", || { - for i in 0u..n_keys { + for i in 0..n_keys { assert_eq!(map.find(&dist[i]).unwrap(), &(i + 1)); } }); timed("remove", || { - for i in 0u..n_keys { + for i in 0..n_keys { assert!(map.remove(&dist[i])); } }); } fn main() { - let args = os::args(); - let args = args; + let mut args = env::args(); let n_keys = { if args.len() == 2 { - args[1].parse::().unwrap() + args.nth(1).unwrap().parse::().unwrap() } else { 1000000 } @@ -131,18 +130,18 @@ fn main() { println!("{}", "\nBTreeMap:"); { - let mut map: BTreeMap = BTreeMap::new(); + let mut map: BTreeMap = BTreeMap::new(); ascending(&mut map, n_keys); } { - let mut map: BTreeMap = BTreeMap::new(); + let mut map: BTreeMap = BTreeMap::new(); descending(&mut map, n_keys); } { println!(" Random integers:"); - let mut map: BTreeMap = BTreeMap::new(); + let mut map: BTreeMap = BTreeMap::new(); vector(&mut map, n_keys, &rand); } @@ -150,18 +149,18 @@ fn main() { println!("{}", "\nHashMap:"); { - let mut map: HashMap = HashMap::new(); + let mut map: HashMap = HashMap::new(); ascending(&mut map, n_keys); } { - let mut map: HashMap = HashMap::new(); + let mut map: HashMap = HashMap::new(); descending(&mut map, n_keys); } { println!(" Random integers:"); - let mut map: HashMap = HashMap::new(); + let mut map: HashMap = HashMap::new(); vector(&mut map, n_keys, &rand); } } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 33ac8a43b437b..1d440c4540ca3 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -20,7 +20,7 @@ use std::collections::BitvSet; use std::collections::HashSet; use std::collections::hash_map::Hasher; use std::hash::Hash; -use std::os; +use std::env; use std::time::Duration; struct Results { @@ -53,29 +53,29 @@ impl MutableSet for BTreeSet { fn remove(&mut self, k: &T) -> bool { self.remove(k) } fn contains(&self, k: &T) -> bool { self.contains(k) } } -impl MutableSet for BitvSet { - fn insert(&mut self, k: uint) { self.insert(k); } - fn remove(&mut self, k: &uint) -> bool { self.remove(k) } - fn contains(&self, k: &uint) -> bool { self.contains(k) } +impl MutableSet for BitvSet { + fn insert(&mut self, k: usize) { self.insert(k); } + fn remove(&mut self, k: &usize) -> bool { self.remove(k) } + fn contains(&self, k: &usize) -> bool { self.contains(k) } } impl Results { - pub fn bench_int, + pub fn bench_int, R:rand::Rng, F:FnMut() -> T>( &mut self, rng: &mut R, - num_keys: uint, - rand_cap: uint, + num_keys: usize, + rand_cap: usize, mut f: F) { { let mut set = f(); timed(&mut self.sequential_ints, || { - for i in 0u..num_keys { + for i in 0..num_keys { set.insert(i); } - for i in 0u..num_keys { + for i in 0..num_keys { assert!(set.contains(&i)); } }) @@ -85,19 +85,19 @@ impl Results { let mut set = f(); timed(&mut self.random_ints, || { for _ in 0..num_keys { - set.insert(rng.gen::() % rand_cap); + set.insert(rng.gen::() % rand_cap); } }) } { let mut set = f(); - for i in 0u..num_keys { + for i in 0..num_keys { set.insert(i); } timed(&mut self.delete_ints, || { - for i in 0u..num_keys { + for i in 0..num_keys { assert!(set.remove(&i)); } }) @@ -109,16 +109,16 @@ impl Results { F:FnMut() -> T>( &mut self, rng: &mut R, - num_keys: uint, + num_keys: usize, mut f: F) { { let mut set = f(); timed(&mut self.sequential_strings, || { - for i in 0u..num_keys { + for i in 0..num_keys { set.insert(i.to_string()); } - for i in 0u..num_keys { + for i in 0..num_keys { assert!(set.contains(&i.to_string())); } }) @@ -128,7 +128,7 @@ impl Results { let mut set = f(); timed(&mut self.random_strings, || { for _ in 0..num_keys { - let s = rng.gen::().to_string(); + let s = rng.gen::().to_string(); set.insert(s); } }) @@ -136,11 +136,11 @@ impl Results { { let mut set = f(); - for i in 0u..num_keys { + for i in 0..num_keys { set.insert(i.to_string()); } timed(&mut self.delete_strings, || { - for i in 0u..num_keys { + for i in 0..num_keys { assert!(set.remove(&i.to_string())); } }) @@ -179,11 +179,10 @@ fn empty_results() -> Results { } fn main() { - let args = os::args(); - let args = args; + let mut args = env::args(); let num_keys = { if args.len() == 2 { - args[1].parse::().unwrap() + args.nth(1).unwrap().parse::().unwrap() } else { 100 // woefully inadequate for any real measurement } @@ -196,7 +195,7 @@ fn main() { let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed); let mut results = empty_results(); results.bench_int(&mut rng, num_keys, max, || { - let s: HashSet = HashSet::new(); + let s: HashSet = HashSet::new(); s }); results.bench_str(&mut rng, num_keys, || { @@ -210,7 +209,7 @@ fn main() { let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed); let mut results = empty_results(); results.bench_int(&mut rng, num_keys, max, || { - let s: BTreeSet = BTreeSet::new(); + let s: BTreeSet = BTreeSet::new(); s }); results.bench_str(&mut rng, num_keys, || { diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 00f8feacff8ca..2409487c04fc1 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -16,7 +16,6 @@ use std::old_io::File; use std::iter::repeat; use std::mem::swap; -use std::os; use std::env; use std::rand::Rng; use std::rand; @@ -25,8 +24,7 @@ use std::time::Duration; use std::vec; fn main() { - let argv = os::args(); - let _tests = &argv[1..argv.len()]; + let argv: Vec = env::args().collect(); macro_rules! bench { ($id:ident) => diff --git a/src/test/bench/core-uint-to-str.rs b/src/test/bench/core-uint-to-str.rs index 90cc222c3deba..57889053e3c1b 100644 --- a/src/test/bench/core-uint-to-str.rs +++ b/src/test/bench/core-uint-to-str.rs @@ -8,17 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::os; use std::env; fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "10000000".to_string()) } else if args.len() <= 1u { vec!("".to_string(), "100000".to_string()) } else { - args.into_iter().collect() + args.collect() }; let n = args[1].parse().unwrap(); diff --git a/src/test/bench/msgsend-pipes-shared.rs b/src/test/bench/msgsend-pipes-shared.rs index 4e9c2fe99bd4a..208f088442b9b 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -19,9 +19,8 @@ // version. use std::sync::mpsc::{channel, Sender, Receiver}; -use std::os; use std::env; -use std::thread::Thread; +use std::thread; use std::time::Duration; fn move_out(_x: T) {} @@ -64,7 +63,7 @@ fn run(args: &[String]) { let mut worker_results = Vec::new(); for _ in 0u..workers { let to_child = to_child.clone(); - worker_results.push(Thread::scoped(move|| { + worker_results.push(thread::spawn(move|| { for _ in 0u..size / workers { //println!("worker {}: sending {} bytes", i, num_bytes); to_child.send(request::bytes(num_bytes)).unwrap(); @@ -72,7 +71,7 @@ fn run(args: &[String]) { //println!("worker {} exiting", i); })); } - Thread::spawn(move|| { + thread::spawn(move|| { server(&from_parent, &to_parent); }); @@ -94,13 +93,13 @@ fn run(args: &[String]) { } fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "1000000".to_string(), "10000".to_string()) - } else if args.len() <= 1u { + } else if args.len() <= 1 { vec!("".to_string(), "10000".to_string(), "4".to_string()) } else { - args.into_iter().map(|x| x.to_string()).collect() + args.map(|x| x.to_string()).collect() }; println!("{:?}", args); diff --git a/src/test/bench/msgsend-pipes.rs b/src/test/bench/msgsend-pipes.rs index 2530e8bd90707..76b91f0295bb5 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -15,9 +15,8 @@ // I *think* it's the same, more or less. use std::sync::mpsc::{channel, Sender, Receiver}; -use std::os; use std::env; -use std::thread::Thread; +use std::thread; use std::time::Duration; enum request { @@ -57,7 +56,7 @@ fn run(args: &[String]) { let mut worker_results = Vec::new(); let from_parent = if workers == 1 { let (to_child, from_parent) = channel(); - worker_results.push(Thread::scoped(move|| { + worker_results.push(thread::spawn(move|| { for _ in 0u..size / workers { //println!("worker {}: sending {} bytes", i, num_bytes); to_child.send(request::bytes(num_bytes)); @@ -69,7 +68,7 @@ fn run(args: &[String]) { let (to_child, from_parent) = channel(); for _ in 0u..workers { let to_child = to_child.clone(); - worker_results.push(Thread::scoped(move|| { + worker_results.push(thread::spawn(move|| { for _ in 0u..size / workers { //println!("worker {}: sending {} bytes", i, num_bytes); to_child.send(request::bytes(num_bytes)); @@ -79,7 +78,7 @@ fn run(args: &[String]) { } from_parent }; - Thread::spawn(move|| { + thread::spawn(move|| { server(&from_parent, &to_parent); }); @@ -101,13 +100,13 @@ fn run(args: &[String]) { } fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "1000000".to_string(), "8".to_string()) - } else if args.len() <= 1u { + } else if args.len() <= 1 { vec!("".to_string(), "10000".to_string(), "4".to_string()) } else { - args.clone().into_iter().map(|x| x.to_string()).collect() + args.map(|x| x.to_string()).collect() }; println!("{:?}", args); diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index a935a6b308646..168fe929e1254 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -18,7 +18,6 @@ // no-pretty-expanded FIXME #15189 // ignore-lexer-test FIXME #15679 -use std::os; use std::env; use std::sync::{Arc, Future, Mutex, Condvar}; use std::time::Duration; @@ -64,13 +63,13 @@ fn thread_ring(i: uint, count: uint, num_chan: pipe, num_port: pipe) { } fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "100".to_string(), "10000".to_string()) - } else if args.len() <= 1u { + } else if args.len() <= 1 { vec!("".to_string(), "10".to_string(), "100".to_string()) } else { - args.clone().into_iter().collect() + args.collect() }; let num_tasks = args[1].parse::().unwrap(); diff --git a/src/test/bench/rt-messaging-ping-pong.rs b/src/test/bench/rt-messaging-ping-pong.rs index e4e8b4a6e6e1e..b9512324e42d6 100644 --- a/src/test/bench/rt-messaging-ping-pong.rs +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -18,24 +18,24 @@ // except according to those terms. use std::sync::mpsc::channel; -use std::os; -use std::thread::Thread; +use std::env; +use std::thread; // This is a simple bench that creates M pairs of tasks. These // tasks ping-pong back and forth over a pair of streams. This is a // canonical message-passing benchmark as it heavily strains message // passing and almost nothing else. -fn ping_pong_bench(n: uint, m: uint) { +fn ping_pong_bench(n: usize, m: usize) { // Create pairs of tasks that pingpong back and forth. - fn run_pair(n: uint) { + fn run_pair(n: usize) { // Create a channel: A->B let (atx, arx) = channel(); // Create a channel: B->A let (btx, brx) = channel(); - let guard_a = Thread::scoped(move|| { + let guard_a = thread::spawn(move|| { let (tx, rx) = (atx, brx); for _ in 0..n { tx.send(()).unwrap(); @@ -43,7 +43,7 @@ fn ping_pong_bench(n: uint, m: uint) { } }); - let guard_b = Thread::scoped(move|| { + let guard_b = thread::spawn(move|| { let (tx, rx) = (btx, arx); for _ in 0..n { rx.recv().unwrap(); @@ -63,19 +63,13 @@ fn ping_pong_bench(n: uint, m: uint) { fn main() { - - let args = os::args(); - let args = args; - let n = if args.len() == 3 { - args[1].parse::().unwrap() - } else { - 10000 - }; - - let m = if args.len() == 3 { - args[2].parse::().unwrap() + let mut args = env::args(); + let (n, m) = if args.len() == 3 { + let n = args.nth(1).unwrap().parse::().unwrap(); + let m = args.next().unwrap().parse::().unwrap(); + (n, m) } else { - 4 + (10000, 4) }; ping_pong_bench(n, m); diff --git a/src/test/bench/rt-parfib.rs b/src/test/bench/rt-parfib.rs index 13b8a5ca763ad..d420023cf0059 100644 --- a/src/test/bench/rt-parfib.rs +++ b/src/test/bench/rt-parfib.rs @@ -9,20 +9,20 @@ // except according to those terms. use std::sync::mpsc::channel; -use std::os; -use std::thread::Thread; +use std::env; +use std::thread; // A simple implementation of parfib. One subtree is found in a new // task and communicated over a oneshot pipe, the other is found // locally. There is no sequential-mode threshold. -fn parfib(n: uint) -> uint { +fn parfib(n: u64) -> u64 { if n == 0 || n == 1 { return 1; } let (tx, rx) = channel(); - Thread::spawn(move|| { + thread::spawn(move|| { tx.send(parfib(n-1)).unwrap(); }); let m2 = parfib(n-2); @@ -30,11 +30,9 @@ fn parfib(n: uint) -> uint { } fn main() { - - let args = os::args(); - let args = args; + let mut args = env::args(); let n = if args.len() == 2 { - args[1].parse::().unwrap() + args.nth(1).unwrap().parse::().unwrap() } else { 10 }; diff --git a/src/test/bench/shootout-ackermann.rs b/src/test/bench/shootout-ackermann.rs index 933c1c218c376..d07aa8850aa83 100644 --- a/src/test/bench/shootout-ackermann.rs +++ b/src/test/bench/shootout-ackermann.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::os; use std::env; -fn ack(m: int, n: int) -> int { +fn ack(m: i64, n: i64) -> i64 { if m == 0 { return n + 1 } else { @@ -24,13 +23,13 @@ fn ack(m: int, n: int) -> int { } fn main() { - let args = os::args(); + let mut args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "12".to_string()) - } else if args.len() <= 1u { + } else if args.len() <= 1 { vec!("".to_string(), "8".to_string()) } else { - args.into_iter().collect() + args.collect() }; let n = args[1].parse().unwrap(); println!("Ack(3,{}): {}\n", n, ack(3, n)); diff --git a/src/test/bench/shootout-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index 0311a1ac7c4e1..1e23da3020f27 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -41,7 +41,7 @@ extern crate arena; use std::iter::range_step; -use std::thread::{Thread, JoinGuard}; +use std::thread; use arena::TypedArena; struct Tree<'a> { @@ -84,14 +84,13 @@ fn inner(depth: i32, iterations: i32) -> String { } fn main() { - let args = std::os::args(); - let args = args; + let mut args = std::env::args(); let n = if std::env::var_os("RUST_BENCH").is_some() { 17 - } else if args.len() <= 1u { + } else if args.len() <= 1 { 8 } else { - args[1].parse().unwrap() + args.nth(1).unwrap().parse().unwrap() }; let min_depth = 4; let max_depth = if min_depth + 2 > n {min_depth + 2} else {n}; @@ -111,11 +110,11 @@ fn main() { let messages = range_step(min_depth, max_depth + 1, 2).map(|depth| { use std::num::Int; let iterations = 2.pow((max_depth - depth + min_depth) as usize); - Thread::scoped(move || inner(depth, iterations)) + thread::scoped(move || inner(depth, iterations)) }).collect::>(); for message in messages { - println!("{}", message.join().ok().unwrap()); + println!("{}", message.join()); } println!("long lived tree of depth {}\t check: {}", diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 628206986c518..5bd1e91ae14e4 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -43,7 +43,7 @@ use self::Color::{Red, Yellow, Blue}; use std::sync::mpsc::{channel, Sender, Receiver}; use std::fmt; -use std::thread::Thread; +use std::thread; fn print_complements() { let all = [Blue, Red, Yellow]; @@ -187,7 +187,7 @@ fn rendezvous(nn: uint, set: Vec) { let to_rendezvous = to_rendezvous.clone(); let to_rendezvous_log = to_rendezvous_log.clone(); let (to_creature, from_rendezvous) = channel(); - Thread::spawn(move|| { + thread::spawn(move|| { creature(ii, col, from_rendezvous, @@ -230,10 +230,10 @@ fn main() { let nn = if std::env::var_os("RUST_BENCH").is_some() { 200000 } else { - std::os::args() - .get(1) + std::env::args() + .nth(1) .and_then(|arg| arg.parse().ok()) - .unwrap_or(600u) + .unwrap_or(600us) }; print_complements(); diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index 92e1bc1a922c2..f7de935d08fdd 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -39,7 +39,7 @@ // OF THE POSSIBILITY OF SUCH DAMAGE. use std::{cmp, iter, mem}; -use std::thread::Thread; +use std::thread; fn rotate(x: &mut [i32]) { let mut prev = x[0]; @@ -164,7 +164,7 @@ fn fannkuch(n: i32) -> (i32, i32) { for (_, j) in (0..N).zip(iter::count(0, k)) { let max = cmp::min(j+k, perm.max()); - futures.push(Thread::scoped(move|| { + futures.push(thread::scoped(move|| { work(perm, j as uint, max as uint) })) } @@ -172,7 +172,7 @@ fn fannkuch(n: i32) -> (i32, i32) { let mut checksum = 0; let mut maxflips = 0; for fut in futures { - let (cs, mf) = fut.join().ok().unwrap(); + let (cs, mf) = fut.join(); checksum += cs; maxflips = cmp::max(maxflips, mf); } @@ -180,8 +180,8 @@ fn fannkuch(n: i32) -> (i32, i32) { } fn main() { - let n = std::os::args() - .get(1) + let n = std::env::args() + .nth(1) .and_then(|arg| arg.parse().ok()) .unwrap_or(2i32); diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index d91031b8401f3..277c3ee73dff1 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -41,11 +41,11 @@ use std::cmp::min; use std::old_io::{stdout, IoResult}; use std::iter::repeat; -use std::os; +use std::env; use std::slice::bytes::copy_memory; -const LINE_LEN: uint = 60; -const LOOKUP_SIZE: uint = 4 * 1024; +const LINE_LEN: usize = 60; +const LOOKUP_SIZE: usize = 4 * 1024; const LOOKUP_SCALE: f32 = (LOOKUP_SIZE - 1) as f32; // Random number generator constants @@ -119,7 +119,7 @@ impl<'a, W: Writer> RepeatFasta<'a, W> { RepeatFasta { alu: alu, out: w } } - fn make(&mut self, n: uint) -> IoResult<()> { + fn make(&mut self, n: usize) -> IoResult<()> { let alu_len = self.alu.len(); let mut buf = repeat(0u8).take(alu_len + LINE_LEN).collect::>(); let alu: &[u8] = self.alu.as_bytes(); @@ -188,19 +188,19 @@ impl<'a, W: Writer> RandomFasta<'a, W> { 0 } - fn make(&mut self, n: uint) -> IoResult<()> { + fn make(&mut self, n: usize) -> IoResult<()> { let lines = n / LINE_LEN; let chars_left = n % LINE_LEN; let mut buf = [0;LINE_LEN + 1]; for _ in 0..lines { - for i in 0u..LINE_LEN { + for i in 0..LINE_LEN { buf[i] = self.nextc(); } buf[LINE_LEN] = '\n' as u8; try!(self.out.write(&buf)); } - for i in 0u..chars_left { + for i in 0..chars_left { buf[i] = self.nextc(); } self.out.write(&buf[..chars_left]) @@ -208,10 +208,9 @@ impl<'a, W: Writer> RandomFasta<'a, W> { } fn main() { - let args = os::args(); - let args = args; + let mut args = env::args(); let n = if args.len() > 1 { - args[1].parse::().unwrap() + args.nth(1).unwrap().parse::().unwrap() } else { 5 }; diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 5bf0862e0a1d6..fd559608011af 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -42,10 +42,9 @@ use std::cmp::min; use std::old_io::{BufferedWriter, File}; use std::old_io; use std::num::Float; -use std::os; use std::env; -const LINE_LENGTH: uint = 60; +const LINE_LENGTH: usize = 60; const IM: u32 = 139968; struct MyRandom { @@ -86,7 +85,7 @@ impl<'a> Iterator for AAGen<'a> { } fn make_fasta>( - wr: &mut W, header: &str, mut it: I, mut n: uint) + wr: &mut W, header: &str, mut it: I, mut n: usize) -> std::old_io::IoResult<()> { try!(wr.write(header.as_bytes())); @@ -104,14 +103,13 @@ fn make_fasta>( } fn run(writer: &mut W) -> std::old_io::IoResult<()> { - let args = os::args(); - let args = args; + let mut args = env::args(); let n = if env::var_os("RUST_BENCH").is_some() { 25000000 - } else if args.len() <= 1u { + } else if args.len() <= 1 { 1000 } else { - args[1].parse().unwrap() + args.nth(1).unwrap().parse().unwrap() }; let rng = &mut MyRandom::new(); diff --git a/src/test/bench/shootout-fibo.rs b/src/test/bench/shootout-fibo.rs index 6a062ba3980d6..6f9c775609af5 100644 --- a/src/test/bench/shootout-fibo.rs +++ b/src/test/bench/shootout-fibo.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::os; use std::env; -fn fib(n: int) -> int { +fn fib(n: i64) -> i64 { if n < 2 { return 1; } else { @@ -20,13 +19,13 @@ fn fib(n: int) -> int { } fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "40".to_string()) - } else if args.len() <= 1u { + } else if args.len() <= 1 { vec!("".to_string(), "30".to_string()) } else { - args.into_iter().collect() + args.collect() }; let n = args[1].parse().unwrap(); println!("{}\n", fib(n)); diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 3c96878179f3a..4d6ef3d533e3f 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -24,7 +24,7 @@ use std::option; use std::os; use std::env; use std::sync::mpsc::{channel, Sender, Receiver}; -use std::thread::Thread; +use std::thread; fn f64_cmp(x: f64, y: f64) -> Ordering { // arbitrarily decide that NaNs are larger than everything. @@ -172,7 +172,7 @@ fn main() { let (to_child, from_parent) = channel(); - Thread::spawn(move|| { + thread::spawn(move|| { make_sequence_processor(sz, &from_parent, &to_parent_); }); diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index ca920b2fa821c..b5c460737b86c 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -45,7 +45,7 @@ use std::ascii::OwnedAsciiExt; use std::slice; use std::sync::Arc; -use std::thread::Thread; +use std::thread; static TABLE: [u8;4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ]; static TABLE_SIZE: uint = 2 << 16; @@ -303,17 +303,17 @@ fn main() { let nb_freqs: Vec<_> = (1u..3).map(|i| { let input = input.clone(); - (i, Thread::scoped(move|| generate_frequencies(&input, i))) + (i, thread::scoped(move|| generate_frequencies(&input, i))) }).collect(); let occ_freqs: Vec<_> = OCCURRENCES.iter().map(|&occ| { let input = input.clone(); - Thread::scoped(move|| generate_frequencies(&input, occ.len())) + thread::scoped(move|| generate_frequencies(&input, occ.len())) }).collect(); for (i, freq) in nb_freqs { - print_frequencies(&freq.join().ok().unwrap(), i); + print_frequencies(&freq.join(), i); } for (&occ, freq) in OCCURRENCES.iter().zip(occ_freqs.into_iter()) { - print_occurrences(&mut freq.join().ok().unwrap(), occ); + print_occurrences(&mut freq.join(), occ); } } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index e2d51fbf4111d..bddf615322816 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -43,10 +43,10 @@ // ignore-pretty very bad with line comments use std::old_io; -use std::os; +use std::env; use std::simd::f64x2; use std::sync::Arc; -use std::thread::Thread; +use std::thread; const ITER: usize = 50; const LIMIT: f64 = 2.0; @@ -81,7 +81,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { let mut precalc_i = Vec::with_capacity(h); let precalc_futures = (0..WORKERS).map(|i| { - Thread::scoped(move|| { + thread::scoped(move|| { let mut rs = Vec::with_capacity(w / WORKERS); let mut is = Vec::with_capacity(w / WORKERS); @@ -107,7 +107,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { }).collect::>(); for res in precalc_futures { - let (rs, is) = res.join().ok().unwrap(); + let (rs, is) = res.join(); precalc_r.extend(rs.into_iter()); precalc_i.extend(is.into_iter()); } @@ -122,7 +122,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { let vec_init_r = arc_init_r.clone(); let vec_init_i = arc_init_i.clone(); - Thread::scoped(move|| { + thread::scoped(move|| { let mut res: Vec = Vec::with_capacity((chunk_size * w) / 8); let init_r_slice = vec_init_r; @@ -143,7 +143,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h)); for res in data { - try!(out.write(&res.join().ok().unwrap())); + try!(out.write(&res.join())); } out.flush() } @@ -197,13 +197,13 @@ fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec) { } fn main() { - let args = os::args(); + let mut args = env::args(); let res = if args.len() < 2 { println!("Test mode: do not dump the image because it's not utf8, \ which interferes with the test runner."); mandelbrot(1000, old_io::util::NullWriter) } else { - mandelbrot(args[1].parse().unwrap(), old_io::stdout()) + mandelbrot(args.nth(1).unwrap().parse().unwrap(), old_io::stdout()) }; res.unwrap(); } diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs index d061403d5901d..a9c4bb99a0ed1 100644 --- a/src/test/bench/shootout-meteor.rs +++ b/src/test/bench/shootout-meteor.rs @@ -43,7 +43,7 @@ use std::iter::repeat; use std::sync::Arc; use std::sync::mpsc::channel; -use std::thread::Thread; +use std::thread; // // Utilities. @@ -317,7 +317,7 @@ fn par_search(masks: Vec>>) -> Data { let masks = masks.clone(); let tx = tx.clone(); let m = *m; - Thread::spawn(move|| { + thread::spawn(move|| { let mut data = Data::new(); search(&*masks, m, 1, List::Cons(m, &List::Nil), &mut data); tx.send(data).unwrap(); diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 7904657bece28..534dfe9548c2f 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -173,7 +173,7 @@ fn main() { let n = if std::env::var_os("RUST_BENCH").is_some() { 5000000 } else { - std::os::args().get(1) + std::env::args().nth(1) .and_then(|arg| arg.parse().ok()) .unwrap_or(1000) }; diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 9abc808f88770..a542c81f2394e 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -21,14 +21,13 @@ extern crate getopts; use std::sync::mpsc::{channel, Sender}; -use std::os; use std::env; use std::result::Result::{Ok, Err}; -use std::thread::Thread; +use std::thread; use std::time::Duration; -fn fib(n: int) -> int { - fn pfib(tx: &Sender, n: int) { +fn fib(n: isize) -> isize { + fn pfib(tx: &Sender, n: isize) { if n == 0 { tx.send(0).unwrap(); } else if n <= 2 { @@ -36,15 +35,15 @@ fn fib(n: int) -> int { } else { let (tx1, rx) = channel(); let tx2 = tx1.clone(); - Thread::spawn(move|| pfib(&tx2, n - 1)); + thread::spawn(move|| pfib(&tx2, n - 1)); let tx2 = tx1.clone(); - Thread::spawn(move|| pfib(&tx2, n - 2)); + thread::spawn(move|| pfib(&tx2, n - 2)); tx.send(rx.recv().unwrap() + rx.recv().unwrap()); } } let (tx, rx) = channel(); - Thread::spawn(move|| pfib(&tx, n) ); + thread::spawn(move|| pfib(&tx, n) ); rx.recv().unwrap() } @@ -66,7 +65,7 @@ fn parse_opts(argv: Vec ) -> Config { } } -fn stress_task(id: int) { +fn stress_task(id: isize) { let mut i = 0; loop { let n = 15; @@ -79,7 +78,7 @@ fn stress_task(id: int) { fn stress(num_tasks: int) { let mut results = Vec::new(); for i in 0..num_tasks { - results.push(Thread::scoped(move|| { + results.push(thread::spawn(move|| { stress_task(i); })); } @@ -89,13 +88,13 @@ fn stress(num_tasks: int) { } fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "20".to_string()) - } else if args.len() <= 1u { + } else if args.len() <= 1 { vec!("".to_string(), "8".to_string()) } else { - args.into_iter().map(|x| x.to_string()).collect() + args.map(|x| x.to_string()).collect() }; let opts = parse_opts(args.clone()); @@ -103,12 +102,12 @@ fn main() { if opts.stress { stress(2); } else { - let max = args[1].parse::().unwrap(); + let max = args[1].parse::().unwrap(); let num_trials = 10; for n in 1..max + 1 { - for _ in 0u..num_trials { + for _ in 0..num_trials { let mut fibn = None; let dur = Duration::span(|| fibn = Some(fib(n))); let fibn = fibn.unwrap(); diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index 944383199543f..33d959dfe93e3 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -47,7 +47,7 @@ extern crate libc; use std::old_io::stdio::{stdin_raw, stdout_raw}; use std::old_io::{IoResult, EndOfFile}; use std::ptr::{copy_memory, Unique}; -use std::thread::Thread; +use std::thread; struct Tables { table8: [u8;1 << 8], @@ -229,21 +229,12 @@ unsafe impl Send for Racy {} /// Executes a closure in parallel over the given iterator over mutable slice. /// The closure `f` is run in parallel with an element of `iter`. -fn parallel<'a, I, T, F>(iter: I, f: F) - where T: 'a+Send + Sync, - I: Iterator, - F: Fn(&mut [T]) + Sync { - use std::mem; - use std::raw::Repr; - - iter.map(|chunk| { - // Need to convert `f` and `chunk` to something that can cross the task - // boundary. - let f = Racy(&f as *const F as *const uint); - let raw = Racy(chunk.repr()); - Thread::scoped(move|| { - let f = f.0 as *const F; - unsafe { (*f)(mem::transmute(raw.0)) } +fn parallel<'a, I: Iterator, F>(iter: I, ref f: F) + where I::Item: Send + 'a, + F: Fn(I::Item) + Sync + 'a { + iter.map(|x| { + thread::scoped(move|| { + f(x) }) }).collect::>(); } diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index 8356df8d8a184..76ba5acb16ce4 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -44,7 +44,7 @@ #![feature(unboxed_closures)] use std::iter::{repeat, AdditiveIterator}; -use std::thread::Thread; +use std::thread; use std::mem; use std::num::Float; use std::os; @@ -53,13 +53,13 @@ use std::raw::Repr; use std::simd::f64x2; fn main() { - let args = os::args(); + let mut args = env::args(); let answer = spectralnorm(if env::var_os("RUST_BENCH").is_some() { 5500 } else if args.len() < 2 { 2000 } else { - args[1].parse().unwrap() + args.nth(1).unwrap().parse().unwrap() }); println!("{:.9}", answer); } @@ -112,26 +112,16 @@ fn dot(v: &[f64], u: &[f64]) -> f64 { } -struct Racy(T); - -unsafe impl Send for Racy {} - // Executes a closure in parallel over the given mutable slice. The closure `f` // is run in parallel and yielded the starting index within `v` as well as a // sub-slice of `v`. -fn parallel(v: &mut [T], f: F) - where T: Send + Sync, - F: Fn(uint, &mut [T]) + Sync { +fn parallel<'a,T, F>(v: &mut [T], ref f: F) + where T: Send + Sync + 'a, + F: Fn(uint, &mut [T]) + Sync + 'a { let size = v.len() / os::num_cpus() + 1; - v.chunks_mut(size).enumerate().map(|(i, chunk)| { - // Need to convert `f` and `chunk` to something that can cross the task - // boundary. - let f = Racy(&f as *const _ as *const uint); - let raw = Racy(chunk.repr()); - Thread::scoped(move|| { - let f = f.0 as *const F; - unsafe { (*f)(i * size, mem::transmute(raw.0)) } + thread::scoped(move|| { + f(i * size, chunk) }) }).collect::>(); } diff --git a/src/test/bench/shootout-threadring.rs b/src/test/bench/shootout-threadring.rs index 8614f94da89ea..2653e758a487d 100644 --- a/src/test/bench/shootout-threadring.rs +++ b/src/test/bench/shootout-threadring.rs @@ -39,7 +39,7 @@ // OF THE POSSIBILITY OF SUCH DAMAGE. use std::sync::mpsc::{channel, Sender, Receiver}; -use std::thread::Thread; +use std::thread; fn start(n_tasks: i32, token: i32) { let (tx, mut rx) = channel(); @@ -48,9 +48,9 @@ fn start(n_tasks: i32, token: i32) { for i in 2 .. n_tasks + 1 { let (tx, next_rx) = channel(); let cur_rx = std::mem::replace(&mut rx, next_rx); - guards.push(Thread::scoped(move|| roundtrip(i, tx, cur_rx))); + guards.push(thread::spawn(move|| roundtrip(i, tx, cur_rx))); } - let guard = Thread::scoped(move|| roundtrip(1, tx, rx)); + let guard = thread::spawn(move|| roundtrip(1, tx, rx)); } fn roundtrip(id: i32, tx: Sender, rx: Receiver) { @@ -64,13 +64,13 @@ fn roundtrip(id: i32, tx: Sender, rx: Receiver) { } fn main() { - let args = std::os::args(); + let mut args = std::env::args(); let token = if std::env::var_os("RUST_BENCH").is_some() { 2000000 } else { - args.get(1).and_then(|arg| arg.parse().ok()).unwrap_or(1000) + args.nth(1).and_then(|arg| arg.parse().ok()).unwrap_or(1000) }; - let n_tasks = args.get(2) + let n_tasks = args.next() .and_then(|arg| arg.parse().ok()) .unwrap_or(503); diff --git a/src/test/bench/std-smallintmap.rs b/src/test/bench/std-smallintmap.rs index e6948a1371c9e..a54a869412e35 100644 --- a/src/test/bench/std-smallintmap.rs +++ b/src/test/bench/std-smallintmap.rs @@ -11,41 +11,40 @@ // Microbenchmark for the smallintmap library use std::collections::VecMap; -use std::os; use std::env; use std::time::Duration; -fn append_sequential(min: uint, max: uint, map: &mut VecMap) { +fn append_sequential(min: usize, max: usize, map: &mut VecMap) { for i in min..max { - map.insert(i, i + 22u); + map.insert(i, i + 22); } } -fn check_sequential(min: uint, max: uint, map: &VecMap) { +fn check_sequential(min: usize, max: usize, map: &VecMap) { for i in min..max { - assert_eq!(map[i], i + 22u); + assert_eq!(map[i], i + 22); } } fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "100000".to_string(), "100".to_string()) - } else if args.len() <= 1u { + } else if args.len() <= 1 { vec!("".to_string(), "10000".to_string(), "50".to_string()) } else { - args.into_iter().collect() + args.collect() }; - let max = args[1].parse::().unwrap(); - let rep = args[2].parse::().unwrap(); + let max = args[1].parse::().unwrap(); + let rep = args[2].parse::().unwrap(); let mut checkf = Duration::seconds(0); let mut appendf = Duration::seconds(0); - for _ in 0u..rep { + for _ in 0..rep { let mut map = VecMap::new(); - let d1 = Duration::span(|| append_sequential(0u, max, &mut map)); - let d2 = Duration::span(|| check_sequential(0u, max, &map)); + let d1 = Duration::span(|| append_sequential(0, max, &mut map)); + let d2 = Duration::span(|| check_sequential(0, max, &map)); checkf = checkf + d2; appendf = appendf + d1; diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index c5a64db95e6a3..ada8efcbf38e1 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -18,7 +18,7 @@ use std::old_io::stdio::StdReader; use std::old_io; use std::iter::repeat; use std::num::Int; -use std::os; +use std::env; // Computes a single solution to a given 9x9 sudoku // @@ -269,8 +269,8 @@ fn check_DEFAULT_SUDOKU_solution() { } fn main() { - let args = os::args(); - let use_default = args.len() == 1u; + let args = env::args(); + let use_default = args.len() == 1; let mut sudoku = if use_default { Sudoku::from_vec(&DEFAULT_SUDOKU) } else { diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index c45efe5f54b2c..6b412c47cd7f8 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -11,7 +11,7 @@ #![feature(unsafe_destructor, box_syntax)] use std::env; -use std::thread::Thread; +use std::thread; use std::time::Duration; #[derive(Clone)] @@ -32,7 +32,7 @@ fn main() { fn run(repeat: int, depth: int) { for _ in 0..repeat { let dur = Duration::span(|| { - let _ = Thread::scoped(move|| { + let _ = thread::spawn(move|| { recurse_or_panic(depth, None) }).join(); }); diff --git a/src/test/bench/task-perf-jargon-metal-smoke.rs b/src/test/bench/task-perf-jargon-metal-smoke.rs index 9edb4201098d6..e36d685d7c6ea 100644 --- a/src/test/bench/task-perf-jargon-metal-smoke.rs +++ b/src/test/bench/task-perf-jargon-metal-smoke.rs @@ -18,17 +18,16 @@ // ignore-pretty very bad with line comments use std::sync::mpsc::{channel, Sender}; -use std::os; use std::env; -use std::thread::Thread; +use std::thread; fn child_generation(gens_left: uint, tx: Sender<()>) { // This used to be O(n^2) in the number of generations that ever existed. // With this code, only as many generations are alive at a time as tasks // alive at a time, - Thread::spawn(move|| { + thread::spawn(move|| { if gens_left & 1 == 1 { - Thread::yield_now(); // shake things up a bit + thread::yield_now(); // shake things up a bit } if gens_left > 0 { child_generation(gens_left - 1, tx); // recurse @@ -39,13 +38,13 @@ fn child_generation(gens_left: uint, tx: Sender<()>) { } fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "100000".to_string()) } else if args.len() <= 1 { vec!("".to_string(), "100".to_string()) } else { - args.clone().into_iter().collect() + args.collect() }; let (tx, rx) = channel(); diff --git a/src/test/bench/task-perf-spawnalot.rs b/src/test/bench/task-perf-spawnalot.rs index 279b3fa432a3c..69b9e89dbc522 100644 --- a/src/test/bench/task-perf-spawnalot.rs +++ b/src/test/bench/task-perf-spawnalot.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::os; use std::env; -use std::thread::Thread; +use std::thread; -fn f(n: uint) { +fn f(n: usize) { let mut i = 0u; while i < n { - let _ = Thread::scoped(move|| g()).join(); + let _ = thread::spawn(move|| g()).join(); i += 1u; } } @@ -23,15 +22,15 @@ fn f(n: uint) { fn g() { } fn main() { - let args = os::args(); + let args = env::args(); let args = if env::var_os("RUST_BENCH").is_some() { vec!("".to_string(), "400".to_string()) - } else if args.len() <= 1u { + } else if args.len() <= 1 { vec!("".to_string(), "10".to_string()) } else { - args.into_iter().collect() + args.collect() }; let n = args[1].parse().unwrap(); - let mut i = 0u; - while i < n { Thread::spawn(move|| f(n) ); i += 1u; } + let mut i = 0; + while i < n { thread::spawn(move|| f(n) ); i += 1; } } diff --git a/src/test/compile-fail/asm-gated2.rs b/src/test/compile-fail/asm-gated2.rs new file mode 100644 index 0000000000000..d2ee01109f8d8 --- /dev/null +++ b/src/test/compile-fail/asm-gated2.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + unsafe { + println!("{}", asm!("")); //~ ERROR inline assembly is not stable + } +} diff --git a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs index 980c498e39b47..7f676f5166f7f 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs @@ -10,7 +10,7 @@ #![feature(box_syntax)] -use std::thread::Thread; +use std::thread; fn borrow(v: &isize, f: F) where F: FnOnce(&isize) { f(v); @@ -19,7 +19,7 @@ fn borrow(v: &isize, f: F) where F: FnOnce(&isize) { fn box_imm() { let v = box 3; let _w = &v; - Thread::spawn(move|| { + thread::spawn(move|| { println!("v={}", *v); //~^ ERROR cannot move `v` into closure }); @@ -28,7 +28,7 @@ fn box_imm() { fn box_imm_explicit() { let v = box 3; let _w = &v; - Thread::spawn(move|| { + thread::spawn(move|| { println!("v={}", *v); //~^ ERROR cannot move }); diff --git a/src/test/compile-fail/borrowck-multiple-captures.rs b/src/test/compile-fail/borrowck-multiple-captures.rs index 94e213ae1ae5b..9db05d76284e8 100644 --- a/src/test/compile-fail/borrowck-multiple-captures.rs +++ b/src/test/compile-fail/borrowck-multiple-captures.rs @@ -10,7 +10,7 @@ #![feature(box_syntax)] -use std::thread::Thread; +use std::thread; fn borrow(_: &T) { } @@ -19,7 +19,7 @@ fn different_vars_after_borrows() { let p1 = &x1; let x2 = box 2; let p2 = &x2; - Thread::spawn(move|| { + thread::spawn(move|| { drop(x1); //~ ERROR cannot move `x1` into closure because it is borrowed drop(x2); //~ ERROR cannot move `x2` into closure because it is borrowed }); @@ -32,7 +32,7 @@ fn different_vars_after_moves() { drop(x1); let x2 = box 2; drop(x2); - Thread::spawn(move|| { + thread::spawn(move|| { drop(x1); //~ ERROR capture of moved value: `x1` drop(x2); //~ ERROR capture of moved value: `x2` }); @@ -41,7 +41,7 @@ fn different_vars_after_moves() { fn same_var_after_borrow() { let x = box 1; let p = &x; - Thread::spawn(move|| { + thread::spawn(move|| { drop(x); //~ ERROR cannot move `x` into closure because it is borrowed drop(x); //~ ERROR use of moved value: `x` }); @@ -51,7 +51,7 @@ fn same_var_after_borrow() { fn same_var_after_move() { let x = box 1; drop(x); - Thread::spawn(move|| { + thread::spawn(move|| { drop(x); //~ ERROR capture of moved value: `x` drop(x); //~ ERROR use of moved value: `x` }); diff --git a/src/test/compile-fail/builtin-superkinds-simple.rs b/src/test/compile-fail/builtin-superkinds-simple.rs index c7b75ade55584..c3fb6a1be8797 100644 --- a/src/test/compile-fail/builtin-superkinds-simple.rs +++ b/src/test/compile-fail/builtin-superkinds-simple.rs @@ -13,7 +13,7 @@ trait Foo : Send { } -impl <'a> Foo for &'a mut () { } -//~^ ERROR the type `&'a mut ()` does not fulfill the required lifetime +impl Foo for std::rc::Rc { } +//~^ ERROR the trait `core::marker::Send` is not implemented fn main() { } diff --git a/src/test/compile-fail/coherence-impls-builtin.rs b/src/test/compile-fail/coherence-impls-builtin.rs index 2ca288b60a33f..38730d241f685 100644 --- a/src/test/compile-fail/coherence-impls-builtin.rs +++ b/src/test/compile-fail/coherence-impls-builtin.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(optin_builtin_traits)] + use std::marker::Send; enum TestE { @@ -16,18 +18,21 @@ enum TestE { struct MyType; +struct NotSync; +impl !Sync for NotSync {} + unsafe impl Send for TestE {} unsafe impl Send for MyType {} unsafe impl Send for (MyType, MyType) {} //~^ ERROR builtin traits can only be implemented on structs or enums -unsafe impl Send for &'static MyType {} +unsafe impl Send for &'static NotSync {} //~^ ERROR builtin traits can only be implemented on structs or enums unsafe impl Send for [MyType] {} //~^ ERROR builtin traits can only be implemented on structs or enums -unsafe impl Send for &'static [MyType] {} +unsafe impl Send for &'static [NotSync] {} //~^ ERROR builtin traits can only be implemented on structs or enums fn is_send() {} diff --git a/src/test/compile-fail/concat_idents-gate.rs b/src/test/compile-fail/concat_idents-gate.rs new file mode 100644 index 0000000000000..f4d97445725cd --- /dev/null +++ b/src/test/compile-fail/concat_idents-gate.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const XY_1: i32 = 10; + +fn main() { + const XY_2: i32 = 20; + let a = concat_idents!(X, Y_1); //~ ERROR `concat_idents` is not stable + let b = concat_idents!(X, Y_2); //~ ERROR `concat_idents` is not stable + assert_eq!(a, 10); + assert_eq!(b, 20); +} diff --git a/src/test/compile-fail/concat_idents-gate2.rs b/src/test/compile-fail/concat_idents-gate2.rs new file mode 100644 index 0000000000000..d8f8f803edcc8 --- /dev/null +++ b/src/test/compile-fail/concat_idents-gate2.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const XY_1: i32 = 10; + +fn main() { + const XY_2: i32 = 20; + assert_eq!(10, concat_idents!(X, Y_1)); //~ ERROR `concat_idents` is not stable + assert_eq!(20, concat_idents!(X, Y_2)); //~ ERROR `concat_idents` is not stable +} diff --git a/src/test/compile-fail/custom_attribute.rs b/src/test/compile-fail/custom_attribute.rs new file mode 100644 index 0000000000000..193063a98cb00 --- /dev/null +++ b/src/test/compile-fail/custom_attribute.rs @@ -0,0 +1,14 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[foo] //~ ERROR The attribute `foo` +fn main() { + +} \ No newline at end of file diff --git a/src/test/compile-fail/issue-12041.rs b/src/test/compile-fail/issue-12041.rs index 236142a691921..735f529277c36 100644 --- a/src/test/compile-fail/issue-12041.rs +++ b/src/test/compile-fail/issue-12041.rs @@ -9,11 +9,11 @@ // except according to those terms. use std::sync::mpsc::channel; -use std::thread::Thread; +use std::thread; fn main() { let (tx, rx) = channel(); - let _t = Thread::spawn(move|| -> () { + let _t = thread::spawn(move|| -> () { loop { let tx = tx; //~^ ERROR: use of moved value: `tx` diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs index 01bed69fb1de9..b6d371e4b119f 100644 --- a/src/test/compile-fail/issue-8460-const.rs +++ b/src/test/compile-fail/issue-8460-const.rs @@ -9,47 +9,47 @@ // except according to those terms. use std::{int, i8, i16, i32, i64}; -use std::thread::Thread; +use std::thread; fn main() { - assert!(Thread::scoped(move|| int::MIN / -1).join().is_err()); + assert!(thread::spawn(move|| { int::MIN / -1; }).join().is_err()); //~^ ERROR attempted to divide with overflow in a constant expression - assert!(Thread::scoped(move|| i8::MIN / -1).join().is_err()); + assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); //~^ ERROR attempted to divide with overflow in a constant expression - assert!(Thread::scoped(move|| i16::MIN / -1).join().is_err()); + assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); //~^ ERROR attempted to divide with overflow in a constant expression - assert!(Thread::scoped(move|| i32::MIN / -1).join().is_err()); + assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); //~^ ERROR attempted to divide with overflow in a constant expression - assert!(Thread::scoped(move|| i64::MIN / -1).join().is_err()); + assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); //~^ ERROR attempted to divide with overflow in a constant expression - assert!(Thread::scoped(move|| 1is / 0).join().is_err()); + assert!(thread::spawn(move|| { 1is / 0; }).join().is_err()); //~^ ERROR attempted to divide by zero in a constant expression - assert!(Thread::scoped(move|| 1i8 / 0).join().is_err()); + assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); //~^ ERROR attempted to divide by zero in a constant expression - assert!(Thread::scoped(move|| 1i16 / 0).join().is_err()); + assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); //~^ ERROR attempted to divide by zero in a constant expression - assert!(Thread::scoped(move|| 1i32 / 0).join().is_err()); + assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); //~^ ERROR attempted to divide by zero in a constant expression - assert!(Thread::scoped(move|| 1i64 / 0).join().is_err()); + assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); //~^ ERROR attempted to divide by zero in a constant expression - assert!(Thread::scoped(move|| int::MIN % -1).join().is_err()); + assert!(thread::spawn(move|| { int::MIN % -1; }).join().is_err()); //~^ ERROR attempted remainder with overflow in a constant expression - assert!(Thread::scoped(move|| i8::MIN % -1).join().is_err()); + assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); //~^ ERROR attempted remainder with overflow in a constant expression - assert!(Thread::scoped(move|| i16::MIN % -1).join().is_err()); + assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); //~^ ERROR attempted remainder with overflow in a constant expression - assert!(Thread::scoped(move|| i32::MIN % -1).join().is_err()); + assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); //~^ ERROR attempted remainder with overflow in a constant expression - assert!(Thread::scoped(move|| i64::MIN % -1).join().is_err()); + assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); //~^ ERROR attempted remainder with overflow in a constant expression - assert!(Thread::scoped(move|| 1is % 0).join().is_err()); + assert!(thread::spawn(move|| { 1is % 0; }).join().is_err()); //~^ ERROR attempted remainder with a divisor of zero in a constant expression - assert!(Thread::scoped(move|| 1i8 % 0).join().is_err()); + assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); //~^ ERROR attempted remainder with a divisor of zero in a constant expression - assert!(Thread::scoped(move|| 1i16 % 0).join().is_err()); + assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); //~^ ERROR attempted remainder with a divisor of zero in a constant expression - assert!(Thread::scoped(move|| 1i32 % 0).join().is_err()); + assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); //~^ ERROR attempted remainder with a divisor of zero in a constant expression - assert!(Thread::scoped(move|| 1i64 % 0).join().is_err()); + assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); //~^ ERROR attempted remainder with a divisor of zero in a constant expression } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index de7639c621325..d5276efa8be98 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -17,7 +17,7 @@ struct S; trait Gettable {} -impl Gettable for S {} +impl Gettable for S {} fn f(val: T) { let t: S = S; diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs index 7984b3b32c213..570f7ad7fe3bf 100644 --- a/src/test/compile-fail/kindck-send-object.rs +++ b/src/test/compile-fail/kindck-send-object.rs @@ -20,7 +20,7 @@ trait Message : Send { } fn object_ref_with_static_bound_not_ok() { assert_send::<&'static (Dummy+'static)>(); - //~^ ERROR the trait `core::marker::Send` is not implemented + //~^ ERROR the trait `core::marker::Sync` is not implemented } fn box_object_with_no_bound_not_ok<'a>() { @@ -28,7 +28,7 @@ fn box_object_with_no_bound_not_ok<'a>() { } fn object_with_send_bound_ok() { - assert_send::<&'static (Dummy+Send)>(); + assert_send::<&'static (Dummy+Sync)>(); assert_send::>(); } diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index 3d47d33d7c35d..48d5215b7085b 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -12,22 +12,22 @@ // is broken into two parts because some errors occur in distinct // phases in the compiler. See kindck-send-object2.rs as well! -fn assert_send() { } +fn assert_send() { } trait Dummy { } // careful with object types, who knows what they close over... fn test51<'a>() { assert_send::<&'a Dummy>(); - //~^ ERROR the trait `core::marker::Send` is not implemented + //~^ ERROR the trait `core::marker::Sync` is not implemented } fn test52<'a>() { - assert_send::<&'a (Dummy+Send)>(); + assert_send::<&'a (Dummy+Sync)>(); //~^ ERROR does not fulfill the required lifetime } // ...unless they are properly bounded fn test60() { - assert_send::<&'static (Dummy+Send)>(); + assert_send::<&'static (Dummy+Sync)>(); } fn test61() { assert_send::>(); diff --git a/src/test/compile-fail/kindck-send-object2.rs b/src/test/compile-fail/kindck-send-object2.rs index 75bae09b37f17..d3d166e2a6916 100644 --- a/src/test/compile-fail/kindck-send-object2.rs +++ b/src/test/compile-fail/kindck-send-object2.rs @@ -14,7 +14,7 @@ fn assert_send() { } trait Dummy { } fn test50() { - assert_send::<&'static Dummy>(); //~ ERROR the trait `core::marker::Send` is not implemented + assert_send::<&'static Dummy>(); //~ ERROR the trait `core::marker::Sync` is not implemented } fn test53() { @@ -23,7 +23,7 @@ fn test53() { // ...unless they are properly bounded fn test60() { - assert_send::<&'static (Dummy+Send)>(); + assert_send::<&'static (Dummy+Sync)>(); } fn test61() { assert_send::>(); diff --git a/src/test/compile-fail/kindck-send-owned.rs b/src/test/compile-fail/kindck-send-owned.rs index 266b61566560f..406711902a543 100644 --- a/src/test/compile-fail/kindck-send-owned.rs +++ b/src/test/compile-fail/kindck-send-owned.rs @@ -18,8 +18,8 @@ fn test31() { assert_send::(); } fn test32() { assert_send:: >(); } // but not if they own a bad thing -fn test40<'a>(_: &'a isize) { - assert_send::>(); //~ ERROR does not fulfill the required lifetime +fn test40() { + assert_send::>(); //~ ERROR `core::marker::Send` is not implemented } fn main() { } diff --git a/src/test/compile-fail/kindck-send-region-pointers.rs b/src/test/compile-fail/kindck-send-region-pointers.rs deleted file mode 100644 index e2a5b0678a628..0000000000000 --- a/src/test/compile-fail/kindck-send-region-pointers.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that borrowed pointers are not sendable unless 'static. - -fn assert_send() { } - -// lifetime pointers with 'static lifetime are ok -fn test01() { assert_send::<&'static isize>(); } -fn test02() { assert_send::<&'static str>(); } -fn test03() { assert_send::<&'static [isize]>(); } - -// whether or not they are mutable -fn test10() { assert_send::<&'static mut isize>(); } - -// otherwise lifetime pointers are not ok -fn test20<'a>(_: &'a isize) { - assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime -} -fn test21<'a>(_: &'a isize) { - assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime -} -fn test22<'a>(_: &'a isize) { - assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime -} - -fn main() { } diff --git a/src/test/compile-fail/linkage1.rs b/src/test/compile-fail/linkage1.rs index 555cc2b9a7aad..35f93c13fb5e2 100644 --- a/src/test/compile-fail/linkage1.rs +++ b/src/test/compile-fail/linkage1.rs @@ -11,4 +11,5 @@ extern { #[linkage = "extern_weak"] static foo: isize; //~^ ERROR: the `linkage` attribute is experimental and not portable + //~^^ ERROR: the `linkage` attribute is experimental and not portable } diff --git a/src/test/compile-fail/linkage4.rs b/src/test/compile-fail/linkage4.rs index 635d58e04c7ab..1cf6e90d6c855 100644 --- a/src/test/compile-fail/linkage4.rs +++ b/src/test/compile-fail/linkage4.rs @@ -10,6 +10,6 @@ #[linkage = "external"] static foo: isize = 0; -//~^ ERROR: the `linkage` attribute is experimental and not portable +//~^^ ERROR: the `linkage` attribute is experimental and not portable fn main() {} diff --git a/src/test/compile-fail/lint-obsolete-attr.rs b/src/test/compile-fail/lint-obsolete-attr.rs index e4fd042d09845..dd4e1212a00ca 100644 --- a/src/test/compile-fail/lint-obsolete-attr.rs +++ b/src/test/compile-fail/lint-obsolete-attr.rs @@ -13,6 +13,7 @@ #![deny(unused_attributes)] #![allow(dead_code)] +#![feature(custom_attribute)] #[abi="stdcall"] extern {} //~ ERROR unused attribute diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 5c187176fb2ae..f9cdfa4f7d685 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -133,6 +133,11 @@ mod cross_crate { impl UnstableTrait for S { } //~ WARNING use of unstable library feature trait LocalTrait : UnstableTrait { } //~ WARNING use of unstable library feature + + impl Trait for S { + fn trait_stable(&self) {} + fn trait_unstable(&self) {} //~ WARNING use of unstable library feature + } } mod inheritance { diff --git a/src/test/compile-fail/lint-unknown-attr.rs b/src/test/compile-fail/lint-unknown-attr.rs index e4cb92477c299..af4e81be1951d 100644 --- a/src/test/compile-fail/lint-unknown-attr.rs +++ b/src/test/compile-fail/lint-unknown-attr.rs @@ -11,6 +11,7 @@ // When denying at the crate level, be sure to not get random warnings from the // injected intrinsics by the compiler. +#![feature(custom_attribute)] #![deny(unused_attributes)] #![mutable_doc] //~ ERROR unused attribute diff --git a/src/test/compile-fail/lint-uppercase-variables.rs b/src/test/compile-fail/lint-uppercase-variables.rs index 057b8e3acc6e3..a4f46cbd1874f 100644 --- a/src/test/compile-fail/lint-uppercase-variables.rs +++ b/src/test/compile-fail/lint-uppercase-variables.rs @@ -12,11 +12,10 @@ #![allow(dead_code)] #![deny(non_snake_case)] -#![feature(path)] -#![feature(io)] -use std::old_io::File; -use std::old_io::IoError; +mod foo { + pub enum Foo { Foo } +} struct Something { X: usize //~ ERROR structure field `X` should have a snake case name such as `x` @@ -30,13 +29,11 @@ fn main() { let Test: usize = 0; //~ ERROR variable `Test` should have a snake case name such as `test` println!("{}", Test); - let mut f = File::open(&Path::new("something.txt")); - let mut buff = [0u8; 16]; - match f.read(&mut buff) { - Ok(cnt) => println!("read this many bytes: {}", cnt), - Err(IoError{ kind: EndOfFile, .. }) => println!("Got end of file: {:?}", EndOfFile), -//~^ ERROR variable `EndOfFile` should have a snake case name such as `end_of_file` -//~^^ WARN `EndOfFile` is named the same as one of the variants of the type `std::old_io::IoErrorKind` + match foo::Foo::Foo { + Foo => {} +//~^ ERROR variable `Foo` should have a snake case name such as `foo` +//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` +//~^^^ WARN unused variable: `Foo` } test(1); diff --git a/src/test/compile-fail/log-syntax-gate2.rs b/src/test/compile-fail/log-syntax-gate2.rs new file mode 100644 index 0000000000000..bb19e97ab0fa8 --- /dev/null +++ b/src/test/compile-fail/log-syntax-gate2.rs @@ -0,0 +1,13 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("{}", log_syntax!()); //~ ERROR `log_syntax!` is not stable +} diff --git a/src/test/compile-fail/macro-inner-attributes.rs b/src/test/compile-fail/macro-inner-attributes.rs index e4fc5bb462700..e76eaea365ea6 100644 --- a/src/test/compile-fail/macro-inner-attributes.rs +++ b/src/test/compile-fail/macro-inner-attributes.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(custom_attribute)] + macro_rules! test { ($nm:ident, #[$a:meta], $i:item) => (mod $nm { #![$a] $i }); } diff --git a/src/test/compile-fail/macro-outer-attributes.rs b/src/test/compile-fail/macro-outer-attributes.rs index a0f23c72bc41e..cff01f36f3ad7 100644 --- a/src/test/compile-fail/macro-outer-attributes.rs +++ b/src/test/compile-fail/macro-outer-attributes.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(custom_attribute)] + macro_rules! test { ($nm:ident, #[$a:meta], $i:item) => (mod $nm { #[$a] $i }); } diff --git a/src/test/compile-fail/missing-stability.rs b/src/test/compile-fail/missing-stability.rs index 14dd983161b4a..cf7a8378b9a9a 100644 --- a/src/test/compile-fail/missing-stability.rs +++ b/src/test/compile-fail/missing-stability.rs @@ -30,4 +30,4 @@ pub mod bar { // #[stable] is not inherited pub fn unmarked() {} //~^ ERROR This node does not have a stability attribute -} \ No newline at end of file +} diff --git a/src/test/compile-fail/move-fragments-1.rs b/src/test/compile-fail/move-fragments-1.rs index 3f14be2da109a..0219f5b6becb3 100644 --- a/src/test/compile-fail/move-fragments-1.rs +++ b/src/test/compile-fail/move-fragments-1.rs @@ -18,6 +18,8 @@ // These are all fairly trivial cases: unused variables or direct // drops of substructure. +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-2.rs b/src/test/compile-fail/move-fragments-2.rs index 6c0635d6be931..175488bf2fcd0 100644 --- a/src/test/compile-fail/move-fragments-2.rs +++ b/src/test/compile-fail/move-fragments-2.rs @@ -18,6 +18,8 @@ // These are checking that enums are tracked; note that their output // paths include "downcasts" of the path to a particular enum. +#![feature(rustc_attrs)] + use self::Lonely::{Zero, One, Two}; pub struct D { d: isize } diff --git a/src/test/compile-fail/move-fragments-3.rs b/src/test/compile-fail/move-fragments-3.rs index 24d73ec2274ba..b65921177adaa 100644 --- a/src/test/compile-fail/move-fragments-3.rs +++ b/src/test/compile-fail/move-fragments-3.rs @@ -18,6 +18,8 @@ // This checks the handling of `_` within variants, especially when mixed // with bindings. +#![feature(rustc_attrs)] + use self::Lonely::{Zero, One, Two}; pub struct D { d: isize } diff --git a/src/test/compile-fail/move-fragments-4.rs b/src/test/compile-fail/move-fragments-4.rs index 97e8e45ed0656..191e23a28638b 100644 --- a/src/test/compile-fail/move-fragments-4.rs +++ b/src/test/compile-fail/move-fragments-4.rs @@ -19,6 +19,8 @@ // early draft of the code did not properly traverse up through all of // the parents of the leaf fragment.) +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-5.rs b/src/test/compile-fail/move-fragments-5.rs index 9f70421fa8425..38a385eacac5c 100644 --- a/src/test/compile-fail/move-fragments-5.rs +++ b/src/test/compile-fail/move-fragments-5.rs @@ -17,6 +17,8 @@ // This is the first test that checks moving into local variables. +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-6.rs b/src/test/compile-fail/move-fragments-6.rs index b249d0d739789..122727c3f6b64 100644 --- a/src/test/compile-fail/move-fragments-6.rs +++ b/src/test/compile-fail/move-fragments-6.rs @@ -18,6 +18,8 @@ // Test that moving into a field (i.e. overwriting it) fragments the // receiver. +#![feature(rustc_attrs)] + use std::mem::drop; pub struct Pair { x: X, y: Y } diff --git a/src/test/compile-fail/move-fragments-7.rs b/src/test/compile-fail/move-fragments-7.rs index 2af2b2957f8d6..a2a37208cd616 100644 --- a/src/test/compile-fail/move-fragments-7.rs +++ b/src/test/compile-fail/move-fragments-7.rs @@ -19,6 +19,8 @@ // both moving out of the structure (i.e. reading `*p.x`) and writing // into the container (i.e. writing `*p.x`). +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-8.rs b/src/test/compile-fail/move-fragments-8.rs index 18bf4066076ba..e57268dbfa32a 100644 --- a/src/test/compile-fail/move-fragments-8.rs +++ b/src/test/compile-fail/move-fragments-8.rs @@ -22,6 +22,8 @@ // also that in this case we cannot do a move out of `&T`, so we only // test writing `*p.x` here. +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-9.rs b/src/test/compile-fail/move-fragments-9.rs index 426d5fa29a020..350f416903400 100644 --- a/src/test/compile-fail/move-fragments-9.rs +++ b/src/test/compile-fail/move-fragments-9.rs @@ -14,6 +14,8 @@ // Note also that the `test_move_array_then_overwrite` tests represent // cases that we probably should make illegal. +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs b/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs index dc90994fcc102..32fa773ec8079 100644 --- a/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs +++ b/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::thread::Thread; +use std::thread; fn main() { let x = "Hello world!".to_string(); - Thread::spawn(move|| { + thread::spawn(move|| { println!("{}", x); }); println!("{}", x); //~ ERROR use of moved value diff --git a/src/test/compile-fail/no-capture-arc.rs b/src/test/compile-fail/no-capture-arc.rs index 939d7c7a5348b..7b7b3c414dded 100644 --- a/src/test/compile-fail/no-capture-arc.rs +++ b/src/test/compile-fail/no-capture-arc.rs @@ -11,13 +11,13 @@ // error-pattern: use of moved value use std::sync::Arc; -use std::thread::Thread; +use std::thread; fn main() { let v = vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); let arc_v = Arc::new(v); - Thread::spawn(move|| { + thread::spawn(move|| { assert_eq!((*arc_v)[3], 4); }); diff --git a/src/test/compile-fail/no-reuse-move-arc.rs b/src/test/compile-fail/no-reuse-move-arc.rs index 730ba9ab9ea71..1720b40c83bbd 100644 --- a/src/test/compile-fail/no-reuse-move-arc.rs +++ b/src/test/compile-fail/no-reuse-move-arc.rs @@ -9,13 +9,13 @@ // except according to those terms. use std::sync::Arc; -use std::thread::Thread; +use std::thread; fn main() { let v = vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); let arc_v = Arc::new(v); - Thread::spawn(move|| { + thread::spawn(move|| { assert_eq!((*arc_v)[3], 4); }); diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index ae2847aab0963..5ebc386109a8b 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -10,7 +10,7 @@ #![feature(unsafe_destructor)] -use std::thread::Thread; +use std::thread; use std::rc::Rc; #[derive(Debug)] @@ -35,7 +35,7 @@ fn main() { let x = foo(Port(Rc::new(()))); - Thread::spawn(move|| { + thread::spawn(move|| { //~^ ERROR `core::marker::Send` is not implemented let y = x; println!("{:?}", y); diff --git a/src/test/compile-fail/object-lifetime-default.rs b/src/test/compile-fail/object-lifetime-default.rs index 73f71751ee80f..ac03c085b7b6c 100644 --- a/src/test/compile-fail/object-lifetime-default.rs +++ b/src/test/compile-fail/object-lifetime-default.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(rustc_attrs)] + #[rustc_object_lifetime_default] struct A(T); //~ ERROR None diff --git a/src/test/compile-fail/region-object-lifetime-1.rs b/src/test/compile-fail/region-object-lifetime-1.rs index bb37d55fb08d0..2095fb903b844 100644 --- a/src/test/compile-fail/region-object-lifetime-1.rs +++ b/src/test/compile-fail/region-object-lifetime-1.rs @@ -11,6 +11,7 @@ // Various tests related to testing how region inference works // with respect to the object receivers. +#![feature(rustc_attrs)] #![allow(warnings)] trait Foo { diff --git a/src/test/compile-fail/region-object-lifetime-3.rs b/src/test/compile-fail/region-object-lifetime-3.rs index 7f00334f67e9f..097053276c7fb 100644 --- a/src/test/compile-fail/region-object-lifetime-3.rs +++ b/src/test/compile-fail/region-object-lifetime-3.rs @@ -11,6 +11,7 @@ // Various tests related to testing how region inference works // with respect to the object receivers. +#![feature(rustc_attrs)] #![allow(warnings)] trait Foo { diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs deleted file mode 100644 index 71254e15d32fc..0000000000000 --- a/src/test/compile-fail/regions-bounded-by-send.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test which of the builtin types are considered sendable. The tests -// in this file all test region bound and lifetime violations that are -// detected during type check. - -extern crate core; -use core::ptr::Unique; - -fn assert_send() { } -trait Dummy:Send { } - -// lifetime pointers with 'static lifetime are ok - -fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) { - assert_send::<&'static isize>(); - assert_send::<&'static str>(); - assert_send::<&'static [isize]>(); - - // whether or not they are mutable - assert_send::<&'static mut isize>(); -} - -// otherwise lifetime pointers are not ok - -fn param_not_ok<'a>(x: &'a isize) { - assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime -} - -fn param_not_ok1<'a>(_: &'a isize) { - assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime -} - -fn param_not_ok2<'a>(_: &'a isize) { - assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime -} - -// boxes are ok - -fn box_ok() { - assert_send::>(); - assert_send::(); - assert_send::>(); -} - -// but not if they own a bad thing - -fn box_with_region_not_ok<'a>() { - assert_send::>(); //~ ERROR does not fulfill the required lifetime -} - -// objects with insufficient bounds no ok - -fn object_with_random_bound_not_ok<'a>() { - assert_send::<&'a (Dummy+'a)>(); - //~^ ERROR reference has a longer lifetime -} - -fn object_with_send_bound_not_ok<'a>() { - assert_send::<&'a (Dummy+Send)>(); - //~^ ERROR does not fulfill the required lifetime -} - -// unsafe pointers are ok unless they point at unsendable things - -struct UniqueUnsafePtr(Unique<*const isize>); - -unsafe impl Send for UniqueUnsafePtr {} - -fn unsafe_ok1<'a>(_: &'a isize) { - assert_send::(); -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-pattern-typing-issue-19552.rs b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs index 57ea607cbf623..3401dd1becdd8 100644 --- a/src/test/compile-fail/regions-pattern-typing-issue-19552.rs +++ b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn assert_send(_t: T) {} +fn assert_static(_t: T) {} fn main() { let line = String::new(); match [&*line] { //~ ERROR `line` does not live long enough - [ word ] => { assert_send(word); } + [ word ] => { assert_static(word); } } } diff --git a/src/test/compile-fail/rustc-error.rs b/src/test/compile-fail/rustc-error.rs index 6497439c3dc57..82f32cbcd14e4 100644 --- a/src/test/compile-fail/rustc-error.rs +++ b/src/test/compile-fail/rustc-error.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(rustc_attrs)] + #[rustc_error] fn main() { //~^ ERROR compilation successful diff --git a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs new file mode 100755 index 0000000000000..abbcd7e45904f --- /dev/null +++ b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::thread; + +fn main() { + let bad = { + let x = 1; + let y = &x; + + thread::scoped(|| { //~ ERROR cannot infer an appropriate lifetime + let _z = y; + }) + }; + + bad.join(); +} diff --git a/src/test/compile-fail/trace_macros-gate.rs b/src/test/compile-fail/trace_macros-gate.rs new file mode 100644 index 0000000000000..6473bcece91b6 --- /dev/null +++ b/src/test/compile-fail/trace_macros-gate.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the trace_macros feature gate is on. + +fn main() { + trace_macros!(); //~ ERROR `trace_macros` is not stable + trace_macros!(1); //~ ERROR `trace_macros` is not stable + trace_macros!(ident); //~ ERROR `trace_macros` is not stable + trace_macros!(for); //~ ERROR `trace_macros` is not stable + trace_macros!(true,); //~ ERROR `trace_macros` is not stable + trace_macros!(false 1); //~ ERROR `trace_macros` is not stable + + // Errors are signalled early for the above, before expansion. + // See trace_macros-gate2 and trace_macros-gate3. for examples + // of the below being caught. + + macro_rules! expando { + ($x: ident) => { trace_macros!($x) } + } + + expando!(true); +} diff --git a/src/test/compile-fail/trace_macros-gate2.rs b/src/test/compile-fail/trace_macros-gate2.rs new file mode 100644 index 0000000000000..71cc45e132d33 --- /dev/null +++ b/src/test/compile-fail/trace_macros-gate2.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the trace_macros feature gate is on. + +fn main() { + // (Infrastructure does not attempt to detect uses in macro definitions.) + macro_rules! expando { + ($x: ident) => { trace_macros!($x) } + } + + expando!(true); //~ ERROR `trace_macros` is not stable +} diff --git a/src/test/compile-fail/trace_macros-gate3.rs b/src/test/compile-fail/trace_macros-gate3.rs new file mode 100644 index 0000000000000..66d03cf9d8046 --- /dev/null +++ b/src/test/compile-fail/trace_macros-gate3.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the trace_macros feature gate is on. + +pub fn main() { + println!("arg: {}", trace_macros!()); //~ ERROR `trace_macros` is not stable + println!("arg: {}", trace_macros!(1)); //~ ERROR `trace_macros` is not stable + println!("arg: {}", trace_macros!(ident)); //~ ERROR `trace_macros` is not stable + println!("arg: {}", trace_macros!(for)); //~ ERROR `trace_macros` is not stable + println!("arg: {}", trace_macros!(true,)); //~ ERROR `trace_macros` is not stable + println!("arg: {}", trace_macros!(false 1)); //~ ERROR `trace_macros` is not stable +} diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs index 89e89cf824693..79174552ae09c 100644 --- a/src/test/compile-fail/trait-bounds-cant-coerce.rs +++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs @@ -22,7 +22,7 @@ fn c(x: Box) { fn d(x: Box) { a(x); //~ ERROR mismatched types //~| expected `Box` - //~| found `Box` + //~| found `Box` //~| expected bounds `Send` //~| found no bounds } diff --git a/src/test/compile-fail/unused-attr.rs b/src/test/compile-fail/unused-attr.rs index 50217ff9e5dc6..2d4bc0c857a9a 100644 --- a/src/test/compile-fail/unused-attr.rs +++ b/src/test/compile-fail/unused-attr.rs @@ -7,9 +7,10 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + #![deny(unused_attributes)] #![allow(dead_code, unused_imports)] -#![feature(core)] +#![feature(core, custom_attribute)] #![foo] //~ ERROR unused attribute diff --git a/src/test/compile-fail/variance-associated-types.rs b/src/test/compile-fail/variance-associated-types.rs index ecb2287769bbd..0ed0861d34af1 100644 --- a/src/test/compile-fail/variance-associated-types.rs +++ b/src/test/compile-fail/variance-associated-types.rs @@ -11,6 +11,8 @@ // Test that the variance computation considers types/regions that // appear in projections to be invariant. +#![feature(rustc_attrs)] + trait Trait<'a> { type Type; diff --git a/src/test/compile-fail/variance-object-types.rs b/src/test/compile-fail/variance-object-types.rs index 972ec96f5f27b..2b7b05970d90f 100644 --- a/src/test/compile-fail/variance-object-types.rs +++ b/src/test/compile-fail/variance-object-types.rs @@ -11,6 +11,8 @@ // Test that Cell is considered invariant with respect to its // type. +#![feature(rustc_attrs)] + use std::cell::Cell; // For better or worse, associated types are invariant, and hence we diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index 04389b67dba04..d70305d1106ec 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -11,6 +11,8 @@ // Test that we correctly infer variance for region parameters in // various self-contained types. +#![feature(rustc_attrs)] + // Regions that just appear in normal spots are contravariant: #[rustc_variance] diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index e2c7958b31dec..4bb329d6304cf 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -12,6 +12,8 @@ // case that involve multiple intricate types. // Try enums too. +#![feature(rustc_attrs)] + #[rustc_variance] enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] Test8A(extern "Rust" fn(&'a isize)), diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index c61f2ff79c019..965b9430a5e2d 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -14,6 +14,8 @@ // // Issue #18262. +#![feature(rustc_attrs)] + use std::mem; trait T { fn foo(); } diff --git a/src/test/pretty/attr-fn-inner.rs b/src/test/pretty/attr-fn-inner.rs index 65dcf90056701..79964d2a7baca 100644 --- a/src/test/pretty/attr-fn-inner.rs +++ b/src/test/pretty/attr-fn-inner.rs @@ -13,6 +13,8 @@ // preserved, and that the first outer item parsed in main is not // accidentally carried over to each inner function +#![feature(custom_attribute)] + fn main() { #![inner_attr] #[outer_attr] diff --git a/src/test/run-fail/panic-task-name-none.rs b/src/test/run-fail/panic-task-name-none.rs index 816ee84a8410a..3a5ac5a100957 100644 --- a/src/test/run-fail/panic-task-name-none.rs +++ b/src/test/run-fail/panic-task-name-none.rs @@ -10,12 +10,11 @@ // error-pattern:thread '' panicked at 'test' -use std::thread::Thread; +use std::thread; fn main() { - let r: Result = Thread::scoped(move|| { + let r: Result<(),_> = thread::spawn(move|| { panic!("test"); - 1 }).join(); assert!(r.is_ok()); } diff --git a/src/test/run-fail/panic-task-name-owned.rs b/src/test/run-fail/panic-task-name-owned.rs index d48d282c9eb35..8cab9e05f96e8 100644 --- a/src/test/run-fail/panic-task-name-owned.rs +++ b/src/test/run-fail/panic-task-name-owned.rs @@ -13,9 +13,9 @@ use std::thread::Builder; fn main() { - let r: Result = Builder::new().name("owned name".to_string()).scoped(move|| { + let r: () = Builder::new().name("owned name".to_string()).scoped(move|| { panic!("test"); - 1 - }).join(); - assert!(r.is_ok()); + () + }).unwrap().join(); + panic!(); } diff --git a/src/test/run-fail/rt-set-exit-status-panic2.rs b/src/test/run-fail/rt-set-exit-status-panic2.rs index 446ef6f97e297..775d38c8b3044 100644 --- a/src/test/run-fail/rt-set-exit-status-panic2.rs +++ b/src/test/run-fail/rt-set-exit-status-panic2.rs @@ -12,7 +12,7 @@ #[macro_use] extern crate log; use std::os; -use std::thread::Thread; +use std::thread; struct r { x:int, @@ -35,7 +35,7 @@ fn r(x:int) -> r { fn main() { error!("whatever"); - let _t = Thread::spawn(move|| { + let _t = thread::spawn(move|| { let _i = r(5); }); panic!(); diff --git a/src/test/run-fail/task-spawn-barefn.rs b/src/test/run-fail/task-spawn-barefn.rs index d58148810da1f..406f7dbcb67fe 100644 --- a/src/test/run-fail/task-spawn-barefn.rs +++ b/src/test/run-fail/task-spawn-barefn.rs @@ -10,12 +10,12 @@ // error-pattern:Ensure that the child task runs by panicking -use std::thread::Thread; +use std::thread; fn main() { // the purpose of this test is to make sure that task::spawn() // works when provided with a bare function: - let r = Thread::scoped(startfn).join(); + let r = thread::spawn(startfn).join(); if r.is_err() { panic!() } diff --git a/src/test/run-fail/tls-exit-status.rs b/src/test/run-fail/tls-exit-status.rs index 5b44e3757047b..be619e3a82cc6 100644 --- a/src/test/run-fail/tls-exit-status.rs +++ b/src/test/run-fail/tls-exit-status.rs @@ -11,9 +11,9 @@ // error-pattern:nonzero // exec-env:RUST_NEWRT=1 -use std::os; +use std::env; fn main() { - os::args(); + env::args(); panic!("please have a nonzero exit status"); } diff --git a/src/test/run-make/cannot-read-embedded-idents/create_and_compile.rs b/src/test/run-make/cannot-read-embedded-idents/create_and_compile.rs index c8156b95dcfcb..89352a16d8ba2 100644 --- a/src/test/run-make/cannot-read-embedded-idents/create_and_compile.rs +++ b/src/test/run-make/cannot-read-embedded-idents/create_and_compile.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::os; +use std::env; use std::old_io::{File, Command}; // creates broken.rs, which has the Ident \x00name_0,ctxt_0\x00 @@ -16,7 +16,7 @@ use std::old_io::{File, Command}; // provided `rustc` fn main() { - let args = os::args(); + let args: Vec = env::args().collect(); let rustc = &args[1]; let tmpdir = Path::new(&args[2]); diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 808417d6521ea..c96210896fd65 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -22,7 +22,7 @@ fn main() { fn main() {} "#; - let args = std::os::args(); + let args: Vec = std::env::args().collect(); if args.len() < 4 { panic!("expected rustc path"); diff --git a/src/test/run-make/static-unwinding/lib.rs b/src/test/run-make/static-unwinding/lib.rs index c3fa1a68e164c..12c72d54c094b 100644 --- a/src/test/run-make/static-unwinding/lib.rs +++ b/src/test/run-make/static-unwinding/lib.rs @@ -10,7 +10,7 @@ #![crate_type = "rlib"] -pub static mut statik: int = 0; +pub static mut statik: isize = 0; struct A; impl Drop for A { diff --git a/src/test/run-make/static-unwinding/main.rs b/src/test/run-make/static-unwinding/main.rs index 6d10a247143fa..d325f54d36515 100644 --- a/src/test/run-make/static-unwinding/main.rs +++ b/src/test/run-make/static-unwinding/main.rs @@ -10,9 +10,9 @@ extern crate lib; -use std::thread::Thread; +use std::thread; -static mut statik: int = 0; +static mut statik: isize = 0; struct A; impl Drop for A { @@ -22,10 +22,9 @@ impl Drop for A { } fn main() { - Thread::scoped(move|| { + thread::spawn(move|| { let _a = A; lib::callback(|| panic!()); - 1 }).join().err().unwrap(); unsafe { diff --git a/src/test/run-make/target-specs/my-awesome-platform.json b/src/test/run-make/target-specs/my-awesome-platform.json index f5f622bbcdaa6..d7cf7131d7381 100644 --- a/src/test/run-make/target-specs/my-awesome-platform.json +++ b/src/test/run-make/target-specs/my-awesome-platform.json @@ -2,7 +2,7 @@ "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32", "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", - "target-word-size": "32", + "target-pointer-width": "32", "arch": "x86", "os": "linux", "morestack": false diff --git a/src/test/run-make/target-specs/my-incomplete-platform.json b/src/test/run-make/target-specs/my-incomplete-platform.json index 5005a9ff83960..053f2dd63358a 100644 --- a/src/test/run-make/target-specs/my-incomplete-platform.json +++ b/src/test/run-make/target-specs/my-incomplete-platform.json @@ -1,7 +1,7 @@ { "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32", "target-endian": "little", - "target-word-size": "32", + "target-pointer-width": "32", "arch": "x86", "os": "foo", "morestack": false diff --git a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json b/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json index 5e0f0f40e67bc..688bbe46bfaf0 100644 --- a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json +++ b/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json @@ -3,7 +3,7 @@ "data-layout": "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128", "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "little", - "target-word-size": "64", + "target-pointer-width": "64", "arch": "x86_64", "os": "linux", "morestack": false diff --git a/src/test/run-make/unicode-input/multiple_files.rs b/src/test/run-make/unicode-input/multiple_files.rs index be67e5a066acb..759a1d4aff958 100644 --- a/src/test/run-make/unicode-input/multiple_files.rs +++ b/src/test/run-make/unicode-input/multiple_files.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{char, os}; +use std::{char, env}; use std::old_io::{File, Command}; use std::rand::{thread_rng, Rng}; @@ -33,7 +33,7 @@ fn random_char() -> char { } fn main() { - let args = os::args(); + let args: Vec = env::args().collect(); let rustc = &args[1]; let tmpdir = Path::new(&args[2]); diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index 95ce57da4e110..5dee9104b0f69 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -11,7 +11,7 @@ use std::old_io::{File, Command}; use std::iter::repeat; use std::rand::{thread_rng, Rng}; -use std::{char, os}; +use std::{char, env}; // creates a file with `fn main() { }` and checks the // compiler emits a span of the appropriate length (for the @@ -33,7 +33,7 @@ fn random_char() -> char { } fn main() { - let args = os::args(); + let args: Vec = env::args().collect(); let rustc = &args[1]; let tmpdir = Path::new(&args[2]); let main_file = tmpdir.join("span_main.rs"); diff --git a/src/test/run-pass/attr-before-view-item.rs b/src/test/run-pass/attr-before-view-item.rs index 2a65fd9d8a655..951a716879fce 100644 --- a/src/test/run-pass/attr-before-view-item.rs +++ b/src/test/run-pass/attr-before-view-item.rs @@ -10,6 +10,8 @@ // error-pattern:expected item +#![feature(custom_attribute)] + #[foo = "bar"] extern crate test; diff --git a/src/test/run-pass/attr-before-view-item2.rs b/src/test/run-pass/attr-before-view-item2.rs index 5b8e62de6bd82..ad8ce608bd05d 100644 --- a/src/test/run-pass/attr-before-view-item2.rs +++ b/src/test/run-pass/attr-before-view-item2.rs @@ -10,6 +10,8 @@ // error-pattern:expected item +#![feature(custom_attribute)] + mod m { #[foo = "bar"] extern crate test; diff --git a/src/test/run-pass/attr-mix-new.rs b/src/test/run-pass/attr-mix-new.rs index 55ca75b4b7131..7980937ce2a15 100644 --- a/src/test/run-pass/attr-mix-new.rs +++ b/src/test/run-pass/attr-mix-new.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(unused_attribute)] +#![feature(custom_attribute)] #[foo(bar)] mod foo { diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index b1cb4d6e42c23..6f76322cb778d 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -14,7 +14,6 @@ #![feature(unboxed_closures)] #![feature(unsafe_destructor)] -use std::os; use std::env; use std::old_io::process::Command; use std::str; @@ -86,8 +85,7 @@ fn runtest(me: &str) { } fn main() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); if args.len() >= 2 && args[1] == "fail" { foo(); } else if args.len() >= 2 && args[1] == "double-fail" { diff --git a/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs b/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs index 3df9dd25d8681..379ac12a95424 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs @@ -22,7 +22,7 @@ trait Foo : Bar { } impl Foo for T { } impl Bar for T { } -fn foo(val: T, chan: Sender) { +fn foo(val: T, chan: Sender) { chan.send(val).unwrap(); } diff --git a/src/test/run-pass/builtin-superkinds-capabilities-xc.rs b/src/test/run-pass/builtin-superkinds-capabilities-xc.rs index 52b826393e9e3..cd019c21a3d05 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities-xc.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities-xc.rs @@ -25,7 +25,7 @@ struct X(T); impl RequiresShare for X { } impl RequiresRequiresShareAndSend for X { } -fn foo(val: T, chan: Sender) { +fn foo(val: T, chan: Sender) { chan.send(val).unwrap(); } diff --git a/src/test/run-pass/builtin-superkinds-capabilities.rs b/src/test/run-pass/builtin-superkinds-capabilities.rs index 034e5ff2d3a5c..dc61508eec4fa 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities.rs @@ -18,7 +18,7 @@ trait Foo : Send { } impl Foo for T { } -fn foo(val: T, chan: Sender) { +fn foo(val: T, chan: Sender) { chan.send(val).unwrap(); } diff --git a/src/test/run-pass/builtin-superkinds-self-type.rs b/src/test/run-pass/builtin-superkinds-self-type.rs index 1b3070ba3b04d..1d05a7baa5352 100644 --- a/src/test/run-pass/builtin-superkinds-self-type.rs +++ b/src/test/run-pass/builtin-superkinds-self-type.rs @@ -13,13 +13,13 @@ use std::sync::mpsc::{Sender, channel}; -trait Foo : Send + Sized { +trait Foo : Send + Sized + 'static { fn foo(self, tx: Sender) { tx.send(self).unwrap(); } } -impl Foo for T { } +impl Foo for T { } pub fn main() { let (tx, rx) = channel(); diff --git a/src/test/run-pass/check-static-recursion-foreign.rs b/src/test/run-pass/check-static-recursion-foreign.rs index 9acc0b3a3c52f..4e05c263a48ba 100644 --- a/src/test/run-pass/check-static-recursion-foreign.rs +++ b/src/test/run-pass/check-static-recursion-foreign.rs @@ -11,6 +11,9 @@ // Static recursion check shouldn't fail when given a foreign item (#18279) // aux-build:check_static_recursion_foreign_helper.rs + +#![feature(custom_attribute)] + extern crate check_static_recursion_foreign_helper; extern crate libc; diff --git a/src/test/run-pass/class-attributes-1.rs b/src/test/run-pass/class-attributes-1.rs index 28081e5292aaa..5dc27472184d7 100644 --- a/src/test/run-pass/class-attributes-1.rs +++ b/src/test/run-pass/class-attributes-1.rs @@ -10,6 +10,7 @@ // pp-exact - Make sure we actually print the attributes #![allow(unused_attribute)] +#![feature(custom_attribute)] struct cat { name: String, diff --git a/src/test/run-pass/class-attributes-2.rs b/src/test/run-pass/class-attributes-2.rs index bd62f838444af..cc1b15bcb81cd 100644 --- a/src/test/run-pass/class-attributes-2.rs +++ b/src/test/run-pass/class-attributes-2.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(unused_attribute)] +#![feature(custom_attribute)] struct cat { name: String, diff --git a/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs b/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs index edb3d72483b47..96ae7e3d3368f 100644 --- a/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs +++ b/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs @@ -27,7 +27,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] -use std::thread::Thread; +use std::thread; enum Conzabble { Bickwick(Foo) @@ -48,5 +48,5 @@ pub fn fails() { } pub fn main() { - Thread::scoped(fails).join(); + thread::spawn(fails).join(); } diff --git a/src/test/run-pass/cleanup-shortcircuit.rs b/src/test/run-pass/cleanup-shortcircuit.rs index b776f098b1db2..59f63a79c3ddf 100644 --- a/src/test/run-pass/cleanup-shortcircuit.rs +++ b/src/test/run-pass/cleanup-shortcircuit.rs @@ -20,11 +20,10 @@ // Test that cleanups for the RHS of shortcircuiting operators work. -use std::os; +use std::env; pub fn main() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); // Here, the rvalue `"signal".to_string()` requires cleanup. Older versions // of the code had a problem that the cleanup scope for this diff --git a/src/test/run-pass/drop-trait-enum.rs b/src/test/run-pass/drop-trait-enum.rs index 2474bb8a4f36c..d52c645730f45 100644 --- a/src/test/run-pass/drop-trait-enum.rs +++ b/src/test/run-pass/drop-trait-enum.rs @@ -11,7 +11,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] -use std::thread::Thread; +use std::thread; use std::sync::mpsc::{channel, Sender}; #[derive(PartialEq, Debug)] @@ -69,15 +69,16 @@ pub fn main() { assert_eq!(receiver.recv().ok(), None); let (sender, receiver) = channel(); - let _t = Thread::scoped(move|| { + let t = thread::spawn(move|| { let v = Foo::FailingVariant { on_drop: SendOnDrop { sender: sender } }; }); assert_eq!(receiver.recv().unwrap(), Message::Dropped); assert_eq!(receiver.recv().ok(), None); + drop(t.join()); let (sender, receiver) = channel(); - let _t = { - Thread::scoped(move|| { + let t = { + thread::spawn(move|| { let mut v = Foo::NestedVariant(box 42u, SendOnDrop { sender: sender.clone() }, sender.clone()); @@ -93,4 +94,5 @@ pub fn main() { assert_eq!(receiver.recv().unwrap(), Message::DestructorRan); assert_eq!(receiver.recv().unwrap(), Message::Dropped); assert_eq!(receiver.recv().ok(), None); + drop(t.join()); } diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs index f99d3eb1c7d49..3f226a1985e78 100644 --- a/src/test/run-pass/foreign-call-no-runtime.rs +++ b/src/test/run-pass/foreign-call-no-runtime.rs @@ -11,7 +11,7 @@ extern crate libc; use std::mem; -use std::thread::Thread; +use std::thread; #[link(name = "rust_test_helpers")] extern { @@ -21,9 +21,9 @@ extern { pub fn main() { unsafe { - Thread::scoped(move|| { - let i = &100; - rust_dbg_call(callback, mem::transmute(i)); + thread::spawn(move|| { + let i = 100; + rust_dbg_call(callback, mem::transmute(&i)); }).join(); } } diff --git a/src/test/run-pass/issue-10626.rs b/src/test/run-pass/issue-10626.rs index 9150920cf2cc7..29e4801d0a9aa 100644 --- a/src/test/run-pass/issue-10626.rs +++ b/src/test/run-pass/issue-10626.rs @@ -12,12 +12,11 @@ // Make sure that if a process doesn't have its stdio/stderr descriptors set up // that we don't die in a large ball of fire -use std::os; +use std::env; use std::old_io::process; pub fn main () { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "child" { for _ in 0..1000 { println!("hello?"); diff --git a/src/test/run-pass/issue-12684.rs b/src/test/run-pass/issue-12684.rs index 38731b8c8daeb..e66b5d21e17fa 100644 --- a/src/test/run-pass/issue-12684.rs +++ b/src/test/run-pass/issue-12684.rs @@ -9,10 +9,10 @@ // except according to those terms. use std::time::Duration; -use std::thread::Thread; +use std::thread; fn main() { - Thread::scoped(move|| customtask()).join().ok().unwrap(); + thread::spawn(move|| customtask()).join().ok().unwrap(); } fn customtask() { diff --git a/src/test/run-pass/issue-13304.rs b/src/test/run-pass/issue-13304.rs index 4dc824d9068e5..4a7d6be55a162 100644 --- a/src/test/run-pass/issue-13304.rs +++ b/src/test/run-pass/issue-13304.rs @@ -10,13 +10,12 @@ // ignore-fast -use std::os; +use std::env; use std::old_io; use std::str; fn main() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "child" { child(); } else { @@ -25,8 +24,7 @@ fn main() { } fn parent() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); let mut p = old_io::process::Command::new(&args[0]) .arg("child").spawn().unwrap(); p.stdin.as_mut().unwrap().write_str("test1\ntest2\ntest3").unwrap(); diff --git a/src/test/run-pass/issue-14456.rs b/src/test/run-pass/issue-14456.rs index 1c8066bc3c985..723db9485ca6e 100644 --- a/src/test/run-pass/issue-14456.rs +++ b/src/test/run-pass/issue-14456.rs @@ -12,10 +12,10 @@ use std::old_io::process; use std::old_io::Command; use std::old_io; -use std::os; +use std::env; fn main() { - let args = os::args(); + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "child" { return child() } @@ -32,7 +32,7 @@ fn child() { } fn test() { - let args = os::args(); + let args: Vec = env::args().collect(); let mut p = Command::new(&args[0]).arg("child") .stdin(process::Ignored) .stdout(process::Ignored) diff --git a/src/test/run-pass/issue-14940.rs b/src/test/run-pass/issue-14940.rs index e5fead72bebeb..ed0e3bddbe515 100644 --- a/src/test/run-pass/issue-14940.rs +++ b/src/test/run-pass/issue-14940.rs @@ -8,16 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::os; +use std::env; use std::old_io::{stdio, Command}; fn main() { - let args = os::args(); + let mut args = env::args(); if args.len() > 1 { let mut out = stdio::stdout(); out.write(&['a' as u8; 128 * 1024]).unwrap(); } else { - let out = Command::new(&args[0]).arg("child").output(); + let out = Command::new(&args.next().unwrap()).arg("child").output(); let out = out.unwrap(); assert!(out.status.success()); } diff --git a/src/test/run-pass/issue-15149.rs b/src/test/run-pass/issue-15149.rs index aa45a8c5d5f7f..aa176d5b0f041 100644 --- a/src/test/run-pass/issue-15149.rs +++ b/src/test/run-pass/issue-15149.rs @@ -11,21 +11,21 @@ // except according to those terms. use std::slice::SliceExt; -use std::old_io::{Command, fs, USER_RWX}; -use std::os; +use std::old_io::{fs, USER_RWX}; +use std::process; use std::env; use std::old_path::BytesContainer; use std::rand::random; fn main() { // If we're the child, make sure we were invoked correctly - let args = os::args(); + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "child" { // FIXME: This should check the whole `args[0]` instead of just // checking that it ends_with the executable name. This // is needed because of Windows, which has a different behavior. // See #15149 for more info. - return assert!(args[0].ends_with(&format!("mytest{}", os::consts::EXE_SUFFIX)[])); + return assert!(args[0].ends_with(&format!("mytest{}", env::consts::EXE_SUFFIX)[])); } test(); @@ -33,7 +33,7 @@ fn main() { fn test() { // If we're the parent, copy our own binary to a new directory. - let my_path = os::self_exe_name().unwrap(); + let my_path = env::current_exe().unwrap(); let my_dir = my_path.dir_path(); let random_u32: u32 = random(); @@ -42,22 +42,24 @@ fn test() { fs::mkdir(&child_dir, USER_RWX).unwrap(); let child_path = child_dir.join(format!("mytest{}", - os::consts::EXE_SUFFIX)); + env::consts::EXE_SUFFIX)); fs::copy(&my_path, &child_path).unwrap(); // Append the new directory to our own PATH. - let mut path = os::split_paths(env::var("PATH").ok().unwrap_or(String::new())); - path.push(child_dir.clone()); - let path = os::join_paths(&path).unwrap(); + let path = { + let mut paths: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap()).collect(); + paths.push(child_dir.clone()); + env::join_paths(paths.iter()).unwrap() + }; - let child_output = Command::new("mytest").env("PATH", path) - .arg("child") - .output().unwrap(); + let child_output = process::Command::new("mytest").env("PATH", &path) + .arg("child") + .output().unwrap(); assert!(child_output.status.success(), format!("child assertion failed\n child stdout:\n {}\n child stderr:\n {}", - child_output.output.container_as_str().unwrap(), - child_output.error.container_as_str().unwrap())); + child_output.stdout.container_as_str().unwrap(), + child_output.stderr.container_as_str().unwrap())); fs::rmdir_recursive(&child_dir).unwrap(); diff --git a/src/test/run-pass/issue-16272.rs b/src/test/run-pass/issue-16272.rs index d73ca1b11a555..3bab78ab0df9f 100644 --- a/src/test/run-pass/issue-16272.rs +++ b/src/test/run-pass/issue-16272.rs @@ -9,10 +9,10 @@ // except according to those terms. use std::old_io::{process, Command}; -use std::os; +use std::env; fn main() { - let len = os::args().len(); + let len = env::args().len(); if len == 1 { test(); @@ -22,7 +22,7 @@ fn main() { } fn test() { - let status = Command::new(os::self_exe_name().unwrap()) + let status = Command::new(env::current_exe().unwrap()) .arg("foo").arg("") .stdout(process::InheritFd(1)) .stderr(process::InheritFd(2)) diff --git a/src/test/run-pass/issue-16560.rs b/src/test/run-pass/issue-16560.rs index ca40b2fe4c7d0..9448e605937f7 100644 --- a/src/test/run-pass/issue-16560.rs +++ b/src/test/run-pass/issue-16560.rs @@ -10,7 +10,7 @@ #![feature(unboxed_closures)] -use std::thread::Thread; +use std::thread; use std::mem; fn main() { @@ -20,7 +20,7 @@ fn main() { // Check that both closures are capturing by value assert_eq!(1, mem::size_of_val(&closure)); - Thread::scoped(move|| { + thread::spawn(move|| { let ok = closure; }).join().ok().unwrap(); } diff --git a/src/test/run-pass/issue-16671.rs b/src/test/run-pass/issue-16671.rs index 707aa48259ac9..b06c4923c16c1 100644 --- a/src/test/run-pass/issue-16671.rs +++ b/src/test/run-pass/issue-16671.rs @@ -17,11 +17,11 @@ // A var moved into a proc, that has a mutable loan path should // not trigger a misleading unused_mut warning. -use std::thread::Thread; +use std::thread; pub fn main() { let mut stdin = std::old_io::stdin(); - Thread::spawn(move|| { + thread::spawn(move|| { let _ = stdin.read_to_end(); }); } diff --git a/src/test/run-pass/issue-18188.rs b/src/test/run-pass/issue-18188.rs index 7a5a86822afda..a4b09eb08e0f6 100644 --- a/src/test/run-pass/issue-18188.rs +++ b/src/test/run-pass/issue-18188.rs @@ -14,12 +14,12 @@ use std::thunk::Thunk; pub trait Promisable: Send + Sync {} impl Promisable for T {} -pub fn propagate(action: F) -> Thunk, Result> +pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a,Result, Result> where - T: Promisable + Clone, - E: Promisable + Clone, - F: FnOnce(&T) -> Result + Send, - G: FnOnce(Result) -> Result { + T: Promisable + Clone + 'a, + E: Promisable + Clone + 'a, + F: FnOnce(&T) -> Result + Send + 'a, + G: FnOnce(Result) -> Result + 'a { Thunk::with_arg(move |result: Result| { match result { Ok(ref t) => action(t), diff --git a/src/test/run-pass/issue-20091.rs b/src/test/run-pass/issue-20091.rs index 3ef63a53a6dea..4d20e6360ad4f 100644 --- a/src/test/run-pass/issue-20091.rs +++ b/src/test/run-pass/issue-20091.rs @@ -11,11 +11,11 @@ // ignore-windows currently windows requires UTF-8 for spawning processes use std::old_io::Command; -use std::os; +use std::env; fn main() { - if os::args().len() == 1 { - assert!(Command::new(os::self_exe_name().unwrap()).arg(b"\xff") + if env::args().len() == 1 { + assert!(Command::new(env::current_exe().unwrap()).arg(b"\xff") .status().unwrap().success()) } } diff --git a/src/test/run-pass/issue-21058.rs b/src/test/run-pass/issue-21058.rs index 044d43a57faba..3cdd57aed5a1c 100644 --- a/src/test/run-pass/issue-21058.rs +++ b/src/test/run-pass/issue-21058.rs @@ -14,7 +14,7 @@ struct DST { a: u32, b: str } fn main() { // get_tydesc should support unsized types - assert!(unsafe {( + assert_eq!(unsafe {( // Slice (*std::intrinsics::get_tydesc::<[u8]>()).name, // str @@ -25,5 +25,5 @@ fn main() { (*std::intrinsics::get_tydesc::()).name, // DST (*std::intrinsics::get_tydesc::()).name - )} == ("[u8]", "str", "core::marker::Copy + 'static", "NT", "DST")); + )}, ("[u8]", "str", "core::marker::Copy", "NT", "DST")); } diff --git a/src/test/run-pass/issue-2190-1.rs b/src/test/run-pass/issue-2190-1.rs index 810bf385d7e0b..3025741694f43 100644 --- a/src/test/run-pass/issue-2190-1.rs +++ b/src/test/run-pass/issue-2190-1.rs @@ -13,11 +13,11 @@ use std::thunk::Thunk; static generations: uint = 1024+256+128+49; -fn spawn(f: Thunk) { +fn spawn(f: Thunk<'static>) { Builder::new().stack_size(32 * 1024).spawn(move|| f.invoke(())); } -fn child_no(x: uint) -> Thunk { +fn child_no(x: uint) -> Thunk<'static> { Thunk::new(move|| { if x < generations { spawn(child_no(x+1)); diff --git a/src/test/run-pass/issue-4446.rs b/src/test/run-pass/issue-4446.rs index ec4cd02e9fd69..b40a726a2c397 100644 --- a/src/test/run-pass/issue-4446.rs +++ b/src/test/run-pass/issue-4446.rs @@ -10,14 +10,14 @@ use std::old_io::println; use std::sync::mpsc::channel; -use std::thread::Thread; +use std::thread; pub fn main() { let (tx, rx) = channel(); tx.send("hello, world").unwrap(); - Thread::scoped(move|| { + thread::spawn(move|| { println(rx.recv().unwrap()); }).join().ok().unwrap(); } diff --git a/src/test/run-pass/issue-4448.rs b/src/test/run-pass/issue-4448.rs index a19bfca721a7c..ef30f9182ba69 100644 --- a/src/test/run-pass/issue-4448.rs +++ b/src/test/run-pass/issue-4448.rs @@ -9,12 +9,12 @@ // except according to those terms. use std::sync::mpsc::channel; -use std::thread::Thread; +use std::thread; pub fn main() { let (tx, rx) = channel::<&'static str>(); - let t = Thread::scoped(move|| { + let t = thread::spawn(move|| { assert_eq!(rx.recv().unwrap(), "hello, world"); }); diff --git a/src/test/run-pass/issue-4541.rs b/src/test/run-pass/issue-4541.rs index f10303e8d8479..1f090d8b622e0 100644 --- a/src/test/run-pass/issue-4541.rs +++ b/src/test/run-pass/issue-4541.rs @@ -9,8 +9,7 @@ // except according to those terms. fn parse_args() -> String { - let args = ::std::os::args(); - let args = args; + let args: Vec<_> = ::std::env::args().collect(); let mut n = 0; while n < args.len() { diff --git a/src/test/run-pass/issue-4542.rs b/src/test/run-pass/issue-4542.rs index ae72de50d26d8..521e1b40f992e 100644 --- a/src/test/run-pass/issue-4542.rs +++ b/src/test/run-pass/issue-4542.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::os; +use std::env; pub fn main() { - for arg in &os::args() { - match (*arg).clone() { + for arg in env::args() { + match arg.clone() { _s => { } } } diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs index 4b9ed44c7cd7a..72a1ec436f307 100644 --- a/src/test/run-pass/issue-8460.rs +++ b/src/test/run-pass/issue-8460.rs @@ -9,31 +9,31 @@ // except according to those terms. use std::num::Int; -use std::thread::Thread; +use std::thread; // Avoid using constants, which would trigger compile-time errors. fn min_val() -> T { Int::min_value() } fn zero() -> T { Int::zero() } fn main() { - assert!(Thread::scoped(move|| min_val::() / -1).join().is_err()); - assert!(Thread::scoped(move|| min_val::() / -1).join().is_err()); - assert!(Thread::scoped(move|| min_val::() / -1).join().is_err()); - assert!(Thread::scoped(move|| min_val::() / -1).join().is_err()); - assert!(Thread::scoped(move|| min_val::() / -1).join().is_err()); - assert!(Thread::scoped(move|| 1is / zero()).join().is_err()); - assert!(Thread::scoped(move|| 1i8 / zero()).join().is_err()); - assert!(Thread::scoped(move|| 1i16 / zero()).join().is_err()); - assert!(Thread::scoped(move|| 1i32 / zero()).join().is_err()); - assert!(Thread::scoped(move|| 1i64 / zero()).join().is_err()); - assert!(Thread::scoped(move|| min_val::() % -1).join().is_err()); - assert!(Thread::scoped(move|| min_val::() % -1).join().is_err()); - assert!(Thread::scoped(move|| min_val::() % -1).join().is_err()); - assert!(Thread::scoped(move|| min_val::() % -1).join().is_err()); - assert!(Thread::scoped(move|| min_val::() % -1).join().is_err()); - assert!(Thread::scoped(move|| 1is % zero()).join().is_err()); - assert!(Thread::scoped(move|| 1i8 % zero()).join().is_err()); - assert!(Thread::scoped(move|| 1i16 % zero()).join().is_err()); - assert!(Thread::scoped(move|| 1i32 % zero()).join().is_err()); - assert!(Thread::scoped(move|| 1i64 % zero()).join().is_err()); + assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { 1is / zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i8 / zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i16 / zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i32 / zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i64 / zero(); }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { 1is % zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i8 % zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i16 % zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i32 % zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i64 % zero(); }).join().is_err()); } diff --git a/src/test/run-pass/issue22008.rs b/src/test/run-pass/issue22008.rs new file mode 100644 index 0000000000000..3e145122e5aeb --- /dev/null +++ b/src/test/run-pass/issue22008.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let command = "a"; + + match command { + "foo" => println!("foo"), + _ => println!("{}", command), + } +} diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index 6c2de471f0f58..2aa5a57966672 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -11,6 +11,8 @@ // These are attributes of the implicit crate. Really this just needs to parse // for completeness since .rs files linked from .rc files support this // notation to specify their module's attributes + +#![feature(custom_attribute)] #![allow(unused_attribute)] #![attr1 = "val"] #![attr2 = "val"] diff --git a/src/test/run-pass/logging-only-prints-once.rs b/src/test/run-pass/logging-only-prints-once.rs index 644efe20ded1c..b03c4b5ff47ba 100644 --- a/src/test/run-pass/logging-only-prints-once.rs +++ b/src/test/run-pass/logging-only-prints-once.rs @@ -13,7 +13,7 @@ use std::cell::Cell; use std::fmt; -use std::thread::Thread; +use std::thread; struct Foo(Cell); @@ -27,7 +27,7 @@ impl fmt::Debug for Foo { } pub fn main() { - Thread::scoped(move|| { + thread::spawn(move|| { let mut f = Foo(Cell::new(0)); println!("{:?}", f); let Foo(ref mut f) = f; diff --git a/src/test/run-pass/logging-separate-lines.rs b/src/test/run-pass/logging-separate-lines.rs index e1141d4ab37fd..8526dfe72da13 100644 --- a/src/test/run-pass/logging-separate-lines.rs +++ b/src/test/run-pass/logging-separate-lines.rs @@ -15,12 +15,11 @@ extern crate log; use std::old_io::Command; -use std::os; +use std::env; use std::str; fn main() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "child" { debug!("foo"); debug!("bar"); diff --git a/src/test/run-pass/method-attributes.rs b/src/test/run-pass/method-attributes.rs index c015244d520ce..92af96e0d8f2c 100644 --- a/src/test/run-pass/method-attributes.rs +++ b/src/test/run-pass/method-attributes.rs @@ -10,6 +10,7 @@ // pp-exact - Make sure we print all the attributes #![allow(unused_attribute)] +#![feature(custom_attribute)] #[frobable] trait frobable { diff --git a/src/test/run-pass/no-landing-pads.rs b/src/test/run-pass/no-landing-pads.rs index c90c6ce87f09d..5ce32e4fe2ccb 100644 --- a/src/test/run-pass/no-landing-pads.rs +++ b/src/test/run-pass/no-landing-pads.rs @@ -10,7 +10,7 @@ // compile-flags: -Z no-landing-pads -use std::thread::Thread; +use std::thread; static mut HIT: bool = false; @@ -23,7 +23,7 @@ impl Drop for A { } fn main() { - Thread::scoped(move|| -> () { + thread::spawn(move|| -> () { let _a = A; panic!(); }).join().err().unwrap(); diff --git a/src/test/run-pass/out-of-stack-new-thread-no-split.rs b/src/test/run-pass/out-of-stack-new-thread-no-split.rs index ca9ee469e3897..f574259c375fc 100644 --- a/src/test/run-pass/out-of-stack-new-thread-no-split.rs +++ b/src/test/run-pass/out-of-stack-new-thread-no-split.rs @@ -16,7 +16,7 @@ #![feature(asm)] use std::old_io::process::Command; -use std::os; +use std::env; use std::thread::Thread; // lifted from the test module @@ -34,8 +34,7 @@ fn recurse() { } fn main() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "recurse" { let _t = Thread::scoped(recurse); } else { diff --git a/src/test/run-pass/out-of-stack-no-split.rs b/src/test/run-pass/out-of-stack-no-split.rs index fba86d7481679..948c4d064d723 100644 --- a/src/test/run-pass/out-of-stack-no-split.rs +++ b/src/test/run-pass/out-of-stack-no-split.rs @@ -17,7 +17,7 @@ #![feature(asm)] use std::old_io::process::Command; -use std::os; +use std::env; // lifted from the test module // Inlining to avoid llvm turning the recursive functions into tail calls, @@ -34,7 +34,7 @@ fn recurse() { } fn main() { - let args = os::args(); + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "recurse" { recurse(); } else { diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs index 7dfd46fb995a2..cc5eb69bb87e3 100644 --- a/src/test/run-pass/out-of-stack.rs +++ b/src/test/run-pass/out-of-stack.rs @@ -13,7 +13,7 @@ #![feature(asm)] use std::old_io::process::Command; -use std::os; +use std::env; // lifted from the test module // Inlining to avoid llvm turning the recursive functions into tail calls, @@ -34,8 +34,7 @@ fn loud_recurse() { } fn main() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "silent" { silent_recurse(); } else if args.len() > 1 && args[1] == "loud" { diff --git a/src/test/run-pass/panic-in-dtor-drops-fields.rs b/src/test/run-pass/panic-in-dtor-drops-fields.rs index 3cc01b967ce6a..6da15b97acaae 100644 --- a/src/test/run-pass/panic-in-dtor-drops-fields.rs +++ b/src/test/run-pass/panic-in-dtor-drops-fields.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::thread::Thread; +use std::thread; static mut dropped: bool = false; @@ -33,7 +33,7 @@ impl Drop for B { } pub fn main() { - let ret = Thread::scoped(move|| { + let ret = thread::spawn(move|| { let _a = A { b: B { foo: 3 } }; }).join(); assert!(ret.is_err()); diff --git a/src/test/run-pass/process-spawn-with-unicode-params.rs b/src/test/run-pass/process-spawn-with-unicode-params.rs index 15cc128d380db..017784990f417 100644 --- a/src/test/run-pass/process-spawn-with-unicode-params.rs +++ b/src/test/run-pass/process-spawn-with-unicode-params.rs @@ -20,12 +20,13 @@ use std::old_io; use std::old_io::fs; use std::old_io::Command; use std::os; +use std::env; use std::old_path::Path; fn main() { - let my_args = os::args(); + let my_args = env::args().collect::>(); let my_cwd = os::getcwd().unwrap(); - let my_env = os::env(); + let my_env = env::vars().collect::>(); let my_path = Path::new(os::self_exe_name().unwrap()); let my_dir = my_path.dir_path(); let my_ext = my_path.extension_str().unwrap_or(""); diff --git a/src/test/run-pass/segfault-no-out-of-stack.rs b/src/test/run-pass/segfault-no-out-of-stack.rs index a2706dca7d3ea..492736c2252a0 100644 --- a/src/test/run-pass/segfault-no-out-of-stack.rs +++ b/src/test/run-pass/segfault-no-out-of-stack.rs @@ -9,10 +9,10 @@ // except according to those terms. use std::old_io::process::Command; -use std::os; +use std::env; fn main() { - let args = os::args(); + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "segfault" { unsafe { *(0 as *mut int) = 1 }; // trigger a segfault } else { diff --git a/src/test/run-pass/send-is-not-static-par-for.rs b/src/test/run-pass/send-is-not-static-par-for.rs new file mode 100755 index 0000000000000..c6b64d97fbdd5 --- /dev/null +++ b/src/test/run-pass/send-is-not-static-par-for.rs @@ -0,0 +1,47 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core, std_misc)] +use std::thread::Thread; +use std::sync::Mutex; + +fn par_for(iter: I, f: F) + where I: Iterator, + ::Item: Send, + F: Fn(::Item) + Sync +{ + let f = &f; + let _guards: Vec<_> = iter.map(|elem| { + Thread::scoped(move || { + f(elem) + }) + }).collect(); + +} + +fn sum(x: &[i32]) { + let sum_lengths = Mutex::new(0); + par_for(x.windows(4), |x| { + *sum_lengths.lock().unwrap() += x.len() + }); + + assert_eq!(*sum_lengths.lock().unwrap(), (x.len() - 3) * 4); +} + +fn main() { + let mut elements = [0; 20]; + + // iterators over references into this stack frame + par_for(elements.iter_mut().enumerate(), |(i, x)| { + *x = i as i32 + }); + + sum(&elements) +} diff --git a/src/test/run-pass/send-type-inference.rs b/src/test/run-pass/send-type-inference.rs index ae992a0a358d1..60093803f0b77 100644 --- a/src/test/run-pass/send-type-inference.rs +++ b/src/test/run-pass/send-type-inference.rs @@ -16,7 +16,7 @@ struct Command { val: V } -fn cache_server(mut tx: Sender>>) { +fn cache_server(mut tx: Sender>>) { let (tx1, _rx) = channel(); tx.send(tx1); } diff --git a/src/test/run-pass/sendfn-spawn-with-fn-arg.rs b/src/test/run-pass/sendfn-spawn-with-fn-arg.rs index 6c9707103b9bb..523b7528103ad 100644 --- a/src/test/run-pass/sendfn-spawn-with-fn-arg.rs +++ b/src/test/run-pass/sendfn-spawn-with-fn-arg.rs @@ -11,7 +11,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] -use std::thread::Thread; +use std::thread; pub fn main() { test05(); } @@ -25,7 +25,7 @@ fn test05() { println!("{}", *three + n); // will copy x into the closure assert_eq!(*three, 3); }; - Thread::scoped(move|| { + thread::spawn(move|| { test05_start(fn_to_send); }).join().ok().unwrap(); } diff --git a/src/test/run-pass/sepcomp-unwind.rs b/src/test/run-pass/sepcomp-unwind.rs index f68dea04a0876..21c5a6fc83a12 100644 --- a/src/test/run-pass/sepcomp-unwind.rs +++ b/src/test/run-pass/sepcomp-unwind.rs @@ -19,7 +19,7 @@ // In any case, this test should let us know if enabling parallel codegen ever // breaks unwinding. -use std::thread::Thread; +use std::thread; fn pad() -> uint { 0 } @@ -36,5 +36,5 @@ mod b { } fn main() { - Thread::scoped(move|| { ::b::g() }).join().err().unwrap(); + thread::spawn(move|| { ::b::g() }).join().err().unwrap(); } diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs index 856eb241addc3..776d897938dd3 100644 --- a/src/test/run-pass/signal-exit-status.rs +++ b/src/test/run-pass/signal-exit-status.rs @@ -10,12 +10,11 @@ // ignore-windows -use std::os; +use std::env; use std::old_io::process::{Command, ExitSignal, ExitStatus}; pub fn main() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); if args.len() >= 2 && args[1] == "signal" { // Raise a segfault. unsafe { *(0 as *mut int) = 0; } diff --git a/src/test/run-pass/sigpipe-should-be-ignored.rs b/src/test/run-pass/sigpipe-should-be-ignored.rs index de8f76518fc00..d1428c6be19ef 100644 --- a/src/test/run-pass/sigpipe-should-be-ignored.rs +++ b/src/test/run-pass/sigpipe-should-be-ignored.rs @@ -12,6 +12,7 @@ // doesn't die in a ball of fire, but rather it's gracefully handled. use std::os; +use std::env; use std::old_io::PipeStream; use std::old_io::Command; @@ -25,8 +26,7 @@ fn test() { } fn main() { - let args = os::args(); - let args = args; + let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "test" { return test(); } diff --git a/src/test/run-pass/slice-panic-1.rs b/src/test/run-pass/slice-panic-1.rs index b2e3d83ca9b36..639ffd56002ec 100644 --- a/src/test/run-pass/slice-panic-1.rs +++ b/src/test/run-pass/slice-panic-1.rs @@ -10,7 +10,7 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. -use std::thread::Thread; +use std::thread; struct Foo; @@ -26,6 +26,6 @@ fn foo() { } fn main() { - let _ = Thread::scoped(move|| foo()).join(); + let _ = thread::spawn(move|| foo()).join(); unsafe { assert!(DTOR_COUNT == 2); } } diff --git a/src/test/run-pass/slice-panic-2.rs b/src/test/run-pass/slice-panic-2.rs index dea45e63ab000..4a2038175d2e6 100644 --- a/src/test/run-pass/slice-panic-2.rs +++ b/src/test/run-pass/slice-panic-2.rs @@ -10,7 +10,7 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. -use std::thread::Thread; +use std::thread; struct Foo; @@ -30,6 +30,6 @@ fn foo() { } fn main() { - let _ = Thread::scoped(move|| foo()).join(); + let _ = thread::spawn(move|| foo()).join(); unsafe { assert!(DTOR_COUNT == 2); } } diff --git a/src/test/run-pass/spawn-types.rs b/src/test/run-pass/spawn-types.rs index eaad2abe8f72e..bf2f03b3e6de9 100644 --- a/src/test/run-pass/spawn-types.rs +++ b/src/test/run-pass/spawn-types.rs @@ -14,7 +14,7 @@ Arnold. */ -use std::thread::Thread; +use std::thread; use std::sync::mpsc::{channel, Sender}; type ctx = Sender; @@ -25,6 +25,6 @@ fn iotask(_tx: &ctx, ip: String) { pub fn main() { let (tx, _rx) = channel::(); - let t = Thread::scoped(move|| iotask(&tx, "localhost".to_string()) ); + let t = thread::spawn(move|| iotask(&tx, "localhost".to_string()) ); t.join().ok().unwrap(); } diff --git a/src/test/run-pass/spawn.rs b/src/test/run-pass/spawn.rs index 8f937afa6b932..90b47f4986bfb 100644 --- a/src/test/run-pass/spawn.rs +++ b/src/test/run-pass/spawn.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::thread::Thread; +use std::thread; pub fn main() { - Thread::scoped(move|| child(10)).join().ok().unwrap(); + thread::spawn(move|| child(10)).join().ok().unwrap(); } fn child(i: int) { println!("{}", i); assert!((i == 10)); } diff --git a/src/test/run-pass/spawn2.rs b/src/test/run-pass/spawn2.rs index 75104a4ddef00..91edb5fd9c1e8 100644 --- a/src/test/run-pass/spawn2.rs +++ b/src/test/run-pass/spawn2.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::thread::Thread; +use std::thread; pub fn main() { - let t = Thread::scoped(move|| child((10, 20, 30, 40, 50, 60, 70, 80, 90)) ); + let t = thread::spawn(move|| child((10, 20, 30, 40, 50, 60, 70, 80, 90)) ); t.join().ok().unwrap(); } diff --git a/src/test/run-pass/task-stderr.rs b/src/test/run-pass/task-stderr.rs index 5994b24dfdc59..1c263b19dd182 100644 --- a/src/test/run-pass/task-stderr.rs +++ b/src/test/run-pass/task-stderr.rs @@ -20,9 +20,10 @@ fn main() { let mut reader = ChanReader::new(rx); let stderr = ChanWriter::new(tx); - let res = thread::Builder::new().stderr(box stderr as Box).scoped(move|| -> () { + let res = thread::Builder::new().stderr(box stderr as Box) + .spawn(move|| -> () { panic!("Hello, world!") - }).join(); + }).unwrap().join(); assert!(res.is_err()); let output = reader.read_to_string().unwrap(); diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs index 4df1ff1481042..053df3a57f329 100644 --- a/src/test/run-pass/tempfile.rs +++ b/src/test/run-pass/tempfile.rs @@ -23,7 +23,7 @@ use std::old_io::{fs, TempDir}; use std::old_io; use std::os; use std::sync::mpsc::channel; -use std::thread::Thread; +use std::thread; fn test_tempdir() { let path = { @@ -42,7 +42,7 @@ fn test_rm_tempdir() { tx.send(tmp.path().clone()).unwrap(); panic!("panic to unwind past `tmp`"); }; - let _ = Thread::scoped(f).join(); + thread::spawn(f).join(); let path = rx.recv().unwrap(); assert!(!path.exists()); @@ -52,7 +52,7 @@ fn test_rm_tempdir() { let _tmp = tmp; panic!("panic to unwind past `tmp`"); }; - let _ = Thread::scoped(f).join(); + thread::spawn(f).join(); assert!(!path.exists()); let path; @@ -61,7 +61,7 @@ fn test_rm_tempdir() { TempDir::new("test_rm_tempdir").unwrap() }; // FIXME(#16640) `: TempDir` annotation shouldn't be necessary - let tmp: TempDir = Thread::scoped(f).join().ok().expect("test_rm_tmdir"); + let tmp: TempDir = thread::scoped(f).join(); path = tmp.path().clone(); assert!(path.exists()); } @@ -85,7 +85,7 @@ fn test_rm_tempdir_close() { tmp.close(); panic!("panic when unwinding past `tmp`"); }; - let _ = Thread::scoped(f).join(); + thread::spawn(f).join(); let path = rx.recv().unwrap(); assert!(!path.exists()); @@ -96,7 +96,7 @@ fn test_rm_tempdir_close() { tmp.close(); panic!("panic when unwinding past `tmp`"); }; - let _ = Thread::scoped(f).join(); + thread::spawn(f).join(); assert!(!path.exists()); let path; @@ -105,7 +105,7 @@ fn test_rm_tempdir_close() { TempDir::new("test_rm_tempdir").unwrap() }; // FIXME(#16640) `: TempDir` annotation shouldn't be necessary - let tmp: TempDir = Thread::scoped(f).join().ok().expect("test_rm_tmdir"); + let tmp: TempDir = thread::scoped(f).join(); path = tmp.path().clone(); assert!(path.exists()); tmp.close(); @@ -179,7 +179,7 @@ pub fn test_rmdir_recursive_ok() { } pub fn dont_double_panic() { - let r: Result<(), _> = Thread::scoped(move|| { + let r: Result<(), _> = thread::spawn(move|| { let tmpdir = TempDir::new("test").unwrap(); // Remove the temporary directory so that TempDir sees // an error on drop diff --git a/src/test/run-pass/terminate-in-initializer.rs b/src/test/run-pass/terminate-in-initializer.rs index 185edb02cca11..bef9efa9eb68d 100644 --- a/src/test/run-pass/terminate-in-initializer.rs +++ b/src/test/run-pass/terminate-in-initializer.rs @@ -12,7 +12,7 @@ // Issue #787 // Don't try to clean up uninitialized locals -use std::thread::Thread; +use std::thread; fn test_break() { loop { let _x: Box = break; } } @@ -22,13 +22,13 @@ fn test_ret() { let _x: Box = return; } fn test_panic() { fn f() { let _x: Box = panic!(); } - Thread::scoped(move|| f() ).join().err().unwrap(); + thread::spawn(move|| f() ).join().err().unwrap(); } fn test_panic_indirect() { fn f() -> ! { panic!(); } fn g() { let _x: Box = f(); } - Thread::scoped(move|| g() ).join().err().unwrap(); + thread::spawn(move|| g() ).join().err().unwrap(); } pub fn main() { diff --git a/src/test/run-pass/unique-send-2.rs b/src/test/run-pass/unique-send-2.rs index f0b634c0d44a7..08ffe40369626 100644 --- a/src/test/run-pass/unique-send-2.rs +++ b/src/test/run-pass/unique-send-2.rs @@ -12,7 +12,7 @@ #![feature(box_syntax)] use std::sync::mpsc::{channel, Sender}; -use std::thread::Thread; +use std::thread; fn child(tx: &Sender>, i: uint) { tx.send(box i).unwrap(); @@ -25,7 +25,7 @@ pub fn main() { let _t = (0u..n).map(|i| { expected += i; let tx = tx.clone(); - Thread::scoped(move|| { + thread::spawn(move|| { child(&tx, i) }) }).collect::>(); diff --git a/src/test/run-pass/unit-like-struct-drop-run.rs b/src/test/run-pass/unit-like-struct-drop-run.rs index 0acf736e2ab5c..ac46187f03a71 100644 --- a/src/test/run-pass/unit-like-struct-drop-run.rs +++ b/src/test/run-pass/unit-like-struct-drop-run.rs @@ -11,7 +11,7 @@ // Make sure the destructor is run for unit-like structs. use std::boxed::BoxAny; -use std::thread::Thread; +use std::thread; struct Foo; @@ -22,7 +22,7 @@ impl Drop for Foo { } pub fn main() { - let x = Thread::scoped(move|| { + let x = thread::spawn(move|| { let _b = Foo; }).join(); diff --git a/src/test/run-pass/unwind-resource.rs b/src/test/run-pass/unwind-resource.rs index 159bac101830a..52c09aadfbd7b 100644 --- a/src/test/run-pass/unwind-resource.rs +++ b/src/test/run-pass/unwind-resource.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::sync::mpsc::{channel, Sender}; -use std::thread::Thread; +use std::thread; struct complainer { tx: Sender, @@ -37,7 +37,7 @@ fn f(tx: Sender) { pub fn main() { let (tx, rx) = channel(); - let _t = Thread::scoped(move|| f(tx.clone())); + let _t = thread::spawn(move|| f(tx.clone())); println!("hiiiiiiiii"); assert!(rx.recv().unwrap()); } diff --git a/src/test/run-pass/unwind-unique.rs b/src/test/run-pass/unwind-unique.rs index ea52802d24578..d38b6e79eba66 100644 --- a/src/test/run-pass/unwind-unique.rs +++ b/src/test/run-pass/unwind-unique.rs @@ -11,7 +11,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] -use std::thread::Thread; +use std::thread; fn f() { let _a = box 0; @@ -19,5 +19,5 @@ fn f() { } pub fn main() { - let _t = Thread::scoped(f); + let _t = thread::spawn(f); } diff --git a/src/test/run-pass/variant-attributes.rs b/src/test/run-pass/variant-attributes.rs index 88255ad94fd46..16dca2db396e7 100644 --- a/src/test/run-pass/variant-attributes.rs +++ b/src/test/run-pass/variant-attributes.rs @@ -9,6 +9,7 @@ // except according to those terms. // pp-exact - Make sure we actually print the attributes +#![feature(custom_attribute)] enum crew_of_enterprise_d { diff --git a/src/test/run-pass/vec-macro-repeat.rs b/src/test/run-pass/vec-macro-repeat.rs index 9e69ecfce4fbe..76e7b92ea046b 100644 --- a/src/test/run-pass/vec-macro-repeat.rs +++ b/src/test/run-pass/vec-macro-repeat.rs @@ -14,4 +14,9 @@ pub fn main() { assert_eq!(vec![1; 2], vec![1, 1]); assert_eq!(vec![1; 1], vec![1]); assert_eq!(vec![1; 0], vec![]); + + // from_elem syntax (see RFC 832) + let el = Box::new(1); + let n = 3; + assert_eq!(vec![el; n], vec![Box::new(1), Box::new(1), Box::new(1)]); } diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index d13369b1f5258..da9cf35813b5b 100644 --- a/src/test/run-pass/vector-sort-panic-safe.rs +++ b/src/test/run-pass/vector-sort-panic-safe.rs @@ -10,7 +10,7 @@ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use std::rand::{thread_rng, Rng, Rand}; -use std::thread::Thread; +use std::thread; const REPEATS: usize = 5; const MAX_LEN: usize = 32; @@ -79,7 +79,7 @@ pub fn main() { let v = main.clone(); - let _ = Thread::scoped(move|| { + let _ = thread::spawn(move|| { let mut v = v; let mut panic_countdown = panic_countdown; v.sort_by(|a, b| { diff --git a/src/test/run-pass/weak-lang-item.rs b/src/test/run-pass/weak-lang-item.rs index b1c65d322ab20..741e8be02f72c 100644 --- a/src/test/run-pass/weak-lang-item.rs +++ b/src/test/run-pass/weak-lang-item.rs @@ -12,10 +12,10 @@ extern crate "weak-lang-items" as other; -use std::thread::Thread; +use std::thread; fn main() { - let _ = Thread::scoped(move|| { + let _ = thread::spawn(move|| { other::foo() }); } diff --git a/src/test/run-pass/yield.rs b/src/test/run-pass/yield.rs index 9ad6dd9d2b142..45a747509589d 100644 --- a/src/test/run-pass/yield.rs +++ b/src/test/run-pass/yield.rs @@ -8,18 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::thread::Thread; +use std::thread; pub fn main() { - let mut result = Thread::scoped(child); + let mut result = thread::spawn(child); println!("1"); - Thread::yield_now(); + thread::yield_now(); println!("2"); - Thread::yield_now(); + thread::yield_now(); println!("3"); result.join(); } fn child() { - println!("4"); Thread::yield_now(); println!("5"); Thread::yield_now(); println!("6"); + println!("4"); thread::yield_now(); println!("5"); thread::yield_now(); println!("6"); } diff --git a/src/test/run-pass/yield1.rs b/src/test/run-pass/yield1.rs index 3d3a36021da15..69d8431082c2f 100644 --- a/src/test/run-pass/yield1.rs +++ b/src/test/run-pass/yield1.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::thread::Thread; +use std::thread; pub fn main() { - let mut result = Thread::scoped(child); + let mut result = thread::spawn(child); println!("1"); - Thread::yield_now(); + thread::yield_now(); result.join(); } diff --git a/src/test/run-pass/yield2.rs b/src/test/run-pass/yield2.rs index 66ad7de0296b1..56dc02c6d2e67 100644 --- a/src/test/run-pass/yield2.rs +++ b/src/test/run-pass/yield2.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::thread::Thread; +use std::thread; pub fn main() { let mut i: int = 0; - while i < 100 { i = i + 1; println!("{}", i); Thread::yield_now(); } + while i < 100 { i = i + 1; println!("{}", i); thread::yield_now(); } }