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..3bd24cd0ad4bd 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 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/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/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/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/libcollections/fmt.rs b/src/libcollections/fmt.rs index 0892a1c200885..95cf307ba419b 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -179,7 +179,7 @@ //! //! impl fmt::Display for Vector2D { //! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -//! // The `f` value implements the `Writer` trait, which is what the +//! // The `f` value implements the `Write` trait, which is what the //! // write! macro is expecting. Note that this formatting ignores the //! // various flags provided to format strings. //! write!(f, "({}, {})", self.x, self.y) @@ -403,7 +403,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -pub use core::fmt::{Formatter, Result, Writer, rt}; +pub use core::fmt::{Formatter, Result, Write, rt}; pub use core::fmt::{Show, String, Octal, Binary}; pub use core::fmt::{Display, Debug}; pub use core::fmt::{LowerHex, UpperHex, Pointer}; diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 63483d30dd202..69fd28d172368 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -950,7 +950,7 @@ pub trait ToString { impl ToString for T { #[inline] fn to_string(&self) -> String { - use core::fmt::Writer; + use core::fmt::Write; let mut buf = String::new(); let _ = buf.write_fmt(format_args!("{}", self)); buf.shrink_to_fit(); @@ -984,7 +984,7 @@ impl<'a> Str for CowString<'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Writer for String { +impl fmt::Write for String { #[inline] fn write_str(&mut self, s: &str) -> fmt::Result { self.push_str(s); diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index cf293ded13f00..5d351adfca06b 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; diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 1ebd2df5814d1..5bc634936cff4 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 @@ -104,7 +103,22 @@ pub trait Eq: PartialEq { 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 +134,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 +180,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. /// - /// By convention, `self.cmp(&other)` returns the ordering matching - /// the expression `self other` if true. For example: + /// # 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 +232,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 +295,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 +316,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 +336,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 +359,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 +375,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 +393,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 +424,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/float.rs b/src/libcore/fmt/float.rs index 8e09e52daee19..7f7264a04684b 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -314,7 +314,7 @@ pub fn float_to_str_bytes_common( end: &'a mut uint, } - impl<'a> fmt::Writer for Filler<'a> { + impl<'a> fmt::Write for Filler<'a> { fn write_str(&mut self, s: &str) -> fmt::Result { slice::bytes::copy_memory(&mut self.buf[(*self.end)..], s.as_bytes()); diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index f940300a26945..67c8c9fec09ab 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -57,14 +57,14 @@ pub struct Error; /// A collection of methods that are required to format a message into a stream. /// /// This trait is the type which this modules requires when formatting -/// information. This is similar to the standard library's `io::Writer` trait, +/// information. This is similar to the standard library's `io::Write` trait, /// but it is only intended for use in libcore. /// /// This trait should generally not be implemented by consumers of the standard -/// library. The `write!` macro accepts an instance of `io::Writer`, and the -/// `io::Writer` trait is favored over implementing this trait. +/// library. The `write!` macro accepts an instance of `io::Write`, and the +/// `io::Write` trait is favored over implementing this trait. #[stable(feature = "rust1", since = "1.0.0")] -pub trait Writer { +pub trait Write { /// Writes a slice of bytes into this writer, returning whether the write /// succeeded. /// @@ -85,12 +85,12 @@ pub trait Writer { #[stable(feature = "rust1", since = "1.0.0")] fn write_fmt(&mut self, args: Arguments) -> Result { // This Adapter is needed to allow `self` (of type `&mut - // Self`) to be cast to a FormatWriter (below) without + // Self`) to be cast to a Write (below) without // requiring a `Sized` bound. struct Adapter<'a,T: ?Sized +'a>(&'a mut T); - impl<'a, T: ?Sized> Writer for Adapter<'a, T> - where T: Writer + impl<'a, T: ?Sized> Write for Adapter<'a, T> + where T: Write { fn write_str(&mut self, s: &str) -> Result { self.0.write_str(s) @@ -116,7 +116,7 @@ pub struct Formatter<'a> { width: Option, precision: Option, - buf: &'a mut (Writer+'a), + buf: &'a mut (Write+'a), curarg: slice::Iter<'a, ArgumentV1<'a>>, args: &'a [ArgumentV1<'a>], } @@ -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> { @@ -367,7 +368,7 @@ pub trait UpperExp { /// * output - the buffer to write output to /// * args - the precompiled arguments generated by `format_args!` #[stable(feature = "rust1", since = "1.0.0")] -pub fn write(output: &mut Writer, args: Arguments) -> Result { +pub fn write(output: &mut Write, args: Arguments) -> Result { let mut formatter = Formatter { flags: 0, width: None, diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 03c473ed96741..1d22dda2eceef 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2374,7 +2374,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 +2385,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..f1808bc1fb503 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; 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/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/lint/builtin.rs b/src/librustc/lint/builtin.rs index d09e4bd975924..afd6db4dbbc35 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]", 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..944ca7734f7c2 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -94,7 +94,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 { diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 213e356536246..1136d12a2b124 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -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/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/libserialize/json.rs b/src/libserialize/json.rs index daa358647d8e6..d79a317185553 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -371,7 +371,7 @@ impl std::error::FromError for EncoderError { pub type EncodeResult = Result<(), EncoderError>; pub type DecodeResult = Result; -fn escape_str(wr: &mut fmt::Writer, v: &str) -> EncodeResult { +fn escape_str(wr: &mut fmt::Write, v: &str) -> EncodeResult { try!(wr.write_str("\"")); let mut start = 0; @@ -433,14 +433,14 @@ fn escape_str(wr: &mut fmt::Writer, v: &str) -> EncodeResult { Ok(()) } -fn escape_char(writer: &mut fmt::Writer, v: char) -> EncodeResult { +fn escape_char(writer: &mut fmt::Write, v: char) -> EncodeResult { let mut buf = [0; 4]; let n = v.encode_utf8(&mut buf).unwrap(); let buf = unsafe { str::from_utf8_unchecked(&buf[..n]) }; escape_str(writer, buf) } -fn spaces(wr: &mut fmt::Writer, mut n: uint) -> EncodeResult { +fn spaces(wr: &mut fmt::Write, mut n: uint) -> EncodeResult { const BUF: &'static str = " "; while n >= BUF.len() { @@ -464,14 +464,14 @@ fn fmt_number_or_null(v: f64) -> string::String { /// A structure for implementing serialization to JSON. pub struct Encoder<'a> { - writer: &'a mut (fmt::Writer+'a), + writer: &'a mut (fmt::Write+'a), is_emitting_map_key: bool, } impl<'a> Encoder<'a> { /// Creates a new JSON encoder whose output will be written to the writer /// specified. - pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> { + pub fn new(writer: &'a mut fmt::Write) -> Encoder<'a> { Encoder { writer: writer, is_emitting_map_key: false, } } } @@ -709,7 +709,7 @@ impl<'a> ::Encoder for Encoder<'a> { /// Another encoder for JSON, but prints out human-readable JSON instead of /// compact data pub struct PrettyEncoder<'a> { - writer: &'a mut (fmt::Writer+'a), + writer: &'a mut (fmt::Write+'a), curr_indent: uint, indent: uint, is_emitting_map_key: bool, @@ -717,7 +717,7 @@ pub struct PrettyEncoder<'a> { impl<'a> PrettyEncoder<'a> { /// Creates a new encoder whose output will be written to the specified writer - pub fn new(writer: &'a mut fmt::Writer) -> PrettyEncoder<'a> { + pub fn new(writer: &'a mut fmt::Write) -> PrettyEncoder<'a> { PrettyEncoder { writer: writer, curr_indent: 0, @@ -2527,7 +2527,7 @@ struct FormatShim<'a, 'b: 'a> { inner: &'a mut fmt::Formatter<'b>, } -impl<'a, 'b> fmt::Writer for FormatShim<'a, 'b> { +impl<'a, 'b> fmt::Write for FormatShim<'a, 'b> { fn write_str(&mut self, s: &str) -> fmt::Result { match self.inner.write_str(s) { Ok(_) => Ok(()), 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/io/mod.rs b/src/libstd/io/mod.rs index 2668baba095b8..c38d52161c96e 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -381,14 +381,14 @@ pub trait Write { /// /// This function will return any I/O error reported while formatting. fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { - // Create a shim which translates a Writer to a fmt::Writer and saves + // Create a shim which translates a Write to a fmt::Write and saves // off I/O errors. instead of discarding them struct Adaptor<'a, T: ?Sized + 'a> { inner: &'a mut T, error: Result<()>, } - impl<'a, T: Write + ?Sized> fmt::Writer for Adaptor<'a, T> { + impl<'a, T: Write + ?Sized> fmt::Write for Adaptor<'a, T> { fn write_str(&mut self, s: &str) -> fmt::Result { match self.inner.write_all(s.as_bytes()) { Ok(()) => Ok(()), @@ -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/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/mod.rs b/src/libstd/old_io/mod.rs index 3673f590c0a9d..3b35444df318f 100644 --- a/src/libstd/old_io/mod.rs +++ b/src/libstd/old_io/mod.rs @@ -1023,14 +1023,14 @@ pub trait Writer { /// /// This function will return any I/O error reported while formatting. fn write_fmt(&mut self, fmt: fmt::Arguments) -> IoResult<()> { - // Create a shim which translates a Writer to a fmt::Writer and saves + // Create a shim which translates a Writer to a fmt::Write and saves // off I/O errors. instead of discarding them struct Adaptor<'a, T: ?Sized +'a> { inner: &'a mut T, error: IoResult<()>, } - impl<'a, T: ?Sized + Writer> fmt::Writer for Adaptor<'a, T> { + impl<'a, T: ?Sized + Writer> fmt::Write for Adaptor<'a, T> { fn write_str(&mut self, s: &str) -> fmt::Result { match self.inner.write_all(s.as_bytes()) { Ok(()) => Ok(()), diff --git a/src/libstd/old_io/process.rs b/src/libstd/old_io/process.rs index 195d33c41a68e..09a0deec9c935 100644 --- a/src/libstd/old_io/process.rs +++ b/src/libstd/old_io/process.rs @@ -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), } } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d2b98ec89390b..0530527c93fe6 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -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/rt/unwind.rs b/src/libstd/rt/unwind.rs index b45878584e02d..c9bbea27e4ad6 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -495,7 +495,7 @@ pub extern fn rust_begin_unwind(msg: fmt::Arguments, #[inline(never)] #[cold] #[stable(since = "1.0.0", feature = "rust1")] pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, uint)) -> ! { - use fmt::Writer; + use fmt::Write; // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index bb57d19ed2666..d445c29902801 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -110,7 +110,7 @@ impl Stdio { } } -impl fmt::Writer for Stdio { +impl fmt::Write for Stdio { fn write_str(&mut self, data: &str) -> fmt::Result { self.write_bytes(data.as_bytes()); Ok(()) // yes, we're lying @@ -122,13 +122,13 @@ pub fn dumb_print(args: fmt::Arguments) { } pub fn abort(args: fmt::Arguments) -> ! { - use fmt::Writer; + use fmt::Write; struct BufWriter<'a> { buf: &'a mut [u8], pos: uint, } - impl<'a> fmt::Writer for BufWriter<'a> { + impl<'a> fmt::Write for BufWriter<'a> { fn write_str(&mut self, bytes: &str) -> fmt::Result { let left = &mut self.buf[self.pos..]; let to_write = &bytes.as_bytes()[..cmp::min(bytes.len(), left.len())]; 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/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/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/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..cfd4379497a05 100644 --- a/src/rustbook/main.rs +++ b/src/rustbook/main.rs @@ -13,12 +13,13 @@ #![feature(core)] #![feature(io)] #![feature(os)] +#![feature(env)] #![feature(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/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..868202f71e10f 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -19,7 +19,6 @@ // version. use std::sync::mpsc::{channel, Sender, Receiver}; -use std::os; use std::env; use std::thread::Thread; use std::time::Duration; @@ -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..c6319ad65175c 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -15,7 +15,6 @@ // 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::time::Duration; @@ -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..4d0887f48b321 100644 --- a/src/test/bench/rt-messaging-ping-pong.rs +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -18,7 +18,7 @@ // except according to those terms. use std::sync::mpsc::channel; -use std::os; +use std::env; use std::thread::Thread; // This is a simple bench that creates M pairs of tasks. These @@ -26,10 +26,10 @@ use std::thread::Thread; // 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 @@ -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..dadf1a3fd9a1d 100644 --- a/src/test/bench/rt-parfib.rs +++ b/src/test/bench/rt-parfib.rs @@ -9,14 +9,14 @@ // except according to those terms. use std::sync::mpsc::channel; -use std::os; +use std::env; use std::thread::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; } @@ -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..6762760ed5653 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -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}; diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 628206986c518..31c786c16446d 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -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..2c220ab95dd76 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -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-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index e2d51fbf4111d..c0951ccda6ca9 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -43,7 +43,7 @@ // 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; @@ -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-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..45163510a9400 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::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 { @@ -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; @@ -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-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index 8356df8d8a184..f7572b2045301 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -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); } diff --git a/src/test/bench/shootout-threadring.rs b/src/test/bench/shootout-threadring.rs index 8614f94da89ea..f68fb814b2113 100644 --- a/src/test/bench/shootout-threadring.rs +++ b/src/test/bench/shootout-threadring.rs @@ -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-jargon-metal-smoke.rs b/src/test/bench/task-perf-jargon-metal-smoke.rs index 9edb4201098d6..a9848137e755a 100644 --- a/src/test/bench/task-perf-jargon-metal-smoke.rs +++ b/src/test/bench/task-perf-jargon-metal-smoke.rs @@ -18,7 +18,6 @@ // ignore-pretty very bad with line comments use std::sync::mpsc::{channel, Sender}; -use std::os; use std::env; use std::thread::Thread; @@ -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..ba5e25634e8cd 100644 --- a/src/test/bench/task-perf-spawnalot.rs +++ b/src/test/bench/task-perf-spawnalot.rs @@ -8,11 +8,10 @@ // 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; -fn f(n: uint) { +fn f(n: usize) { let mut i = 0u; while i < n { let _ = Thread::scoped(move|| g()).join(); @@ -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; + let mut i = 0; while i < n { Thread::spawn(move|| f(n) ); i += 1u; } } 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/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/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-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/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/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/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/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/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/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/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/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/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-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/colorful-write-macros.rs b/src/test/run-pass/colorful-write-macros.rs index bcb2e49204150..841aaa94e9b55 100644 --- a/src/test/run-pass/colorful-write-macros.rs +++ b/src/test/run-pass/colorful-write-macros.rs @@ -21,7 +21,7 @@ struct Foo<'a> { struct Bar; -impl fmt::Writer for Bar { +impl fmt::Write for Bar { fn write_str(&mut self, _: &str) -> fmt::Result { Ok(()) } @@ -39,7 +39,7 @@ fn main() { let mut s = Bar; { - use std::fmt::Writer; + use std::fmt::Write; write!(&mut s, "test"); } } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 5d157d875fa4d..e5aade792edf0 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -165,9 +165,9 @@ pub fn main() { } // Basic test to make sure that we can invoke the `write!` macro with an -// io::Writer instance. +// fmt::Write instance. fn test_write() { - use std::fmt::Writer; + use std::fmt::Write; let mut buf = String::new(); write!(&mut buf, "{}", 3); { @@ -194,7 +194,7 @@ fn test_print() { // Just make sure that the macros are defined, there's not really a lot that we // can do with them just yet (to test the output) fn test_format_args() { - use std::fmt::Writer; + use std::fmt::Write; let mut buf = String::new(); { let w = &mut buf; 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-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-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-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/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-separate-lines.rs b/src/test/run-pass/logging-separate-lines.rs index 1be0ee4a28551..b90d881569917 100644 --- a/src/test/run-pass/logging-separate-lines.rs +++ b/src/test/run-pass/logging-separate-lines.rs @@ -16,12 +16,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/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/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/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/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 {