auto merge of #21213 : alexcrichton/rust/rollup, r=alexcrichton

This commit is contained in:
bors 2015-01-16 03:02:54 +00:00
commit b565501ad8
114 changed files with 1520 additions and 878 deletions

View File

@ -581,7 +581,7 @@ Robert Knight <robertknight@gmail.com>
Robert Millar <robert.millar@cantab.net>
Robin Gloster <robin@loc-com.de>
Robin Stocker <robin@nibor.org>
Rohit Joshi <rohit.joshi@capitalone.com>
Rohit Joshi <rohit.c.joshi@gmail.com>
Roland Tanglao <roland@rolandtanglao.com>
Rolf Timmermans <rolftimmermans@voormedia.com>
Rolf van de Krol <info@rolfvandekrol.nl>

View File

@ -27,7 +27,7 @@ please do two things:
Pull requests will be treated as "review requests", and we will give
feedback we expect to see corrected on
[style](https://github.com/rust-lang/rust/wiki/Note-style-guide) and
[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.

View File

@ -97,10 +97,9 @@
# make check-stage1-std RUST_TEST_TASKS=1
#
# This is hardly all there is to know of The Rust Build System's
# mysteries. The tale continues on the wiki[1][2].
# mysteries. The tale continues on the wiki[1].
#
# [1]: https://github.com/rust-lang/rust/wiki/Note-getting-started-developing-Rust
# [2]: https://github.com/rust-lang/rust/wiki/Note-testsuite
# [1]: https://github.com/rust-lang/rust/wiki/Note-testsuite
#
# If you really feel like getting your hands dirty, then:
#

View File

@ -58,16 +58,23 @@ documentation.
### Building on Windows
To easily build on windows we can use [MSYS2](http://sourceforge.net/projects/msys2/):
To easily build on windows we can use [MSYS2](http://msys2.github.io/):
1. Grab the latest MSYS2 installer and go through the installer.
2. Now from the MSYS2 terminal we want to install the mingw64 toolchain and the other
tools we need.
$ pacman -S mingw-w64-i686-toolchain
$ pacman -S base-devel
```bash
# choose one based on platform
$ pacman -S mingw-w64-i686-toolchain
$ pacman -S mingw-w64-x86_64-toolchain
3. With that now start `mingw32_shell.bat` from where you installed MSYS2 (i.e. `C:\msys`).
$ pacman -S base-devel
```
3. With that now start `mingw32_shell.bat` or `mingw64_shell.bat`
from where you installed MSYS2 (i.e. `C:\msys`). Which one you
choose depends on if you want 32 or 64 bit Rust.
4. From there just navigate to where you have Rust's source code, configure and build it:
$ ./configure

View File

@ -11,7 +11,7 @@ AR_aarch64-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
endif
CFG_LIB_NAME_aarch64-apple-ios = lib$(1).a
CFG_LIB_GLOB_aarch64-apple-ios = lib$(1)-*.a
CFG_LIB_SKIP_INSTALL_aarch64-apple-ios = 1 #lib$(1)-*.a
CFG_INSTALL_ONLY_RLIB_aarch64-apple-ios = 1
CFG_STATIC_LIB_NAME_aarch64-apple-ios=lib$(1).a
CFG_LIB_DSYM_GLOB_aarch64-apple-ios = lib$(1)-*.a.dSYM
CFG_CFLAGS_aarch64-apple-ios := $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios)

View File

@ -11,7 +11,7 @@ AR_armv7-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
endif
CFG_LIB_NAME_armv7-apple-ios = lib$(1).a
CFG_LIB_GLOB_armv7-apple-ios = lib$(1)-*.a
CFG_LIB_SKIP_INSTALL_armv7-apple-ios = 1 #lib$(1)-*.a
CFG_INSTALL_ONLY_RLIB_armv7-apple-ios = 1
CFG_STATIC_LIB_NAME_armv7-apple-ios=lib$(1).a
CFG_LIB_DSYM_GLOB_armv7-apple-ios = lib$(1)-*.a.dSYM
CFG_JEMALLOC_CFLAGS_armv7-apple-ios := -arch armv7 -mfpu=vfp3 $(CFG_IOS_SDK_FLAGS_armv7-apple-ios)

View File

@ -11,7 +11,7 @@ AR_armv7s-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
endif
CFG_LIB_NAME_armv7s-apple-ios = lib$(1).a
CFG_LIB_GLOB_armv7s-apple-ios = lib$(1)-*.a
CFG_LIB_SKIP_INSTALL_armv7s-apple-ios = 1 #lib$(1)-*.a
CFG_INSTALL_ONLY_RLIB_armv7s-apple-ios = 1
CFG_STATIC_LIB_NAME_armv7s-apple-ios=lib$(1).a
CFG_LIB_DSYM_GLOB_armv7s-apple-ios = lib$(1)-*.a.dSYM
CFG_JEMALLOC_CFLAGS_armv7s-apple-ios := -arch armv7s -mfpu=vfp4 $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios)

View File

@ -11,6 +11,7 @@ AR_i386-apple-ios = $(shell xcrun -find -sdk iphonesimulator ar)
endif
CFG_LIB_NAME_i386-apple-ios = lib$(1).a
CFG_LIB_GLOB_i386-apple-ios = lib$(1)-*.dylib
CFG_INSTALL_ONLY_RLIB_i386-apple-ios = 1
CFG_STATIC_LIB_NAME_i386-apple-ios=lib$(1).a
CFG_LIB_DSYM_GLOB_i386-apple-ios = lib$(1)-*.dylib.dSYM
CFG_GCCISH_CFLAGS_i386-apple-ios := -Wall -Werror -g -fPIC -m32 $(CFG_IOSSIM_FLAGS_i386-apple-ios)

View File

@ -11,7 +11,7 @@ AR_x86_64-apple-ios = $(shell xcrun -find -sdk iphonesimulator ar)
endif
CFG_LIB_NAME_x86_64-apple-ios = lib$(1).a
CFG_LIB_GLOB_x86_64-apple-ios = lib$(1)-*.a
CFG_LIB_SKIP_INSTALL_x86_64-apple-ios = 1 #lib$(1)-*.a
CFG_INSTALL_ONLY_RLIB_x86_64-apple-ios = 1
CFG_STATIC_LIB_NAME_x86_64-apple-ios=lib$(1).a
CFG_LIB_DSYM_GLOB_x86_64-apple-ios = lib$(1)-*.a.dSYM
CFG_CFLAGS_x86_64-apple-ios := $(CFG_IOSSIM_FLAGS_x86_64-apple-ios)

View File

@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.0.0
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
# NB Make sure it starts with a dot to conform to semver pre-release
# versions (section 9)
CFG_PRERELEASE_VERSION=
CFG_PRERELEASE_VERSION=.1
CFG_FILENAME_EXTRA=4e7c5e5c
@ -30,9 +30,8 @@ CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)
CFG_DISABLE_UNSTABLE_FEATURES=1
endif
ifeq ($(CFG_RELEASE_CHANNEL),beta)
# The beta channel is temporarily called 'alpha'
CFG_RELEASE=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION)
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION)
CFG_RELEASE=$(CFG_RELEASE_NUM)-beta(CFG_PRERELEASE_VERSION)
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-beta(CFG_PRERELEASE_VERSION)
CFG_DISABLE_UNSTABLE_FEATURES=1
endif
ifeq ($(CFG_RELEASE_CHANNEL),nightly)

View File

@ -134,7 +134,7 @@ prepare-target-$(2)-host-$(3)-$(1)-$(4): prepare-maybe-clean-$(4) \
$$(if $$(findstring $(3), $$(PREPARE_HOST)), \
$$(call PREPARE_DIR,$$(PREPARE_WORKING_DEST_LIB_DIR)) \
$$(foreach crate,$$(TARGET_CRATES), \
$$(if $$(findstring 1, $$(ONLY_RLIB_$$(crate))),, \
$$(if $$(or $$(findstring 1, $$(ONLY_RLIB_$$(crate))),$$(findstring 1,$$(CFG_INSTALL_ONLY_RLIB_$(2)))),, \
$$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))) \
$$(call PREPARE_LIB,$$(call CFG_RLIB_GLOB,$$(crate)))) \
$$(if $$(findstring $(2),$$(CFG_HOST)), \

View File

@ -10,7 +10,7 @@ There aren't many large programs yet. The Rust [compiler][rustc], 60,000+ lines
A research browser engine called [Servo][servo], currently 30,000+ lines across more than a dozen crates, will be exercising a lot of Rust's distinctive type-system and concurrency features, and integrating many native libraries.
[servo]: https://github.com/mozilla/servo
[servo]: https://github.com/servo/servo
Some examples that demonstrate different aspects of the language:

View File

@ -30,7 +30,7 @@ No. It started as a Graydon Hoare's part-time side project in 2006 and remained
# What will Mozilla use Rust for?
Mozilla intends to use Rust as a platform for prototyping experimental browser architectures. Specifically, the hope is to develop a browser that is more amenable to parallelization than existing ones, while also being less prone to common C++ coding errors that result in security exploits. The name of that project is _[Servo](http://github.com/mozilla/servo)_.
Mozilla intends to use Rust as a platform for prototyping experimental browser architectures. Specifically, the hope is to develop a browser that is more amenable to parallelization than existing ones, while also being less prone to common C++ coding errors that result in security exploits. The name of that project is _[Servo](http://github.com/servo/servo)_.
# Why a BSD-style permissive license rather than MPL or tri-license?

View File

@ -5,7 +5,7 @@ accomplishes these goals by being memory safe without using garbage collection.
This introduction will give you a rough idea of what Rust is like, eliding many
details. It does not require prior experience with systems programming, but you
may find the syntax easier if you've used a 'curly brace' programming language
may find the syntax easier if you've used a "curly brace" programming language
before, like C or JavaScript. The concepts are more important than the syntax,
so don't worry if you don't get every last detail: you can read [The
Rust Programming Language](book/index.html) to get a more complete explanation.
@ -15,7 +15,7 @@ Rust to follow along. If you'd like to anyway, check out [the
homepage](http://rust-lang.org) for explanation.
To show off Rust, let's talk about how easy it is to get started with Rust.
Then, we'll talk about Rust's most interesting feature, **ownership**, and
Then, we'll talk about Rust's most interesting feature, *ownership*, and
then discuss how it makes concurrency easier to reason about. Finally,
we'll talk about how Rust breaks down the perceived dichotomy between speed
and safety.
@ -57,7 +57,7 @@ version = "0.0.1"
authors = ["Your Name <you@example.com>"]
```
This is called a **manifest**, and it contains all of the metadata that Cargo
This is called a *manifest*, and it contains all of the metadata that Cargo
needs to compile your project.
Here's what's in `src/main.rs`:
@ -68,7 +68,7 @@ fn main() {
}
```
Cargo generated a 'hello world' for us. We'll talk more about the syntax here
Cargo generated a "Hello World" for us. We'll talk more about the syntax here
later, but that's what Rust code looks like! Let's compile and run it:
```{bash}
@ -146,8 +146,8 @@ Enough about tools, let's talk code!
# Ownership
Rust's defining feature is 'memory safety without garbage collection.' Let's
take a moment to talk about what that means. **Memory safety** means that the
Rust's defining feature is "memory safety without garbage collection". Let's
take a moment to talk about what that means. *Memory safety* means that the
programming language eliminates certain kinds of bugs, such as [buffer
overflows](http://en.wikipedia.org/wiki/Buffer_overflow) and [dangling
pointers](http://en.wikipedia.org/wiki/Dangling_pointer). These problems occur
@ -170,7 +170,7 @@ We make an array, `v`, and then call `push` on it. `push` is a method which
adds an element to the end of an array.
Next, we make a new variable, `x`, that's equal to the first element of
the array. Simple, but this is where the 'bug' will appear.
the array. Simple, but this is where the "bug" will appear.
Let's keep going. We then call `push` again, pushing "world" onto the
end of the array. `v` now is `["Hello", "world"]`.
@ -222,7 +222,7 @@ its length changes, we may need to allocate more memory. In Ruby, this happens
as well, we just don't think about it very often. So why does the C++ version
segfault when we allocate more memory?
The answer is that in the C++ version, `x` is a **reference** to the memory
The answer is that in the C++ version, `x` is a *reference* to the memory
location where the first element of the array is stored. But in Ruby, `x` is a
standalone value, not connected to the underyling array at all. Let's dig into
the details for a moment. Your program has access to memory, provided to it by
@ -332,11 +332,11 @@ error: aborting due to previous error
When we try to mutate the array by `push`ing it the second time, Rust throws
an error. It says that we "cannot borrow v as mutable because it is also
borrowed as immutable." What's up with "borrowed"?
borrowed as immutable." What does it mean by "borrowed"?
In Rust, the type system encodes the notion of **ownership**. The variable `v`
is an "owner" of the vector. When we make a reference to `v`, we let that
variable (in this case, `x`) 'borrow' it for a while. Just like if you own a
In Rust, the type system encodes the notion of *ownership*. The variable `v`
is an *owner* of the vector. When we make a reference to `v`, we let that
variable (in this case, `x`) *borrow* it for a while. Just like if you own a
book, and you lend it to me, I'm borrowing the book.
So, when I try to modify the vector with the second call to `push`, I need
@ -392,22 +392,23 @@ Here's an example of a concurrent Rust program:
use std::thread::Thread;
fn main() {
for _ in range(0u, 10u) {
Thread::spawn(move || {
let guards: Vec<_> = (0..10).map(|_| {
Thread::scoped(|| {
println!("Hello, world!");
});
}
})
}).collect();
}
```
This program creates ten threads, who all print `Hello, world!`. The
`spawn` function takes one argument, a closure, indicated by the
double bars `||`. (The `move` keyword indicates that the closure takes
ownership of any data it uses; we'll have more on the significance of
this shortly.) This closure is executed in a new thread created by
`spawn`.
This program creates ten threads, which all print `Hello, world!`. The `scoped`
function takes one argument, a closure, indicated by the double bars `||`. This
closure is executed in a new thread created by `scoped`. The method is called
`scoped` because it returns a 'join guard', which will automatically join the
child thread when it goes out of scope. Because we `collect` these guards into
a `Vec<T>`, and that vector goes out of scope at the end of our program, our
program will wait for every thread to finish before finishing.
One common form of problem in concurrent programs is a 'data race.'
One common form of problem in concurrent programs is a *data race*.
This occurs when two different threads attempt to access the same
location in memory in a non-synchronized way, where at least one of
them is a write. If one thread is attempting to read, and one thread
@ -460,9 +461,9 @@ code tries to make three owners. This may cause a safety problem, so
Rust disallows it.
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
"Arc" stands for "atomically reference counted." In other words, an Arc will
*Arc* stands for "atomically reference counted". In other words, an Arc will
keep track of the number of references to something, and not free the
associated resource until the count is zero. The 'atomic' portion refers to an
associated resource until the count is zero. The *atomic* portion refers to an
Arc's usage of concurrency primitives to atomically update the count, making it
safe across threads. If we use an Arc, we can have our three references. But,
an Arc does not allow mutable borrows of the data it holds, and we want to
@ -525,13 +526,13 @@ give us assurance _at compile time_ that we weren't doing something incorrect
with regards to concurrency. In order to share ownership, we were forced to be
explicit and use a mechanism to ensure that it would be properly handled.
# Safety _and_ speed
# Safety _and_ Speed
Safety and speed are always presented as a continuum. On one hand, you have
maximum speed, but no safety. On the other, you have absolute safety, with no
speed. Rust seeks to break out of this mode by introducing safety at compile
time, ensuring that you haven't done anything wrong, while compiling to the
same low-level code you'd expect without the safety.
Safety and speed are always presented as a continuum. At one end of the spectrum,
you have maximum speed, but no safety. On the other end, you have absolute safety
with no speed. Rust seeks to break out of this paradigm by introducing safety at
compile time, ensuring that you haven't done anything wrong, while compiling to
the same low-level code you'd expect without the safety.
As an example, Rust's ownership system is _entirely_ at compile time. The
safety check that makes this an error about moved values:

View File

@ -12,6 +12,7 @@ Looks like you've taken a wrong turn.
Some things that might be helpful to you though:
## Search
* <form action="https://duckduckgo.com/">
<input type="text" id="site-search" name="q" size="80"></input>
<input type="submit" value="Search DuckDuckGo">
@ -19,10 +20,12 @@ Some things that might be helpful to you though:
* Rust doc search: <span id="core-search"></span>
## Reference
* [The Rust official site](http://rust-lang.org)
* [The Rust reference](http://doc.rust-lang.org/reference.html) (* [PDF](http://doc.rust-lang.org/reference.pdf))
* [The Rust reference](http://doc.rust-lang.org/reference.html)
## Docs
* [The standard library](http://doc.rust-lang.org/std/)
<script>

View File

@ -1588,7 +1588,6 @@ pointer values (pointing to a type for which an implementation of the given
trait is in scope) to pointers to the trait name, used as a type.
```
# use std::boxed::Box;
# trait Shape { }
# impl Shape for int { }
# let mycircle = 0i;
@ -1647,7 +1646,6 @@ fn radius_times_area<T: Circle>(c: T) -> f64 {
Likewise, supertrait methods may also be called on trait objects.
```{.ignore}
# use std::boxed::Box;
# trait Shape { fn area(&self) -> f64; }
# trait Circle : Shape { fn radius(&self) -> f64; }
# impl Shape for int { fn area(&self) -> f64 { 0.0 } }
@ -2432,15 +2430,15 @@ There are three different types of inline attributes:
* `#[inline(always)]` asks the compiler to always perform an inline expansion.
* `#[inline(never)]` asks the compiler to never perform an inline expansion.
### Deriving
### Derive
The `deriving` attribute allows certain traits to be automatically implemented
The `derive` attribute allows certain traits to be automatically implemented
for data structures. For example, the following will create an `impl` for the
`PartialEq` and `Clone` traits for `Foo`, the type parameter `T` will be given
the `PartialEq` or `Clone` constraints for the appropriate `impl`:
```
#[deriving(PartialEq, Clone)]
#[derive(PartialEq, Clone)]
struct Foo<T> {
a: int,
b: T
@ -2462,7 +2460,7 @@ impl<T: PartialEq> PartialEq for Foo<T> {
}
```
Supported traits for `deriving` are:
Supported traits for `derive` are:
* Comparison traits: `PartialEq`, `Eq`, `PartialOrd`, `Ord`.
* Serialization: `Encodable`, `Decodable`. These require `serialize`.
@ -2967,8 +2965,8 @@ _panicked state_.
### Unary operator expressions
Rust defines six symbolic unary operators. They are all written as prefix
operators, before the expression they apply to.
Rust defines three unary operators. They are all written as prefix operators,
before the expression they apply to.
* `-`
: Negation. May only be applied to numeric types.
@ -2986,13 +2984,6 @@ operators, before the expression they apply to.
: Logical negation. On the boolean type, this flips between `true` and
`false`. On integer types, this inverts the individual bits in the
two's complement representation of the value.
* `box`
: [Boxing](#pointer-types) operators. Allocate a box to hold the value they
are applied to, and store the value in it. `box` creates a box.
* `&`
: Borrow operator. Returns a reference, pointing to its operand. The operand
of a borrow is statically proven to outlive the resulting pointer. If the
borrow-checker cannot prove this, it is a compilation error.
### Binary operator expressions
@ -3799,7 +3790,6 @@ enclosing `enum` or `struct` type itself. Such recursion has restrictions:
An example of a *recursive* type and its use:
```
# use std::boxed::Box;
enum List<T> {
Nil,
Cons(T, Box<List<T>>)
@ -3912,7 +3902,6 @@ implementation of `R`, and the pointer value of `E`.
An example of an object type:
```
# use std::boxed::Box;
trait Printable {
fn stringify(&self) -> String;
}
@ -4120,7 +4109,6 @@ the type of a box is `std::owned::Box<T>`.
An example of a box type and value:
```
# use std::boxed::Box;
let x: Box<int> = Box::new(10);
```
@ -4130,7 +4118,6 @@ copy of a box to move ownership of the value. After a value has been moved,
the source location cannot be used unless it is reinitialized.
```
# use std::boxed::Box;
let x: Box<int> = Box::new(10);
let y = x;
// attempting to use `x` will result in an error here

View File

@ -195,6 +195,7 @@ h5 a:hover {text-decoration: none;}
pre, code {
font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", monospace;
word-wrap: break-word;
}
pre {
border-left: 2px solid #eee;
@ -204,7 +205,6 @@ pre {
margin: 20px 0;
font-size: 13px;
word-break: break-all;
word-wrap: break-word;
}
code {
padding: 0 2px;
@ -315,6 +315,8 @@ hr {
table {
border-collapse: collapse;
border-spacing: 0;
overflow-x: auto;
display: block;
}
table tr.odd {

View File

@ -198,7 +198,7 @@ Rustdoc also supplies some extra sugar for helping with some tedious
documentation examples. If a line is prefixed with `# `, then the line
will not show up in the HTML documentation, but it will be used when
testing the code block (NB. the space after the `#` is required, so
that one can still write things like `#[deriving(Eq)]`).
that one can still write things like `#[derive(Eq)]`).
~~~md
```
@ -217,6 +217,35 @@ spawn(move || { fib(200); })
The documentation online would look like `spawn(move || { fib(200); })`, but when
testing this code, the `fib` function will be included (so it can compile).
Rustdoc will automatically add a `main()` wrapper around your code, and in the right
place. For example:
```
/// ```
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
/// ```
# fn foo() {}
```
This will end up testing:
```
fn main() {
use std::rc::Rc;
let five = Rc::new(5);
}
```
Here's the full algorithm:
1. Given a code block, if it does not contain `fn main`, it is wrapped in `fn main() { your_code }`
2. Given that result, if it contains no `extern crate` directives but it also
contains the name of the crate being tested, then `extern crate <name>` is
injected at the top.
3. Some common `allow` attributes are added for documentation examples at the top.
## Running tests (advanced)
Running tests often requires some special configuration to filter tests, find

View File

@ -8,7 +8,7 @@ memory safe without using garbage collection.
"The Rust Programming Language" is split into three sections, which you can
navigate through the menu on the left.
## Basics
<h2 class="section-header"><a href="basic.html">Basics</a></h2>
This section is a linear introduction to the basic syntax and semantics of
Rust. It has individual sections on each part of Rust's syntax, and culminates
@ -17,7 +17,7 @@ in a small project: a guessing game.
After reading "Basics," you will have a good foundation to learn more about
Rust, and can write very simple programs.
## Intermediate
<h2 class="section-header"><a href="intermediate.html">Intermediate</a></h2>
This section contains individual chapters, which are self-contained. They focus
on specific topics, and can be read in any order.
@ -25,7 +25,7 @@ on specific topics, and can be read in any order.
After reading "Intermediate," you will have a solid understanding of Rust,
and will be able to understand most Rust code and write more complex programs.
## Advanced
<h2 class="section-header"><a href="advanced.html">Advanced</a></h2>
In a similar fashion to "Intermediate," this section is full of individual,
deep-dive chapters, which stand alone and can be read in any order. These

View File

@ -26,7 +26,7 @@
* [Iterators](iterators.md)
* [Generics](generics.md)
* [Traits](traits.md)
* [Tasks](tasks.md)
* [Threads](threads.md)
* [Error Handling](error-handling.md)
* [III: Advanced Topics](advanced.md)
* [FFI](ffi.md)

View File

@ -82,7 +82,7 @@ arrays:
```{rust}
let a = [0, 1, 2, 3, 4];
let middle = a.slice(1, 4); // A slice of a: just the elements [1,2,3]
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
for e in middle.iter() {
println!("{}", e); // Prints 1, 2, 3

View File

@ -51,7 +51,7 @@ defined. The closure borrows any variables it uses, so this will error:
```{rust,ignore}
fn main() {
let mut x = 5;
let mut x: i32 = 5;
let printer = |&:| { println!("x is: {}", x); };

View File

@ -182,7 +182,7 @@ and with a struct, we have actual names.
There _is_ one case when a tuple struct is very useful, though, and that's a
tuple struct with only one element. We call this a *newtype*, because it lets
you create a new type that's a synonym for another one:
you create a new type that's similar to another one:
```{rust}
struct Inches(i32);
@ -194,7 +194,8 @@ println!("length is {} inches", integer_length);
```
As you can see here, you can extract the inner integer type through a
destructuring `let`.
destructuring `let`, as we discussed previously in 'tuples.' In this case, the
`let Inches(integer_length)` assigns `10` to `integer_length`.
## Enums

View File

@ -181,7 +181,7 @@ errors that can occur.
# Non-recoverable errors with `panic!`
In the case of an error that is unexpected and not recoverable, the `panic!`
macro will induce a panic. This will crash the current task, and give an error:
macro will induce a panic. This will crash the current thread, and give an error:
```{rust,ignore}
panic!("boom");
@ -190,7 +190,7 @@ panic!("boom");
gives
```text
task '<main>' panicked at 'boom', hello.rs:2
thread '<main>' panicked at 'boom', hello.rs:2
```
when you run it.

View File

@ -166,12 +166,12 @@ GitHub](https://github.com/thestinger/rust-snappy).
# Stack management
Rust tasks by default run on a *large stack*. This is actually implemented as a
Rust threads by default run on a *large stack*. This is actually implemented as a
reserving a large segment of the address space and then lazily mapping in pages
as they are needed. When calling an external C function, the code is invoked on
the same stack as the rust stack. This means that there is no extra
stack-switching mechanism in place because it is assumed that the large stack
for the rust task is plenty for the C function to have.
for the rust thread is plenty for the C function to have.
A planned future improvement (not yet implemented at the time of this writing)
is to have a guard page at the end of every rust stack. No rust function will
@ -184,8 +184,8 @@ For normal external function usage, this all means that there shouldn't be any
need for any extra effort on a user's perspective. The C stack naturally
interleaves with the rust stack, and it's "large enough" for both to
interoperate. If, however, it is determined that a larger stack is necessary,
there are appropriate functions in the task spawning API to control the size of
the stack of the task which is spawned.
there are appropriate functions in the thread spawning API to control the size of
the stack of the thread which is spawned.
# Destructors
@ -262,8 +262,6 @@ referenced Rust object.
Rust code:
~~~~no_run
# use std::boxed::Box;
#[repr(C)]
struct RustObject {
a: i32,
@ -320,8 +318,7 @@ In the previously given examples the callbacks are invoked as a direct reaction
to a function call to the external C library.
The control over the current thread is switched from Rust to C to Rust for the
execution of the callback, but in the end the callback is executed on the
same thread (and Rust task) that lead called the function which triggered
the callback.
same thread that called the function which triggered the callback.
Things get more complicated when the external library spawns its own threads
and invokes callbacks from there.
@ -329,7 +326,7 @@ In these cases access to Rust data structures inside the callbacks is
especially unsafe and proper synchronization mechanisms must be used.
Besides classical synchronization mechanisms like mutexes, one possibility in
Rust is to use channels (in `std::comm`) to forward data from the C thread
that invoked the callback into a Rust task.
that invoked the callback into a Rust thread.
If an asynchronous callback targets a special object in the Rust address space
it is also absolutely necessary that no more callbacks are performed by the

View File

@ -142,5 +142,23 @@ fn foo(x: i32) -> i32 {
}
```
The previous definition without `return` may look a bit strange if you haven't
worked in an expression-based language before, but it becomes intutive over
time. If this were production code, we wouldn't write it in that way anyway,
we'd write this:
```rust
fn foo(x: i32) -> i32 {
if x < 5 {
x
} else {
x + 1
}
}
```
Because `if` is an expression, and it's the only expression in this function,
the value will be the result of the `if`.
There are some additional ways to define functions, but they involve features
that we haven't learned about yet, so let's just leave it at that for now.

View File

@ -88,9 +88,9 @@ enum Result<H, N> {
if we wanted to. Convention says that the first generic parameter should be
`T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however.
The `Result<T, E>` type is intended to
be used to return the result of a computation, and to have the ability to
return an error if it didn't work out. Here's an example:
The `Result<T, E>` type is intended to be used to return the result of a
computation, and to have the ability to return an error if it didn't work out.
Here's an example:
```{rust}
let x: Result<f64, String> = Ok(2.3f64);

View File

@ -239,7 +239,7 @@ use std::rand;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -283,7 +283,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -318,7 +318,7 @@ $ cargo build
src/main.rs:20:15: 20:20 error: mismatched types: expected `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String)
src/main.rs:20 match cmp(input, secret_number) {
^~~~~
src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `uint` (expected i32 but found uint)
src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `u32` (expected i32 but found u32)
src/main.rs:20 match cmp(input, secret_number) {
^~~~~~~~~~~~~
error: aborting due to 2 previous errors
@ -328,7 +328,7 @@ This often happens when writing Rust programs, and is one of Rust's greatest
strengths. You try out some code, see if it compiles, and Rust tells you that
you've done something wrong. In this case, our `cmp` function works on integers,
but we've given it unsigned integers. In this case, the fix is easy, because
we wrote the `cmp` function! Let's change it to take `uint`s:
we wrote the `cmp` function! Let's change it to take `u32`s:
```{rust,ignore}
use std::io;
@ -338,7 +338,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -358,7 +358,7 @@ fn main() {
}
}
fn cmp(a: uint, b: uint) -> Ordering {
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
@ -370,13 +370,13 @@ And try compiling again:
```bash
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String)
src/main.rs:20:15: 20:20 error: mismatched types: expected `u32` but found `collections::string::String` (expected u32 but found struct collections::string::String)
src/main.rs:20 match cmp(input, secret_number) {
^~~~~
error: aborting due to previous error
```
This error is similar to the last one: we expected to get a `uint`, but we got
This error is similar to the last one: we expected to get a `u32`, but we got
a `String` instead! That's because our `input` variable is coming from the
standard input, and you can guess anything. Try it:
@ -393,14 +393,14 @@ Oops! Also, you'll note that we just ran our program even though it didn't compi
This works because the older version we did successfully compile was still lying
around. Gotta be careful!
Anyway, we have a `String`, but we need a `uint`. What to do? Well, there's
Anyway, we have a `String`, but we need a `u32`. What to do? Well, there's
a function for that:
```{rust,ignore}
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = input.parse();
let input_num: Option<u32> = input.parse();
```
The `parse` function takes in a `&str` value and converts it into something.
@ -408,22 +408,22 @@ We tell it what kind of something with a type hint. Remember our type hint with
`random()`? It looked like this:
```{rust,ignore}
rand::random::<uint>();
rand::random::<u32>();
```
There's an alternate way of providing a hint too, and that's declaring the type
in a `let`:
```{rust,ignore}
let x: uint = rand::random();
let x: u32 = rand::random();
```
In this case, we say `x` is a `uint` explicitly, so Rust is able to properly
In this case, we say `x` is a `u32` explicitly, so Rust is able to properly
tell `random()` what to generate. In a similar fashion, both of these work:
```{rust,ignore}
let input_num = "5".parse::<uint>(); // input_num: Option<uint>
let input_num: Option<uint> = "5".parse(); // input_num: Option<uint>
let input_num = "5".parse::<u32>(); // input_num: Option<u32>
let input_num: Option<u32> = "5".parse(); // input_num: Option<u32>
```
Anyway, with us now converting our input to a number, our code looks like this:
@ -436,7 +436,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -445,7 +445,7 @@ fn main() {
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = input.parse();
let input_num: Option<u32> = input.parse();
println!("You guessed: {}", input_num);
@ -456,7 +456,7 @@ fn main() {
}
}
fn cmp(a: uint, b: uint) -> Ordering {
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
@ -468,13 +468,13 @@ Let's try it out!
```bash
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option<uint>` (expected uint but found enum core::option::Option)
src/main.rs:22:15: 22:24 error: mismatched types: expected `u32` but found `core::option::Option<u32>` (expected u32 but found enum core::option::Option)
src/main.rs:22 match cmp(input_num, secret_number) {
^~~~~~~~~
error: aborting due to previous error
```
Oh yeah! Our `input_num` has the type `Option<uint>`, rather than `uint`. We
Oh yeah! Our `input_num` has the type `Option<u32>`, rather than `u32`. We
need to unwrap the Option. If you remember from before, `match` is a great way
to do that. Try this code:
@ -486,7 +486,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -495,7 +495,7 @@ fn main() {
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = input.parse();
let input_num: Option<u32> = input.parse();
let num = match input_num {
Some(num) => num,
@ -515,14 +515,14 @@ fn main() {
}
}
fn cmp(a: uint, b: uint) -> Ordering {
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
We use a `match` to either give us the `uint` inside of the `Option`, or else
We use a `match` to either give us the `u32` inside of the `Option`, or else
print an error message and return. Let's give this a shot:
```bash
@ -553,7 +553,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -562,7 +562,7 @@ fn main() {
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = input.trim().parse();
let input_num: Option<u32> = input.trim().parse();
let num = match input_num {
Some(num) => num,
@ -582,7 +582,7 @@ fn main() {
}
}
fn cmp(a: uint, b: uint) -> Ordering {
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
@ -627,7 +627,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -638,7 +638,7 @@ fn main() {
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = input.trim().parse();
let input_num: Option<u32> = input.trim().parse();
let num = match input_num {
Some(num) => num,
@ -659,7 +659,7 @@ fn main() {
}
}
fn cmp(a: uint, b: uint) -> Ordering {
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
@ -703,7 +703,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -714,7 +714,7 @@ fn main() {
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = input.trim().parse();
let input_num: Option<u32> = input.trim().parse();
let num = match input_num {
Some(num) => num,
@ -738,7 +738,7 @@ fn main() {
}
}
fn cmp(a: uint, b: uint) -> Ordering {
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
@ -759,7 +759,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
@ -770,7 +770,7 @@ fn main() {
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = input.trim().parse();
let input_num: Option<u32> = input.trim().parse();
let num = match input_num {
Some(num) => num,
@ -794,7 +794,7 @@ fn main() {
}
}
fn cmp(a: uint, b: uint) -> Ordering {
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
@ -838,7 +838,7 @@ use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<uint>() % 100u) + 1u;
let secret_number = (rand::random::<u32>() % 100) + 1;
loop {
@ -847,7 +847,7 @@ fn main() {
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = input.trim().parse();
let input_num: Option<u32> = input.trim().parse();
let num = match input_num {
Some(num) => num,
@ -871,7 +871,7 @@ fn main() {
}
}
fn cmp(a: uint, b: uint) -> Ordering {
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }

View File

@ -71,8 +71,8 @@ These lines define a *function* in Rust. The `main` function is special:
it's the beginning of every Rust program. The first line says "I'm declaring a
function named `main`, which takes no arguments and returns nothing." If there
were arguments, they would go inside the parentheses (`(` and `)`), and because
we aren't returning anything from this function, we've dropped that notation
entirely. We'll get to it later.
we aren't returning anything from this function, we can omit the return type
entirely. We'll get to it later.
You'll also note that the function is wrapped in curly braces (`{` and `}`).
Rust requires these around all function bodies. It is also considered good

View File

@ -42,7 +42,7 @@ the pattern in the above code:
# 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)`
($inp:expr, $sp:path) => ( // invoke it like `(input_5, SpecialE)`
match $inp {
$sp(x) => { return x; }
_ => {}
@ -59,7 +59,7 @@ early_return!(input_2, T::SpecialB);
~~~~
Macros are defined in pattern-matching style: in the above example, the text
`($inp:expr $sp:ident)` that appears on the left-hand side of the `=>` is the
`($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.
@ -74,6 +74,8 @@ conforms to the following rules:
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.
@ -86,7 +88,8 @@ To take a fragment of Rust code as an argument, write `$` followed by a name
`foo`.)
* `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;
`f(42)`.)
* `ty` (a type. Examples: `int`, `Vec<(char, String)>`, `&T`.)
* `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; }`)
@ -97,6 +100,12 @@ 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
@ -571,7 +580,7 @@ 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](plugin.html) instead. Compared to `macro_rules!`
[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

View File

@ -81,7 +81,6 @@ therefore deallocates the memory for you. Here's the equivalent example in
Rust:
```rust
# use std::boxed::Box;
{
let x = Box::new(5);
}
@ -101,7 +100,6 @@ This is pretty straightforward, but what happens when we want to pass our box
to a function? Let's look at some code:
```rust
# use std::boxed::Box;
fn main() {
let x = Box::new(5);
@ -117,7 +115,6 @@ This code works, but it's not ideal. For example, let's add one more line of
code, where we print out the value of `x`:
```{rust,ignore}
# use std::boxed::Box;
fn main() {
let x = Box::new(5);
@ -151,7 +148,6 @@ To fix this, we can have `add_one` give ownership back when it's done with the
box:
```rust
# use std::boxed::Box;
fn main() {
let x = Box::new(5);
@ -207,6 +203,26 @@ fn add_one(num: &mut i32) {
This function borrows an `i32` from its caller, and then increments it. When
the function is over, and `num` goes out of scope, the borrow is over.
We have to change our `main` a bit too:
```rust
fn main() {
let mut x = 5;
add_one(&mut x);
println!("{}", x);
}
fn add_one(num: &mut i32) {
*num += 1;
}
```
We don't need to assign the result of `add_one()` anymore, because it doesn't
return anything anymore. This is because we're not passing ownership back,
since we just borrow, not take ownership.
# Lifetimes
Lending out a reference to a resource that someone else owns can be
@ -225,7 +241,7 @@ To fix this, we have to make sure that step four never happens after step
three. The ownership system in Rust does this through a concept called
*lifetimes*, which describe the scope that a reference is valid for.
Let's look at that function which borrows an `i32` again:
Remember the function that borrowed an `i32`? Let's look at it again.
```rust
fn add_one(num: &i32) -> i32 {

View File

@ -126,7 +126,7 @@ The advantages over a simple `fn(&str) -> uint` are:
a way to define new literal syntax for any data type.
In addition to procedural macros, you can define new
[`deriving`](../reference.html#deriving)-like attributes and other kinds of
[`derive`](../reference.html#derive)-like attributes and other kinds of
extensions. See
[`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
and the [`SyntaxExtension`

View File

@ -455,7 +455,6 @@ fn rc_succ(x: Rc<int>) -> int { *x + 1 }
Note that the caller of your function will have to modify their calls slightly:
```{rust}
# use std::boxed::Box;
use std::rc::Rc;
fn succ(x: &int) -> int { *x + 1 }
@ -478,7 +477,6 @@ those contents.
heap allocation in Rust. Creating a box looks like this:
```{rust}
# use std::boxed::Box;
let x = Box::new(5i);
```
@ -486,7 +484,6 @@ Boxes are heap allocated and they are deallocated automatically by Rust when
they go out of scope:
```{rust}
# use std::boxed::Box;
{
let x = Box::new(5i);
@ -507,7 +504,6 @@ You don't need to fully grok the theory of affine types or regions to grok
boxes, though. As a rough approximation, you can treat this Rust code:
```{rust}
# use std::boxed::Box;
{
let x = Box::new(5i);
@ -548,7 +544,6 @@ for more detail on how lifetimes work.
Using boxes and references together is very common. For example:
```{rust}
# use std::boxed::Box;
fn add_one(x: &int) -> int {
*x + 1
}
@ -566,7 +561,6 @@ function, and since it's only reading the value, allows it.
We can borrow `x` multiple times, as long as it's not simultaneous:
```{rust}
# use std::boxed::Box;
fn add_one(x: &int) -> int {
*x + 1
}
@ -583,7 +577,6 @@ fn main() {
Or as long as it's not a mutable borrow. This will error:
```{rust,ignore}
# use std::boxed::Box;
fn add_one(x: &mut int) -> int {
*x + 1
}
@ -610,7 +603,6 @@ Sometimes, you need a recursive data structure. The simplest is known as a
```{rust}
# use std::boxed::Box;
#[derive(Show)]
enum List<T> {
Cons(T, Box<List<T>>),
@ -666,7 +658,6 @@ In many languages with pointers, you'd return a pointer from a function
so as to avoid copying a large data structure. For example:
```{rust}
# use std::boxed::Box;
struct BigStruct {
one: int,
two: int,
@ -695,7 +686,6 @@ than the hundred `int`s that make up the `BigStruct`.
This is an antipattern in Rust. Instead, write this:
```{rust}
# use std::boxed::Box;
struct BigStruct {
one: int,
two: int,
@ -721,11 +711,10 @@ fn main() {
This gives you flexibility without sacrificing performance.
You may think that this gives us terrible performance: return a value and then
immediately box it up ?! Isn't that the worst of both worlds? Rust is smarter
than that. There is no copy in this code. `main` allocates enough room for the
`box`, passes a pointer to that memory into `foo` as `x`, and then `foo` writes
the value straight into that pointer. This writes the return value directly into
the allocated box.
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
smarter than that. There is no copy in this code. `main` allocates enough room
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
`foo` writes the value straight into the `Box<T>`.
This is important enough that it bears repeating: pointers are not for
optimizing returning values from your code. Allow the caller to choose how they

View File

@ -96,7 +96,7 @@ test it_works ... FAILED
failures:
---- it_works stdout ----
task 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
@ -105,7 +105,7 @@ failures:
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
task '<main>' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
thread '<main>' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
```
Rust indicates that our test failed:
@ -254,7 +254,6 @@ a large module, and so this is a common use of the `glob` feature. Let's change
our `src/lib.rs` to make use of it:
```{rust,ignore}
#![feature(globs)]
pub fn add_two(a: i32) -> i32 {
a + 2
@ -271,8 +270,7 @@ mod tests {
}
```
Note the `feature` attribute, as well as the different `use` line. Now we run
our tests:
Note the different `use` line. Now we run our tests:
```bash
$ cargo test
@ -370,8 +368,6 @@ with examples:
//! assert_eq!(4, adder::add_two(2));
//! ```
#![feature(globs)]
/// This function adds two to its argument.
///
/// # Examples
@ -440,8 +436,6 @@ Rust also supports benchmark tests, which can test the performance of your
code. Let's make our `src/lib.rs` look like this (comments elided):
```{rust,ignore}
#![feature(globs)]
extern crate test;
pub fn add_two(a: i32) -> i32 {

View File

@ -315,3 +315,76 @@ The names don't actually change to this, it's just for illustration. But
as you can see, there's no overhead of deciding which version to call here,
hence *statically dispatched*. The downside is that we have two copies of
the same function, so our binary is a little bit larger.
## Our `inverse` Example
Back in [Generics](generics.html), we were trying to write code like this:
```{rust,ignore}
fn inverse<T>(x: T) -> Result<T, String> {
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
Ok(1.0 / x)
}
```
If we try to compile it, we get this error:
```text
error: binary operation `==` cannot be applied to type `T`
```
This is because `T` is too generic: we don't know if a random `T` can be
compared. For that, we can use trait bounds. It doesn't quite work, but try
this:
```{rust,ignore}
fn inverse<T: PartialEq>(x: T) -> Result<T, String> {
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
Ok(1.0 / x)
}
```
You should get this error:
```text
error: mismatched types:
expected `T`,
found `_`
(expected type parameter,
found floating-point variable)
```
So this won't work. While our `T` is `PartialEq`, we expected to have another `T`,
but instead, we found a floating-point variable. We need a different bound. `Float`
to the rescue:
```
use std::num::Float;
fn inverse<T: Float>(x: T) -> Result<T, String> {
if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
let one: T = Float::one();
Ok(one / x)
}
```
We've had to replace our generic `0.0` and `1.0` with the appropriate methods
from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function
works just fine:
```
# use std::num::Float;
# fn inverse<T: Float>(x: T) -> Result<T, String> {
# if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
# let one: T = Float::one();
# Ok(one / x)
# }
println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32));
println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64));
println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32));
println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64));
```

View File

@ -182,7 +182,7 @@ code:
- implement the `Drop` for resource clean-up via a destructor, and use
RAII (Resource Acquisition Is Initialization). This reduces the need
for any manual memory management by users, and automatically ensures
that clean-up is always run, even when the task panics.
that clean-up is always run, even when the thread panics.
- ensure that any data stored behind a raw pointer is destroyed at the
appropriate time.
@ -197,7 +197,6 @@ extern crate libc;
use libc::{c_void, size_t, malloc, free};
use std::mem;
use std::ptr;
# use std::boxed::Box;
// Define a wrapper around the handle returned by the foreign code.
// Unique<T> has the same semantics as Box<T>
@ -499,7 +498,7 @@ library, but without it you must define your own.
The first of these three functions, `stack_exhausted`, is invoked whenever stack
overflow is detected. This function has a number of restrictions about how it
can be called and what it must do, but if the stack limit register is not being
maintained then a task always has an "infinite stack" and this function
maintained then a thread always has an "infinite stack" and this function
shouldn't get triggered.
The second of these three functions, `eh_personality`, is used by the
@ -530,7 +529,6 @@ vectors provided from C, using idiomatic Rust practices.
```
#![no_std]
#![feature(globs)]
#![feature(lang_items)]
# extern crate libc;

View File

@ -89,25 +89,7 @@ what you need, so it's not verboten.
Let's get back to bindings. Rust variable bindings have one more aspect that
differs from other languages: bindings are required to be initialized with a
value before you're allowed to use them. If we try...
```{ignore}
let x;
```
...we'll get an error:
```text
src/main.rs:2:9: 2:10 error: unable to infer enough type information about `_`; type annotations required
src/main.rs:2 let x;
^
```
Giving it a type will compile, though:
```{rust}
let x: i32;
```
value before you're allowed to use them.
Let's try it out. Change your `src/main.rs` file to look like this:

View File

@ -1,3 +1,3 @@
% The Rust Tutorial
This tutorial has been deprecated in favor of [the Guide](guide.html). Go check that out instead!
This tutorial has been deprecated in favor of [the Book](book/index.html). Go check that out instead!

View File

@ -194,8 +194,13 @@ LIT_STR_RAW
: 'r' LIT_STR_RAW_INNER SUFFIX?
;
QUESTION : '?';
IDENT : XID_start XID_continue* ;
fragment QUESTION_IDENTIFIER : QUESTION? IDENT;
LIFETIME : '\'' IDENT ;
WHITESPACE : [ \r\n\t]+ ;

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(globs, plugin)]
#![feature(plugin)]
extern crate syntax;
extern crate rustc;
@ -107,13 +107,14 @@ fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
"LE" => token::Le,
"LIT_BINARY" => token::Literal(token::Binary(Name(0)), None),
"LIT_BINARY_RAW" => token::Literal(token::BinaryRaw(Name(0), 0), None),
"QUESTION" => token::Question,
_ => continue,
};
res.insert(num.to_string(), tok);
}
debug!("Token map: {}", res);
debug!("Token map: {:?}", res);
res
}
@ -161,7 +162,7 @@ fn fixchar(mut lit: &str) -> ast::Name {
parse::token::intern(lit.slice(1, lit.len() - 1))
}
fn count(lit: &str) -> uint {
fn count(lit: &str) -> usize {
lit.chars().take_while(|c| *c == '#').count()
}
@ -176,12 +177,12 @@ fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAn
let toknum = m.name("toknum").unwrap_or("");
let content = m.name("content").unwrap_or("");
let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map",
let proto_tok = tokens.get(toknum).expect(format!("didn't find token {:?} in the map",
toknum).as_slice());
let nm = parse::token::intern(content);
debug!("What we got: content (`{}`), proto: {}", content, proto_tok);
debug!("What we got: content (`{}`), proto: {:?}", content, proto_tok);
let real_tok = match *proto_tok {
token::BinOp(..) => token::BinOp(str_to_binop(content)),
@ -265,7 +266,7 @@ fn main() {
continue
}
assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
assert!(rustc_tok.sp == antlr_tok.sp, "{:?} and {:?} have different spans", rustc_tok,
antlr_tok);
macro_rules! matches {
@ -276,12 +277,12 @@ fn main() {
if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) {
// FIXME #15677: needs more robust escaping in
// antlr
warn!("Different names for {} and {}", rustc_tok, antlr_tok);
warn!("Different names for {:?} and {:?}", rustc_tok, antlr_tok);
}
}
_ => panic!("{} is not {}", antlr_tok, rustc_tok)
_ => panic!("{:?} is not {:?}", antlr_tok, rustc_tok)
},)*
ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
ref c => assert!(c == &antlr_tok.tok, "{:?} is not {:?}", rustc_tok, antlr_tok)
}
)
}

View File

@ -2526,7 +2526,7 @@ mod bitv_bench {
for _ in range(0u, 100) {
bitv |= 1 << ((r.next_u32() as uint) % u32::BITS);
}
black_box(&bitv)
black_box(&bitv);
});
}
@ -2538,7 +2538,7 @@ mod bitv_bench {
for _ in range(0u, 100) {
bitv.set((r.next_u32() as uint) % BENCH_BITS, true);
}
black_box(&bitv)
black_box(&bitv);
});
}

View File

@ -1422,7 +1422,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
#[cfg(test)]
mod test {
use prelude::*;
use std::borrow::BorrowFrom;
use super::{BTreeMap, Occupied, Vacant};

View File

@ -18,6 +18,8 @@ use core::cmp::Ordering::{self, Less, Greater, Equal};
use core::default::Default;
use core::fmt::Show;
use core::fmt;
// NOTE(stage0) remove import after a snapshot
#[cfg(stage0)]
use core::hash::Hash;
use core::iter::{Peekable, Map, FromIterator};
use core::ops::{BitOr, BitAnd, BitXor, Sub};

View File

@ -1,4 +1,4 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -230,7 +230,7 @@ impl<T> DList<T> {
///
/// # Examples
///
/// ```rust
/// ```
/// use std::collections::DList;
///
/// let mut a = DList::new();
@ -304,6 +304,18 @@ impl<T> DList<T> {
/// Returns `true` if the `DList` is empty.
///
/// This operation should compute in O(1) time.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut dl = DList::new();
/// assert!(dl.is_empty());
///
/// dl.push_front("foo");
/// assert!(!dl.is_empty());
/// ```
#[inline]
#[stable]
pub fn is_empty(&self) -> bool {
@ -313,6 +325,24 @@ impl<T> DList<T> {
/// Returns the length of the `DList`.
///
/// This operation should compute in O(1) time.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut dl = DList::new();
///
/// dl.push_front(2is);
/// assert_eq!(dl.len(), 1);
///
/// dl.push_front(1);
/// assert_eq!(dl.len(), 2);
///
/// dl.push_back(3);
/// assert_eq!(dl.len(), 3);
///
/// ```
#[inline]
#[stable]
pub fn len(&self) -> uint {
@ -322,6 +352,24 @@ impl<T> DList<T> {
/// Removes all elements from the `DList`.
///
/// This operation should compute in O(n) time.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut dl = DList::new();
///
/// dl.push_front(2is);
/// dl.push_front(1);
/// assert_eq!(dl.len(), 2);
/// assert_eq!(dl.front(), Some(&1is));
///
/// dl.clear();
/// assert_eq!(dl.len(), 0);
/// assert_eq!(dl.front(), None);
///
/// ```
#[inline]
#[stable]
pub fn clear(&mut self) {
@ -330,6 +378,19 @@ impl<T> DList<T> {
/// Provides a reference to the front element, or `None` if the list is
/// empty.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut dl = DList::new();
/// assert_eq!(dl.front(), None);
///
/// dl.push_front(1);
/// assert_eq!(dl.front(), Some(&1is));
///
/// ```
#[inline]
#[stable]
pub fn front(&self) -> Option<&T> {
@ -338,6 +399,25 @@ impl<T> DList<T> {
/// Provides a mutable reference to the front element, or `None` if the list
/// is empty.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut dl = DList::new();
/// assert_eq!(dl.front(), None);
///
/// dl.push_front(1);
/// assert_eq!(dl.front(), Some(&1is));
///
/// match dl.front_mut() {
/// None => {},
/// Some(x) => *x = 5is,
/// }
/// assert_eq!(dl.front(), Some(&5is));
///
/// ```
#[inline]
#[stable]
pub fn front_mut(&mut self) -> Option<&mut T> {
@ -346,6 +426,19 @@ impl<T> DList<T> {
/// Provides a reference to the back element, or `None` if the list is
/// empty.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut dl = DList::new();
/// assert_eq!(dl.back(), None);
///
/// dl.push_back(1);
/// assert_eq!(dl.back(), Some(&1is));
///
/// ```
#[inline]
#[stable]
pub fn back(&self) -> Option<&T> {
@ -354,6 +447,25 @@ impl<T> DList<T> {
/// Provides a mutable reference to the back element, or `None` if the list
/// is empty.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut dl = DList::new();
/// assert_eq!(dl.back(), None);
///
/// dl.push_back(1);
/// assert_eq!(dl.back(), Some(&1is));
///
/// match dl.back_mut() {
/// None => {},
/// Some(x) => *x = 5is,
/// }
/// assert_eq!(dl.back(), Some(&5is));
///
/// ```
#[inline]
#[stable]
pub fn back_mut(&mut self) -> Option<&mut T> {
@ -363,6 +475,21 @@ impl<T> DList<T> {
/// Adds an element first in the list.
///
/// This operation should compute in O(1) time.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut dl = DList::new();
///
/// dl.push_front(2is);
/// assert_eq!(dl.front().unwrap(), &2is);
///
/// dl.push_front(1);
/// assert_eq!(dl.front().unwrap(), &1);
///
/// ```
#[stable]
pub fn push_front(&mut self, elt: T) {
self.push_front_node(box Node::new(elt))
@ -372,6 +499,23 @@ impl<T> DList<T> {
/// empty.
///
/// This operation should compute in O(1) time.
///
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut d = DList::new();
/// assert_eq!(d.pop_front(), None);
///
/// d.push_front(1is);
/// d.push_front(3);
/// assert_eq!(d.pop_front(), Some(3));
/// assert_eq!(d.pop_front(), Some(1));
/// assert_eq!(d.pop_front(), None);
///
/// ```
///
#[stable]
pub fn pop_front(&mut self) -> Option<T> {
self.pop_front_node().map(|box Node{value, ..}| value)
@ -381,7 +525,7 @@ impl<T> DList<T> {
///
/// # Examples
///
/// ```rust
/// ```
/// use std::collections::DList;
///
/// let mut d = DList::new();
@ -399,7 +543,7 @@ impl<T> DList<T> {
///
/// # Examples
///
/// ```rust
/// ```
/// use std::collections::DList;
///
/// let mut d = DList::new();
@ -417,6 +561,22 @@ impl<T> DList<T> {
/// including the index.
///
/// This operation should compute in O(n) time.
/// # Examples
///
/// ```
/// use std::collections::DList;
///
/// let mut d = DList::new();
///
/// d.push_front(1is);
/// d.push_front(2);
/// d.push_front(3);
///
/// let mut splitted = d.split_off(2);
///
/// assert_eq!(splitted.pop_front(), Some(1));
/// assert_eq!(splitted.pop_front(), None);
/// ```
#[stable]
pub fn split_off(&mut self, at: uint) -> DList<T> {
let len = self.len();
@ -593,7 +753,7 @@ impl<'a, A> IterMut<'a, A> {
///
/// # Examples
///
/// ```rust
/// ```
/// use std::collections::DList;
///
/// let mut list: DList<int> = vec![1, 3, 4].into_iter().collect();
@ -619,7 +779,7 @@ impl<'a, A> IterMut<'a, A> {
///
/// # Examples
///
/// ```rust
/// ```
/// use std::collections::DList;
///
/// let mut list: DList<int> = vec![1, 2, 3].into_iter().collect();

View File

@ -2841,7 +2841,7 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
b.iter(|| {
for ch in s.chars() { black_box(ch) }
for ch in s.chars() { black_box(ch); }
});
}
@ -2869,7 +2869,7 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
b.iter(|| {
for ch in s.chars().rev() { black_box(ch) }
for ch in s.chars().rev() { black_box(ch); }
});
}

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A growable list type, written `Vec<T>` but pronounced 'vector.'
//! A growable list type with heap-allocated contents, written `Vec<T>` but pronounced 'vector.'
//!
//! Vectors have `O(1)` indexing, push (to the end) and pop (from the end).
//!
@ -1511,6 +1511,9 @@ pub struct IntoIter<T> {
end: *const T
}
unsafe impl<T: Send> Send for IntoIter<T> { }
unsafe impl<T: Sync> Sync for IntoIter<T> { }
impl<T> IntoIter<T> {
#[inline]
/// Drops all items that have not yet been moved and returns the empty vector.

View File

@ -198,6 +198,10 @@ extern "rust-intrinsic" {
pub fn pref_align_of<T>() -> uint;
/// Get a static pointer to a type descriptor.
#[cfg(not(stage0))]
pub fn get_tydesc<T: ?Sized>() -> *const TyDesc;
#[cfg(stage0)]
pub fn get_tydesc<T>() -> *const TyDesc;
/// Gets an identifier which is globally unique to the specified type. This

View File

@ -66,7 +66,6 @@
//! not (`None`).
//!
//! ```
//! # use std::boxed::Box;
//! let optional: Option<Box<int>> = None;
//! check_optional(&optional);
//!

View File

@ -46,7 +46,6 @@
//! though unsafely, transformed from one type to the other.
//!
//! ```
//! # use std::boxed::Box;
//! use std::mem;
//!
//! unsafe {

View File

@ -119,7 +119,7 @@
//! drop(file);
//! ```
//!
//! If you *do* write that in Rust, the compiler will by give you a
//! If you *do* write that in Rust, the compiler will give you a
//! warning (by default, controlled by the `unused_must_use` lint).
//!
//! You might instead, if you don't want to handle the error, simply
@ -178,13 +178,11 @@
//! fn write_info(info: &Info) -> Result<(), IoError> {
//! let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write);
//! // Early return on error
//! match file.write_line(format!("name: {}", info.name).as_slice()) {
//! Ok(_) => (),
//! Err(e) => return Err(e)
//! if let Err(e) = file.write_line(format!("name: {}", info.name).as_slice()) {
//! return Err(e)
//! }
//! match file.write_line(format!("age: {}", info.age).as_slice()) {
//! Ok(_) => (),
//! Err(e) => return Err(e)
//! if let Err(e) = file.write_line(format!("age: {}", info.age).as_slice()) {
//! return Err(e)
//! }
//! return file.write_line(format!("rating: {}", info.rating).as_slice());
//! }

View File

@ -35,9 +35,6 @@
#![stable]
#[unstable = "this is just a documentation module and should not be part \
of the public api"]
use clone::Clone;
use cmp::*;
use cmp::Ordering::*;

View File

@ -28,6 +28,8 @@ pub struct LabelledCFG<'a, 'ast: 'a> {
pub ast_map: &'a ast_map::Map<'ast>,
pub cfg: &'a cfg::CFG,
pub name: String,
/// `labelled_edges` controls whether we emit labels on the edges
pub labelled_edges: bool,
}
fn replace_newline_with_backslash_l(s: String) -> String {
@ -75,6 +77,9 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> {
let mut label = String::new();
if !self.labelled_edges {
return dot::LabelText::EscStr(label.into_cow());
}
let mut put_one = false;
for (i, &node_id) in e.data.exiting_scopes.iter().enumerate() {
if put_one {

View File

@ -12,7 +12,7 @@
//
// There are various parts of the compiler that must impose arbitrary limits
// on how deeply they recurse to prevent stack overflow. Users can override
// this via an attribute on the crate like `#![recursion_limit(22)]`. This pass
// this via an attribute on the crate like `#![recursion_limit="22"]`. This pass
// just peeks and looks for that attribute.
use session::Session;
@ -34,6 +34,6 @@ pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) {
}
sess.span_err(attr.span, "malformed recursion limit attribute, \
expected #![recursion_limit(\"N\")]");
expected #![recursion_limit=\"N\"]");
}
}

View File

@ -22,6 +22,8 @@ use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
use util::common::can_reach;
use std::cell::RefCell;
// NOTE(stage0) remove import after a snapshot
#[cfg(stage0)]
use std::hash::{Hash};
use syntax::codemap::Span;
use syntax::{ast, visit};

View File

@ -2605,12 +2605,17 @@ impl FlagComputation {
&ty_projection(ref data) => {
self.add_flags(HAS_PROJECTION);
self.add_substs(data.trait_ref.substs);
self.add_projection_ty(data);
}
&ty_trait(box TyTrait { ref principal, ref bounds }) => {
let mut computation = FlagComputation::new();
computation.add_substs(principal.0.substs);
for projection_bound in bounds.projection_bounds.iter() {
let mut proj_computation = FlagComputation::new();
proj_computation.add_projection_predicate(&projection_bound.0);
computation.add_bound_computation(&proj_computation);
}
self.add_bound_computation(&computation);
self.add_bounds(bounds);
@ -2674,6 +2679,15 @@ impl FlagComputation {
}
}
fn add_projection_predicate(&mut self, projection_predicate: &ProjectionPredicate) {
self.add_projection_ty(&projection_predicate.projection_ty);
self.add_ty(projection_predicate.ty);
}
fn add_projection_ty(&mut self, projection_ty: &ProjectionTy) {
self.add_substs(projection_ty.trait_ref.substs);
}
fn add_substs(&mut self, substs: &Substs) {
self.add_tys(substs.types.as_slice());
match substs.regions {
@ -4133,12 +4147,8 @@ pub fn node_id_to_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId)
}
}
pub fn try_node_id_to_type<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Option<Ty<'tcx>> {
cx.node_types.borrow().get(&id).cloned()
}
pub fn node_id_to_type<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Ty<'tcx> {
match try_node_id_to_type(cx, id) {
match node_id_to_type_opt(cx, id) {
Some(ty) => ty,
None => cx.sess.bug(
&format!("node_id_to_type: no type for node `{}`",

View File

@ -1430,7 +1430,7 @@ impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> {
impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("<{} as {}>::{}",
self.trait_ref.self_ty().repr(tcx),
self.trait_ref.substs.self_ty().repr(tcx),
self.trait_ref.repr(tcx),
self.item_name.repr(tcx))
}

View File

@ -103,6 +103,13 @@ pub fn compile_input(sess: Session,
write_out_deps(&sess, input, &outputs, &id[]);
controller_entry_point!(after_write_deps,
CompileState::state_after_write_deps(input,
&sess,
outdir,
&ast_map,
&id[]));
let arenas = ty::CtxtArenas::new();
let analysis = phase_3_run_analysis_passes(sess,
ast_map,
@ -176,6 +183,7 @@ pub fn source_name(input: &Input) -> String {
pub struct CompileController<'a> {
pub after_parse: PhaseController<'a>,
pub after_expand: PhaseController<'a>,
pub after_write_deps: PhaseController<'a>,
pub after_analysis: PhaseController<'a>,
pub after_llvm: PhaseController<'a>,
@ -187,6 +195,7 @@ impl<'a> CompileController<'a> {
CompileController {
after_parse: PhaseController::basic(),
after_expand: PhaseController::basic(),
after_write_deps: PhaseController::basic(),
after_analysis: PhaseController::basic(),
after_llvm: PhaseController::basic(),
make_glob_map: resolve::MakeGlobMap::No,
@ -271,6 +280,19 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> {
}
}
fn state_after_write_deps(input: &'a Input,
session: &'a Session,
out_dir: &'a Option<Path>,
ast_map: &'a ast_map::Map<'ast>,
crate_name: &'a str)
-> CompileState<'a, 'ast, 'tcx> {
CompileState {
crate_name: Some(crate_name),
ast_map: Some(ast_map),
.. CompileState::empty(input, session, out_dir)
}
}
fn state_after_analysis(input: &'a Input,
session: &'a Session,
out_dir: &'a Option<Path>,

View File

@ -207,7 +207,7 @@ fn build_controller<'a>(sess: &Session) -> CompileController<'a> {
}
if sess.opts.no_analysis || sess.opts.debugging_opts.ast_json {
control.after_expand.stop = true;
control.after_write_deps.stop = true;
}
if sess.opts.no_trans {

View File

@ -53,10 +53,20 @@ pub enum PpSourceMode {
PpmExpandedHygiene,
}
#[derive(Copy, PartialEq, Show)]
pub enum PpFlowGraphMode {
Default,
/// Drops the labels from the edges in the flowgraph output. This
/// is mostly for use in the --xpretty flowgraph run-make tests,
/// since the labels are largely uninteresting in those cases and
/// have become a pain to maintain.
UnlabelledEdges,
}
#[derive(Copy, PartialEq, Show)]
pub enum PpMode {
PpmSource(PpSourceMode),
PpmFlowGraph,
PpmFlowGraph(PpFlowGraphMode),
}
pub fn parse_pretty(sess: &Session,
@ -73,12 +83,13 @@ pub fn parse_pretty(sess: &Session,
("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
("identified", _) => PpmSource(PpmIdentified),
("flowgraph", true) => PpmFlowGraph,
("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default),
("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges),
_ => {
if extended {
sess.fatal(format!(
"argument to `xpretty` must be one of `normal`, \
`expanded`, `flowgraph=<nodeid>`, `typed`, `identified`, \
`expanded`, `flowgraph[,unlabelled]=<nodeid>`, `typed`, `identified`, \
`expanded,identified`, or `everybody_loops`; got {}", name).as_slice());
} else {
sess.fatal(format!(
@ -417,7 +428,7 @@ fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
PpmSource(PpmExpandedIdentified) |
PpmSource(PpmExpandedHygiene) |
PpmSource(PpmTyped) |
PpmFlowGraph => true
PpmFlowGraph(_) => true
}
}
@ -431,7 +442,7 @@ fn needs_expansion(ppm: &PpMode) -> bool {
PpmSource(PpmExpandedIdentified) |
PpmSource(PpmExpandedHygiene) |
PpmSource(PpmTyped) |
PpmFlowGraph => true
PpmFlowGraph(_) => true
}
}
@ -589,7 +600,7 @@ pub fn pretty_print_input(sess: Session,
pp::eof(&mut pp_state.s)
}),
(PpmFlowGraph, opt_uii) => {
(PpmFlowGraph(mode), opt_uii) => {
debug!("pretty printing flow graph for {:?}", opt_uii);
let uii = opt_uii.unwrap_or_else(|| {
sess.fatal(&format!("`pretty flowgraph=..` needs NodeId (int) or
@ -613,7 +624,7 @@ pub fn pretty_print_input(sess: Session,
&arenas,
id,
resolve::MakeGlobMap::No);
print_flowgraph(variants, analysis, code, out)
print_flowgraph(variants, analysis, code, mode, out)
}
None => {
let message = format!("--pretty=flowgraph needs \
@ -635,20 +646,23 @@ pub fn pretty_print_input(sess: Session,
fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>,
analysis: ty::CrateAnalysis,
code: blocks::Code,
mode: PpFlowGraphMode,
mut out: W) -> io::IoResult<()> {
let ty_cx = &analysis.ty_cx;
let cfg = match code {
blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block),
blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()),
};
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
let lcfg = LabelledCFG {
ast_map: &ty_cx.map,
cfg: &cfg,
name: format!("node_{}", code.id()),
labelled_edges: labelled_edges,
};
match code {
_ if variants.len() == 0 => {
let lcfg = LabelledCFG {
ast_map: &ty_cx.map,
cfg: &cfg,
name: format!("node_{}", code.id()),
};
let r = dot::render(&lcfg, &mut out);
return expand_err_details(r);
}
@ -662,11 +676,6 @@ fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>,
let (bccx, analysis_data) =
borrowck::build_borrowck_dataflow_data_for_fn(ty_cx, fn_parts);
let lcfg = LabelledCFG {
ast_map: &ty_cx.map,
cfg: &cfg,
name: format!("node_{}", code.id()),
};
let lcfg = borrowck_dot::DataflowLabeller {
inner: lcfg,
variants: variants,

View File

@ -167,7 +167,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
let opt = sess.opts.cg.opt_level.unwrap_or(0) as libc::c_uint;
let builder = llvm::LLVMPassManagerBuilderCreate();
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt);
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
/* Internalize = */ False,
/* RunInliner = */ True);

View File

@ -201,7 +201,7 @@ use middle::pat_util::*;
use trans::adt;
use trans::base::*;
use trans::build::{AddCase, And, BitCast, Br, CondBr, GEPi, InBoundsGEP, Load};
use trans::build::{Mul, Not, Store, Sub, add_comment};
use trans::build::{Not, Store, Sub, add_comment};
use trans::build;
use trans::callee;
use trans::cleanup::{self, CleanupMethods};
@ -630,8 +630,7 @@ fn bind_subslice_pat(bcx: Block,
let vec_datum = match_datum(val, vec_ty);
let (base, len) = vec_datum.get_vec_base_and_len(bcx);
let slice_byte_offset = Mul(bcx, vt.llunit_size, C_uint(bcx.ccx(), offset_left));
let slice_begin = tvec::pointer_add_byte(bcx, base, slice_byte_offset);
let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]);
let slice_len_offset = C_uint(bcx.ccx(), offset_left + offset_right);
let slice_len = Sub(bcx, len, slice_len_offset);
let slice_ty = ty::mk_slice(bcx.tcx(),
@ -857,16 +856,9 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
}
debug!("binding {} to {}",
binding_info.id,
bcx.val_to_string(llval));
debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval));
bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum);
if bcx.sess().opts.debuginfo == FullDebugInfo {
debuginfo::create_match_binding_metadata(bcx,
ident,
binding_info);
}
debuginfo::create_match_binding_metadata(bcx, ident, binding_info);
}
bcx
}

View File

@ -44,7 +44,7 @@ use middle::subst;
use middle::weak_lang_items;
use middle::subst::{Subst, Substs};
use middle::ty::{self, Ty, UnboxedClosureTyper};
use session::config::{self, NoDebugInfo, FullDebugInfo};
use session::config::{self, NoDebugInfo};
use session::Session;
use trans::_match;
use trans::adt;
@ -544,15 +544,6 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
}
// Structural comparison: a rather involved form of glue.
pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
if cx.sess().opts.cg.save_temps {
let buf = CString::from_slice(s.as_bytes());
unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) }
}
}
// Used only for creating scalar comparison glue.
#[derive(Copy)]
pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
@ -1626,9 +1617,8 @@ fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>(
result
}
fn copy_args_to_allocas<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>,
fn copy_args_to_allocas<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
arg_scope: cleanup::CustomScopeIndex,
bcx: Block<'blk, 'tcx>,
args: &[ast::Arg],
arg_datums: Vec<RvalueDatum<'tcx>>)
-> Block<'blk, 'tcx> {
@ -1649,10 +1639,7 @@ fn copy_args_to_allocas<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>,
// the event it's not truly needed.
bcx = _match::store_arg(bcx, &*args[i].pat, arg_datum, arg_scope_id);
if fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
debuginfo::create_argument_metadata(bcx, &args[i]);
}
debuginfo::create_argument_metadata(bcx, &args[i]);
}
bcx
@ -1702,9 +1689,7 @@ fn copy_unboxed_closure_args_to_allocas<'blk, 'tcx>(
tuple_element_datum,
arg_scope_id);
if bcx.fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
debuginfo::create_argument_metadata(bcx, &args[j]);
}
debuginfo::create_argument_metadata(bcx, &args[j]);
}
bcx
@ -1877,9 +1862,8 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
bcx = match closure_env.kind {
closure::NotClosure | closure::BoxedClosure(..) => {
copy_args_to_allocas(&fcx,
copy_args_to_allocas(bcx,
arg_scope,
bcx,
&decl.inputs[],
arg_datums)
}

View File

@ -217,12 +217,15 @@ pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>,
ty::type_contents(cx, ty).needs_drop(cx)
}
fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: Ty<'tcx>) -> bool {
fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
match ty.sty {
ty::ty_struct(def_id, substs) => {
let fields = ty::struct_fields(ccx.tcx(), def_id, substs);
fields.len() == 1 && type_is_immediate(ccx, fields[0].mt.ty)
let fields = ty::lookup_struct_fields(ccx.tcx(), def_id);
fields.len() == 1 && {
let ty = ty::lookup_field_type(ccx.tcx(), def_id, fields[0].id, substs);
let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty);
type_is_immediate(ccx, ty)
}
}
_ => false
}

View File

@ -28,7 +28,6 @@ use trans::type_::Type;
use trans;
use middle::ty;
use middle::ty::MethodCall;
use session::config::FullDebugInfo;
use util::ppaux::Repr;
use util::ppaux;
@ -66,10 +65,7 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
match d.node {
ast::DeclLocal(ref local) => {
bcx = init_local(bcx, &**local);
if cx.sess().opts.debuginfo == FullDebugInfo {
trans::debuginfo::create_local_var_metadata(bcx,
&**local);
}
debuginfo::create_local_var_metadata(bcx, &**local);
}
// Inner items are visited by `trans_item`/`trans_meth`.
ast::DeclItem(_) => {},

View File

@ -323,28 +323,26 @@ impl<'tcx> TypeMap<'tcx> {
fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>,
type_: Ty<'tcx>) -> UniqueTypeId {
// basic type -> {:name of the type:}
// tuple -> {tuple_(:param-uid:)*}
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
// enum variant -> {variant_:variant-name:_:enum-uid:}
// reference (&) -> {& :pointee-uid:}
// mut reference (&mut) -> {&mut :pointee-uid:}
// ptr (*) -> {* :pointee-uid:}
// mut ptr (*mut) -> {*mut :pointee-uid:}
// unique ptr (~) -> {~ :pointee-uid:}
// @-ptr (@) -> {@ :pointee-uid:}
// sized vec ([T; x]) -> {[:size:] :element-uid:}
// unsized vec ([T]) -> {[] :element-uid:}
// trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
// closure -> {<unsafe_> <once_> :store-sigil:
// |(:param-uid:),* <,_...>| -> \
// :return-type-uid: : (:bounds:)*}
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
// :return-type-uid:}
// unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>}
// gc box -> {GC_BOX<:pointee-uid:>}
// projection (<T as U>::V) -> {<:ty-uid: as :trait-uid:> :: :name-uid: }
// basic type -> {:name of the type:}
// tuple -> {tuple_(:param-uid:)*}
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
// enum variant -> {variant_:variant-name:_:enum-uid:}
// reference (&) -> {& :pointee-uid:}
// mut reference (&mut) -> {&mut :pointee-uid:}
// ptr (*) -> {* :pointee-uid:}
// mut ptr (*mut) -> {*mut :pointee-uid:}
// unique ptr (~) -> {~ :pointee-uid:}
// @-ptr (@) -> {@ :pointee-uid:}
// sized vec ([T; x]) -> {[:size:] :element-uid:}
// unsized vec ([T]) -> {[] :element-uid:}
// trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
// closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
// :return-type-uid: : (:bounds:)*}
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
// :return-type-uid:}
// unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>}
// gc box -> {GC_BOX<:pointee-uid:>}
match self.type_to_unique_id.get(&type_).cloned() {
Some(unique_type_id) => return unique_type_id,
@ -437,25 +435,6 @@ impl<'tcx> TypeMap<'tcx> {
principal.substs,
&mut unique_type_id);
},
ty::ty_projection(ref projection) => {
unique_type_id.push_str("<");
let self_ty = projection.trait_ref.self_ty();
let self_type_id = self.get_unique_type_id_of_type(cx, self_ty);
let self_type_id = self.get_unique_type_id_as_string(self_type_id);
unique_type_id.push_str(&self_type_id[]);
unique_type_id.push_str(" as ");
from_def_id_and_substs(self,
cx,
projection.trait_ref.def_id,
projection.trait_ref.substs,
&mut unique_type_id);
unique_type_id.push_str(">::");
unique_type_id.push_str(token::get_name(projection.item_name).get());
},
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
if unsafety == ast::Unsafety::Unsafe {
unique_type_id.push_str("unsafe ");
@ -499,10 +478,7 @@ impl<'tcx> TypeMap<'tcx> {
closure_ty,
&mut unique_type_id);
},
ty::ty_err |
ty::ty_infer(_) |
ty::ty_open(_) |
ty::ty_param(_) => {
_ => {
cx.sess().bug(&format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
&ppaux::ty_to_string(cx.tcx(), type_)[],
type_.sty)[])
@ -878,7 +854,9 @@ pub fn create_global_var_metadata(cx: &CrateContext,
/// local in `bcx.fcx.lllocals`.
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
if bcx.unreachable.get() ||
fn_should_be_ignored(bcx.fcx) ||
bcx.sess().opts.debuginfo != FullDebugInfo {
return;
}
@ -922,7 +900,9 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
env_index: uint,
captured_by_ref: bool,
span: Span) {
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
if bcx.unreachable.get() ||
fn_should_be_ignored(bcx.fcx) ||
bcx.sess().opts.debuginfo != FullDebugInfo {
return;
}
@ -1005,7 +985,9 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
variable_ident: ast::Ident,
binding: BindingInfo<'tcx>) {
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
if bcx.unreachable.get() ||
fn_should_be_ignored(bcx.fcx) ||
bcx.sess().opts.debuginfo != FullDebugInfo {
return;
}
@ -1045,7 +1027,9 @@ pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
/// argument in `bcx.fcx.lllocals`.
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
if bcx.unreachable.get() ||
fn_should_be_ignored(bcx.fcx) ||
bcx.sess().opts.debuginfo != FullDebugInfo {
return;
}
@ -1099,7 +1083,9 @@ pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
/// loop variable in `bcx.fcx.lllocals`.
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_for_loop_var_metadata(bcx: Block, pat: &ast::Pat) {
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
if bcx.unreachable.get() ||
fn_should_be_ignored(bcx.fcx) ||
bcx.sess().opts.debuginfo != FullDebugInfo {
return;
}
@ -3880,22 +3866,10 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
ty::ty_unboxed_closure(..) => {
output.push_str("closure");
}
ty::ty_projection(ref projection) => {
output.push_str("<");
let self_ty = projection.trait_ref.self_ty();
push_debuginfo_type_name(cx, self_ty, true, output);
output.push_str(" as ");
push_item_name(cx, projection.trait_ref.def_id, false, output);
push_type_params(cx, projection.trait_ref.substs, output);
output.push_str(">::");
output.push_str(token::get_name(projection.item_name).get());
}
ty::ty_err |
ty::ty_infer(_) |
ty::ty_open(_) |
ty::ty_projection(..) |
ty::ty_param(_) => {
cx.sess().bug(&format!("debuginfo: Trying to create type name for \
unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t))[]);

View File

@ -768,7 +768,6 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
tvec::vec_types(bcx,
ty::sequence_element_type(bcx.tcx(),
base_datum.ty));
base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
let (base, len) = base_datum.get_vec_base_and_len(bcx);

View File

@ -346,12 +346,14 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info:
let align_ptr = GEPi(bcx, info, &[2u]);
(Load(bcx, size_ptr), Load(bcx, align_ptr))
}
ty::ty_vec(unit_ty, None) => {
// The info in this case is the length of the vec, so the size is that
ty::ty_vec(_, None) | ty::ty_str => {
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
// The info in this case is the length of the str, so the size is that
// times the unit size.
let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
let unit_align = llalign_of_min(bcx.ccx(), llunit_ty);
let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
(Mul(bcx, info, C_uint(bcx.ccx(), unit_size)), C_uint(bcx.ccx(), 8u))
(Mul(bcx, info, C_uint(bcx.ccx(), unit_size)), C_uint(bcx.ccx(), unit_align))
}
_ => bcx.sess().bug(&format!("Unexpected unsized type, found {}",
bcx.ty_to_string(t))[])
@ -456,8 +458,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
&[PointerCast(bcx, Load(bcx, lluniquevalue), Type::i8p(bcx.ccx()))],
None);
bcx
}
ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty, false),
},
ty::ty_vec(_, None) | ty::ty_str => {
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
tvec::make_drop_glue_unboxed(bcx, v0, unit_ty, false)
},
_ => {
assert!(type_is_sized(bcx.tcx(), t));
if type_needs_drop(bcx.tcx(), t) &&

View File

@ -82,17 +82,6 @@ pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
return C_uint(cx, llsize_of_alloc(cx, ty));
}
// Returns the "default" size of t (see above), or 1 if the size would
// be zero. This is important for things like vectors that expect
// space to be consumed.
pub fn nonzero_llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
if llbitsize_of_real(cx, ty) == 0 {
unsafe { llvm::LLVMConstInt(cx.int_type().to_ref(), 1, False) }
} else {
llsize_of(cx, ty)
}
}
// Returns the preferred alignment of the given type for the current target.
// The preferred alignment may be larger than the alignment used when
// packing the type into structs. This will be used for things like

View File

@ -288,6 +288,17 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
param_substs,
callee_substs)
}
traits::VtableObject(ref data) => {
let trait_item_def_ids =
ty::trait_item_def_ids(ccx.tcx(), trait_id);
let method_offset_in_trait =
trait_item_def_ids.iter()
.position(|item| item.def_id() == method_id)
.unwrap();
let (llfn, ty) =
trans_object_shim(ccx, data.object_ty, trait_id, method_offset_in_trait);
immediate_rvalue(llfn, ty)
}
_ => {
tcx.sess.bug(&format!("static call to invalid vtable: {}",
vtbl.repr(tcx))[]);
@ -371,7 +382,7 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Callee { bcx: bcx, data: Fn(llfn) }
}
traits::VtableObject(ref data) => {
let llfn = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method);
let (llfn, _) = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method);
Callee { bcx: bcx, data: Fn(llfn) }
}
traits::VtableBuiltin(..) |
@ -540,7 +551,7 @@ pub fn trans_object_shim<'a, 'tcx>(
object_ty: Ty<'tcx>,
trait_id: ast::DefId,
method_offset_in_trait: uint)
-> ValueRef
-> (ValueRef, Ty<'tcx>)
{
let _icx = push_ctxt("trans_object_shim");
let tcx = ccx.tcx();
@ -667,7 +678,7 @@ pub fn trans_object_shim<'a, 'tcx>(
finish_fn(&fcx, bcx, sig.output);
llfn
(llfn, method_bare_fn_ty)
}
/// Creates a returns a dynamic vtable for the given type and vtable origin.

View File

@ -25,7 +25,7 @@ use trans::expr::{Dest, Ignore, SaveIn};
use trans::expr;
use trans::glue;
use trans::machine;
use trans::machine::{nonzero_llsize_of, llsize_of_alloc};
use trans::machine::llsize_of_alloc;
use trans::type_::Type;
use trans::type_of;
use middle::ty::{self, Ty};
@ -44,13 +44,6 @@ fn get_dataptr(bcx: Block, vptr: ValueRef) -> ValueRef {
Load(bcx, expr::get_dataptr(bcx, vptr))
}
pub fn pointer_add_byte(bcx: Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
let _icx = push_ctxt("tvec::pointer_add_byte");
let old_ty = val_ty(ptr);
let bptr = PointerCast(bcx, ptr, Type::i8p(bcx.ccx()));
return PointerCast(bcx, InBoundsGEP(bcx, bptr, &[bytes]), old_ty);
}
pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
vptr: ValueRef,
unit_ty: Ty<'tcx>,
@ -94,17 +87,14 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
pub struct VecTypes<'tcx> {
pub unit_ty: Ty<'tcx>,
pub llunit_ty: Type,
pub llunit_size: ValueRef,
pub llunit_alloc_size: u64
}
impl<'tcx> VecTypes<'tcx> {
pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
format!("VecTypes {{unit_ty={}, llunit_ty={}, \
llunit_size={}, llunit_alloc_size={}}}",
format!("VecTypes {{unit_ty={}, llunit_ty={}, llunit_alloc_size={}}}",
ty_to_string(ccx.tcx(), self.unit_ty),
ccx.tn().type_to_string(self.llunit_ty),
ccx.tn().val_to_string(self.llunit_size),
self.llunit_alloc_size)
}
}
@ -333,13 +323,11 @@ pub fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-> VecTypes<'tcx> {
let ccx = bcx.ccx();
let llunit_ty = type_of::type_of(ccx, unit_ty);
let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);
VecTypes {
unit_ty: unit_ty,
llunit_ty: llunit_ty,
llunit_size: llunit_size,
llunit_alloc_size: llunit_alloc_size
}
}
@ -486,17 +474,13 @@ pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
let fcx = bcx.fcx;
let vt = vec_types(bcx, unit_ty);
let fill = Mul(bcx, len, vt.llunit_size);
if vt.llunit_alloc_size == 0 {
// Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
iter_vec_loop(bcx, data_ptr, &vt, fill, f)
iter_vec_loop(bcx, data_ptr, &vt, len, f)
} else {
// Calculate the last pointer address we want to handle.
// FIXME (#3729): Optimize this when the size of the unit type is
// statically known to not use pointer casts, which tend to confuse
// LLVM.
let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]);
// Now perform the iteration.
let header_bcx = fcx.new_temp_block("iter_vec_loop_header");

View File

@ -516,8 +516,15 @@ pub fn instantiate_poly_trait_ref<'tcx>(
{
let mut projections = Vec::new();
// the trait reference introduces a binding level here, so
// we need to shift the `rscope`. It'd be nice if we could
// do away with this rscope stuff and work this knowledge
// into resolve_lifetimes, as we do with non-omitted
// lifetimes. Oh well, not there yet.
let shifted_rscope = ShiftedRscope::new(rscope);
let trait_ref =
instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref,
instantiate_trait_ref(this, &shifted_rscope, &ast_trait_ref.trait_ref,
self_ty, Some(&mut projections));
for projection in projections.into_iter() {
@ -561,6 +568,29 @@ pub fn instantiate_trait_ref<'tcx>(
}
}
fn object_path_to_poly_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
trait_def_id: ast::DefId,
path: &ast::Path,
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
// we are introducing a binder here, so shift the
// anonymous regions depth to account for that
let shifted_rscope = ShiftedRscope::new(rscope);
let mut tmp = Vec::new();
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
&shifted_rscope,
trait_def_id,
None,
path,
Some(&mut tmp)));
projections.extend(tmp.into_iter().map(ty::Binder));
trait_ref
}
fn ast_path_to_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
@ -573,13 +603,6 @@ fn ast_path_to_trait_ref<'a,'tcx>(
debug!("ast_path_to_trait_ref {:?}", path);
let trait_def = this.get_trait_def(trait_def_id);
// the trait reference introduces a binding level here, so
// we need to shift the `rscope`. It'd be nice if we could
// do away with this rscope stuff and work this knowledge
// into resolve_lifetimes, as we do with non-omitted
// lifetimes. Oh well, not there yet.
let shifted_rscope = ShiftedRscope::new(rscope);
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
ast::AngleBracketedParameters(ref data) => {
// For now, require that parenthetical notation be used
@ -595,7 +618,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
the crate attributes to enable");
}
convert_angle_bracketed_parameters(this, &shifted_rscope, data)
convert_angle_bracketed_parameters(this, rscope, data)
}
ast::ParenthesizedParameters(ref data) => {
// For now, require that parenthetical notation be used
@ -616,7 +639,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
};
let substs = create_substs_for_ast_path(this,
&shifted_rscope,
rscope,
path.span,
&trait_def.generics,
self_ty,
@ -851,15 +874,11 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
match this.tcx().def_map.borrow().get(&id) {
Some(&def::DefTrait(trait_def_id)) => {
let mut projection_bounds = Vec::new();
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
rscope,
trait_def_id,
None,
path,
Some(&mut projection_bounds)));
let projection_bounds = projection_bounds.into_iter()
.map(ty::Binder)
.collect();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
trait_def_id,
path,
&mut projection_bounds);
Ok((trait_ref, projection_bounds))
}
_ => {
@ -1098,16 +1117,13 @@ pub fn ast_ty_to_ty<'tcx>(
// N.B. this case overlaps somewhat with
// TyObjectSum, see that fn for details
let mut projection_bounds = Vec::new();
let trait_ref = ast_path_to_trait_ref(this,
rscope,
trait_def_id,
None,
path,
Some(&mut projection_bounds));
let trait_ref = ty::Binder(trait_ref);
let projection_bounds = projection_bounds.into_iter()
.map(ty::Binder)
.collect();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
trait_def_id,
path,
&mut projection_bounds);
trait_ref_to_object_type(this, rscope, path.span,
trait_ref, projection_bounds, &[])
}

View File

@ -0,0 +1,48 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementations checker: builtin traits and default impls are allowed just
//! for structs and enums.
use middle::ty;
use syntax::ast::{Item, ItemImpl};
use syntax::ast;
use syntax::visit;
pub fn check(tcx: &ty::ctxt) {
let mut impls = ImplsChecker { tcx: tcx };
visit::walk_crate(&mut impls, tcx.map.krate());
}
struct ImplsChecker<'cx, 'tcx:'cx> {
tcx: &'cx ty::ctxt<'tcx>
}
impl<'cx, 'tcx,'v> visit::Visitor<'v> for ImplsChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v ast::Item) {
match item.node {
ast::ItemImpl(_, _, _, Some(ref opt_trait), _, _) => {
let trait_ref = ty::node_id_to_trait_ref(self.tcx, opt_trait.ref_id);
if let Some(_) = self.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
match trait_ref.self_ty().sty {
ty::ty_struct(..) | ty::ty_enum(..) => {}
_ => {
self.tcx.sess.span_err(
item.span,
&format!("builtin traits can only be \
implemented on structs or enums")[]);
}
}
}
}
_ => {}
}
}
}

View File

@ -49,6 +49,7 @@ use syntax::visit;
use util::nodemap::{DefIdMap, FnvHashMap};
use util::ppaux::Repr;
mod impls;
mod orphan;
mod overlap;
mod unsafety;
@ -596,6 +597,7 @@ pub fn check_coherence(crate_context: &CrateCtxt) {
inference_context: new_infer_ctxt(crate_context.tcx),
inherent_impls: RefCell::new(FnvHashMap::new()),
}.check(crate_context.tcx.map.krate());
impls::check(crate_context.tcx);
unsafety::check(crate_context.tcx);
orphan::check(crate_context.tcx);
overlap::check(crate_context.tcx);

View File

@ -91,6 +91,7 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches,
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="rustdoc">
<title>{title}</title>

View File

@ -21,6 +21,8 @@ use prelude::v1::*;
use collections::HashMap;
use ffi::CString;
use fmt;
// NOTE(stage0) remove import after a snapshot
#[cfg(stage0)]
use hash::Hash;
use io::pipe::{PipeStream, PipePair};
use io::{IoResult, IoError};

View File

@ -374,9 +374,13 @@ impl Rng for ThreadRng {
/// `random()` can generate various types of random things, and so may require
/// type hinting to generate the specific type you want.
///
/// This function uses the thread local random number generator. This means
/// that if you're calling `random()` in a loop, caching the generator can
/// increase performance. An example is shown below.
///
/// # Examples
///
/// ```rust
/// ```
/// use std::rand;
///
/// let x = rand::random();
@ -389,6 +393,27 @@ impl Rng for ThreadRng {
/// println!("Better lucky than good!");
/// }
/// ```
///
/// Caching the thread local random number generator:
///
/// ```
/// use std::rand;
/// use std::rand::Rng;
///
/// let mut v = vec![1, 2, 3];
///
/// for x in v.iter_mut() {
/// *x = rand::random()
/// }
///
/// // would be faster as
///
/// let mut rng = rand::thread_rng();
///
/// for x in v.iter_mut() {
/// *x = rng.gen();
/// }
/// ```
#[inline]
pub fn random<T: Rand>() -> T {
thread_rng().gen()

View File

@ -63,6 +63,12 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
'statement: loop {
match state {
Asm => {
if asm_str_style.is_some() {
// If we already have a string with instructions,
// ending up in Asm state again is an error.
cx.span_err(sp, "malformed inline assembly");
return DummyResult::expr(sp);
}
let (s, style) = match expr_to_string(cx, p.parse_expr(),
"inline assembly must be a string literal") {
Some((s, st)) => (s, st),

View File

@ -92,11 +92,10 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
let recurse = vec!(cx.ident_of(krate),
cx.ident_of("Decodable"),
cx.ident_of("decode"));
let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
// throw an underscore in front to suppress unused variable warnings
let blkarg = cx.ident_of("_d");
let blkdecoder = cx.expr_ident(trait_span, blkarg);
let calldecode = cx.expr_call_global(trait_span, recurse, vec!(blkdecoder.clone()));
let lambdadecode = cx.lambda_expr_1(trait_span, calldecode, blkarg);
return match *substr.fields {
StaticStruct(_, ref summary) => {
@ -116,7 +115,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
cx.expr_method_call(span, blkdecoder.clone(), read_struct_field,
vec!(cx.expr_str(span, name),
cx.expr_uint(span, field),
lambdadecode.clone())))
exprdecode.clone())))
});
let result = cx.expr_ok(trait_span, result);
cx.expr_method_call(trait_span,
@ -147,7 +146,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
let idx = cx.expr_uint(span, field);
cx.expr_try(span,
cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg,
vec!(idx, lambdadecode.clone())))
vec!(idx, exprdecode.clone())))
});
arms.push(cx.arm(v_span,

View File

@ -21,13 +21,7 @@
//! (e.g. `Option<T>`), the parameters are automatically given the
//! current trait as a bound. (This includes separate type parameters
//! and lifetimes for methods.)
//! - Additional bounds on the type parameters, e.g. the `Ord` instance
//! requires an explicit `PartialEq` bound at the
//! moment. (`TraitDef.additional_bounds`)
//!
//! Unsupported: FIXME #6257: calling methods on reference fields,
//! e.g. derive Eq/Ord/Clone don't work on `struct A(&int)`,
//! because of how the auto-dereferencing happens.
//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
//!
//! The most important thing for implementers is the `Substructure` and
//! `SubstructureFields` objects. The latter groups 5 possibilities of the
@ -79,6 +73,15 @@
//! enums (one for each variant). For empty struct and empty enum
//! variants, it is represented as a count of 0.
//!
//! # "`cs`" functions
//!
//! The `cs_...` functions ("combine substructure) are designed to
//! make life easier by providing some pre-made recipes for common
//! tasks; mostly calling the function being derived on all the
//! arguments and then combining them back together in some way (or
//! letting the user chose that). They are not meant to be the only
//! way to handle the structures that this code creates.
//!
//! # Examples
//!
//! The following simplified `PartialEq` is used for in-code examples:
@ -102,22 +105,22 @@
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
//!
//! ```{.text}
//! Struct(~[FieldInfo {
//! Struct(vec![FieldInfo {
//! span: <span of x>
//! name: Some(<ident of x>),
//! self_: <expr for &self.x>,
//! other: ~[<expr for &other.x]
//! other: vec![<expr for &other.x]
//! }])
//! ```
//!
//! For the `B` impl, called with `B(a)` and `B(b)`,
//!
//! ```{.text}
//! Struct(~[FieldInfo {
//! Struct(vec![FieldInfo {
//! span: <span of `int`>,
//! name: None,
//! <expr for &a>
//! ~[<expr for &b>]
//! self_: <expr for &a>
//! other: vec![<expr for &b>]
//! }])
//! ```
//!
@ -128,11 +131,11 @@
//!
//! ```{.text}
//! EnumMatching(0, <ast::Variant for C0>,
//! ~[FieldInfo {
//! vec![FieldInfo {
//! span: <span of int>
//! name: None,
//! self_: <expr for &a>,
//! other: ~[<expr for &b>]
//! other: vec![<expr for &b>]
//! }])
//! ```
//!
@ -140,11 +143,11 @@
//!
//! ```{.text}
//! EnumMatching(1, <ast::Variant for C1>,
//! ~[FieldInfo {
//! vec![FieldInfo {
//! span: <span of x>
//! name: Some(<ident of x>),
//! self_: <expr for &self.x>,
//! other: ~[<expr for &other.x>]
//! other: vec![<expr for &other.x>]
//! }])
//! ```
//!
@ -152,7 +155,7 @@
//!
//! ```{.text}
//! EnumNonMatchingCollapsed(
//! ~[<ident of self>, <ident of __arg_1>],
//! vec![<ident of self>, <ident of __arg_1>],
//! &[<ast::Variant for C0>, <ast::Variant for C1>],
//! &[<ident for self index value>, <ident of __arg_1 index value>])
//! ```
@ -168,16 +171,16 @@
//!
//! ## Static
//!
//! A static method on the above would result in,
//! A static method on the types above would result in,
//!
//! ```{.text}
//! StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
//! StaticStruct(<ast::StructDef of A>, Named(vec![(<ident of x>, <span of x>)]))
//!
//! StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
//! StaticStruct(<ast::StructDef of B>, Unnamed(vec![<span of x>]))
//!
//! StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
//! (<ident of C1>, <span of C1>,
//! Named(~[(<ident of x>, <span of x>)]))])
//! StaticEnum(<ast::EnumDef of C>,
//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of int>])),
//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
//! ```
pub use self::StaticFields::*;
@ -1378,8 +1381,8 @@ pub fn cs_fold<F>(use_foldl: bool,
/// process the collected results. i.e.
///
/// ```
/// f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
/// self_2.method(__arg_1_2, __arg_2_2)])
/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
/// self_2.method(__arg_1_2, __arg_2_2)])
/// ```
#[inline]
pub fn cs_same_method<F>(f: F,

View File

@ -65,9 +65,19 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
[ref state_expr] => state_expr,
_ => cx.span_bug(trait_span, "incorrect number of arguments in `deriving(Hash)`")
};
let hash_ident = substr.method_ident;
let call_hash = |&: span, thing_expr| {
let expr = cx.expr_method_call(span, thing_expr, hash_ident, vec!(state_expr.clone()));
let hash_path = {
let strs = vec![
cx.ident_of("std"),
cx.ident_of("hash"),
cx.ident_of("Hash"),
cx.ident_of("hash"),
];
cx.expr_path(cx.path_global(span, strs))
};
let ref_thing = cx.expr_addr_of(span, thing_expr);
let expr = cx.expr_call(span, hash_path, vec!(ref_thing, state_expr.clone()));
cx.stmt_expr(expr)
};
let mut stmts = Vec::new();

View File

@ -24,14 +24,6 @@ use ptr::P;
pub enum ObsoleteSyntax {
Sized,
ForSized,
OwnedType,
OwnedExpr,
OwnedPattern,
OwnedVector,
OwnedSelf,
ImportRenaming,
SubsliceMatch,
ExternCrateRenaming,
ProcType,
ProcExpr,
ClosureType,
@ -69,38 +61,6 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
"`proc` expression",
"use a `move ||` expression instead",
),
ObsoleteSyntax::OwnedType => (
"`~` notation for owned pointers",
"use `Box<T>` in `std::owned` instead"
),
ObsoleteSyntax::OwnedExpr => (
"`~` notation for owned pointer allocation",
"use the `box` operator instead of `~`"
),
ObsoleteSyntax::OwnedPattern => (
"`~` notation for owned pointer patterns",
"use the `box` operator instead of `~`"
),
ObsoleteSyntax::OwnedVector => (
"`~[T]` is no longer a type",
"use the `Vec` type instead"
),
ObsoleteSyntax::OwnedSelf => (
"`~self` is no longer supported",
"write `self: Box<Self>` instead"
),
ObsoleteSyntax::ImportRenaming => (
"`use foo = bar` syntax",
"write `use bar as foo` instead"
),
ObsoleteSyntax::SubsliceMatch => (
"subslice match syntax",
"instead of `..xs`, write `xs..` in a pattern"
),
ObsoleteSyntax::ExternCrateRenaming => (
"`extern crate foo = bar` syntax",
"write `extern crate bar as foo` instead"
),
ObsoleteSyntax::ClosureType => (
"`|uint| -> bool` closure type syntax",
"use unboxed closures instead, no type annotation needed"

View File

@ -52,7 +52,7 @@ use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
use ast::{TtDelimited, TtSequence, TtToken};
use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
use ast::{TypeField, TyFixedLengthVec, TyBareFn};
use ast::{TyFixedLengthVec, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
@ -71,7 +71,7 @@ use parse::attr::ParserAttr;
use parse::classify;
use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
use parse::lexer::{Reader, TokenAndSpan};
use parse::obsolete::*;
use parse::obsolete::{ParserObsoleteMethods, ObsoleteSyntax};
use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString};
use parse::token::{keywords, special_idents, SpecialMacroVar};
use parse::{new_sub_parser_from_file, ParseSess};
@ -1404,22 +1404,6 @@ impl<'a> Parser<'a> {
MutTy { ty: t, mutbl: mutbl }
}
/// Parse [mut/const/imm] ID : TY
/// now used only by obsolete record syntax parser...
pub fn parse_ty_field(&mut self) -> TypeField {
let lo = self.span.lo;
let mutbl = self.parse_mutability();
let id = self.parse_ident();
self.expect(&token::Colon);
let ty = self.parse_ty_sum();
let hi = ty.span.hi;
ast::TypeField {
ident: id,
mt: MutTy { ty: ty, mutbl: mutbl },
span: mk_sp(lo, hi),
}
}
/// Parse optional return type [ -> TY ] in function decl
pub fn parse_ret_ty(&mut self) -> FunctionRetTy {
if self.eat(&token::RArrow) {
@ -1506,17 +1490,6 @@ impl<'a> Parser<'a> {
} else {
TyTup(ts)
}
} else if self.token == token::Tilde {
// OWNED POINTER
self.bump();
let last_span = self.last_span;
match self.token {
token::OpenDelim(token::Bracket) => {
self.obsolete(last_span, ObsoleteSyntax::OwnedVector)
}
_ => self.obsolete(last_span, ObsoleteSyntax::OwnedType)
}
TyTup(vec![self.parse_ty()])
} else if self.check(&token::BinOp(token::Star)) {
// STAR POINTER (bare pointer?)
self.bump();
@ -2830,20 +2803,6 @@ impl<'a> Parser<'a> {
hi = e.span.hi;
ex = ExprAddrOf(m, e);
}
token::Tilde => {
self.bump();
let last_span = self.last_span;
match self.token {
token::OpenDelim(token::Bracket) => {
self.obsolete(last_span, ObsoleteSyntax::OwnedVector)
},
_ => self.obsolete(last_span, ObsoleteSyntax::OwnedExpr)
}
let e = self.parse_prefix_expr();
hi = e.span.hi;
ex = self.mk_unary(UnUniq, e);
}
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
// A range, closed above: `..expr`.
self.bump();
@ -3249,10 +3208,6 @@ impl<'a> Parser<'a> {
span: self.span,
}));
before_slice = false;
} else {
let _ = self.parse_pat();
let span = self.span;
self.obsolete(span, ObsoleteSyntax::SubsliceMatch);
}
continue
}
@ -3361,20 +3316,6 @@ impl<'a> Parser<'a> {
span: mk_sp(lo, hi)
})
}
token::Tilde => {
// parse ~pat
self.bump();
let sub = self.parse_pat();
pat = PatBox(sub);
let last_span = self.last_span;
hi = last_span.hi;
self.obsolete(last_span, ObsoleteSyntax::OwnedPattern);
return P(ast::Pat {
id: ast::DUMMY_NODE_ID,
node: pat,
span: mk_sp(lo, hi)
})
}
token::BinOp(token::And) | token::AndAnd => {
// parse &pat and &mut pat
let lo = self.span.lo;
@ -4483,16 +4424,6 @@ impl<'a> Parser<'a> {
self_ident_hi = self.last_span.hi;
eself
}
token::Tilde => {
// We need to make sure it isn't a type
if self.look_ahead(1, |t| t.is_keyword(keywords::Self)) {
self.bump();
drop(self.expect_self_ident());
let last_span = self.last_span;
self.obsolete(last_span, ObsoleteSyntax::OwnedSelf)
}
SelfStatic
}
token::BinOp(token::Star) => {
// Possibly "*self" or "*mut self" -- not supported. Try to avoid
// emitting cryptic "unexpected token" errors.
@ -4533,15 +4464,6 @@ impl<'a> Parser<'a> {
} else {
SelfValue(self_ident)
}
} else if self.token.is_mutability() &&
self.look_ahead(1, |t| *t == token::Tilde) &&
self.look_ahead(2, |t| t.is_keyword(keywords::Self)) {
mutbl_self = self.parse_mutability();
self.bump();
drop(self.expect_self_ident());
let last_span = self.last_span;
self.obsolete(last_span, ObsoleteSyntax::OwnedSelf);
SelfStatic
} else {
SelfStatic
}
@ -5422,13 +5344,7 @@ impl<'a> Parser<'a> {
let (maybe_path, ident) = match self.token {
token::Ident(..) => {
let the_ident = self.parse_ident();
let path = if self.token == token::Eq {
self.bump();
let path = self.parse_str();
let span = self.span;
self.obsolete(span, ObsoleteSyntax::ExternCrateRenaming);
Some(path)
} else if self.eat_keyword(keywords::As) {
let path = if self.eat_keyword(keywords::As) {
// skip the ident if there is one
if self.token.is_ident() { self.bump(); }
@ -5698,17 +5614,7 @@ impl<'a> Parser<'a> {
}
// either a view item or an item:
if self.eat_keyword(keywords::Extern) {
let next_is_mod = self.eat_keyword(keywords::Mod);
if next_is_mod || self.eat_keyword(keywords::Crate) {
if next_is_mod {
let last_span = self.last_span;
self.span_err(mk_sp(lo, last_span.hi),
&format!("`extern mod` is obsolete, use \
`extern crate` instead \
to refer to external \
crates.")[])
}
if self.eat_keyword(keywords::Crate) {
return self.parse_item_extern_crate(lo, visibility, attrs);
}
@ -6075,35 +5981,7 @@ impl<'a> Parser<'a> {
let first_ident = self.parse_ident();
let mut path = vec!(first_ident);
match self.token {
token::Eq => {
// x = foo::bar
self.bump();
let path_lo = self.span.lo;
path = vec!(self.parse_ident());
while self.check(&token::ModSep) {
self.bump();
let id = self.parse_ident();
path.push(id);
}
let span = mk_sp(path_lo, self.span.hi);
self.obsolete(span, ObsoleteSyntax::ImportRenaming);
let path = ast::Path {
span: span,
global: false,
segments: path.into_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
parameters: ast::PathParameters::none(),
}
}).collect()
};
return P(spanned(lo, self.span.hi,
ViewPathSimple(first_ident, path,
ast::DUMMY_NODE_ID)));
}
token::ModSep => {
if let token::ModSep = self.token {
// foo::bar or foo::{a,b,c} or foo::*
while self.check(&token::ModSep) {
self.bump();
@ -6156,8 +6034,6 @@ impl<'a> Parser<'a> {
_ => break
}
}
}
_ => ()
}
let mut rename_to = path[path.len() - 1u];
let path = ast::Path {

View File

@ -59,10 +59,6 @@
//! line (which it can't) and so naturally place the content on its own line to
//! avoid combining it with other lines and making matters even worse.
pub use self::PrintStackBreak::*;
pub use self::Breaks::*;
pub use self::Token::*;
use std::io;
use std::string;
use std::iter::repeat;
@ -87,7 +83,7 @@ pub struct BeginToken {
#[derive(Clone)]
pub enum Token {
String(string::String, int),
String(String, int),
Break(BreakToken),
Begin(BeginToken),
End,
@ -96,12 +92,15 @@ pub enum Token {
impl Token {
pub fn is_eof(&self) -> bool {
match *self { Eof => true, _ => false }
match *self {
Token::Eof => true,
_ => false,
}
}
pub fn is_hardbreak_tok(&self) -> bool {
match *self {
Break(BreakToken {
Token::Break(BreakToken {
offset: 0,
blank_space: bs
}) if bs == SIZE_INFINITY =>
@ -112,22 +111,22 @@ impl Token {
}
}
pub fn tok_str(t: Token) -> string::String {
match t {
String(s, len) => return format!("STR({},{})", s, len),
Break(_) => return "BREAK".to_string(),
Begin(_) => return "BEGIN".to_string(),
End => return "END".to_string(),
Eof => return "EOF".to_string()
pub fn tok_str(token: &Token) -> String {
match *token {
Token::String(ref s, len) => format!("STR({},{})", s, len),
Token::Break(_) => "BREAK".to_string(),
Token::Begin(_) => "BEGIN".to_string(),
Token::End => "END".to_string(),
Token::Eof => "EOF".to_string()
}
}
pub fn buf_str(toks: Vec<Token>,
szs: Vec<int>,
pub fn buf_str(toks: &[Token],
szs: &[int],
left: uint,
right: uint,
lim: uint)
-> string::String {
-> String {
let n = toks.len();
assert_eq!(n, szs.len());
let mut i = left;
@ -140,7 +139,7 @@ pub fn buf_str(toks: Vec<Token>,
}
s.push_str(&format!("{}={}",
szs[i],
tok_str(toks[i].clone()))[]);
tok_str(&toks[i]))[]);
i += 1u;
i %= n;
}
@ -167,7 +166,7 @@ pub fn mk_printer(out: Box<io::Writer+'static>, linewidth: uint) -> Printer {
// fall behind.
let n: uint = 3 * linewidth;
debug!("mk_printer {}", linewidth);
let token: Vec<Token> = repeat(Eof).take(n).collect();
let token: Vec<Token> = repeat(Token::Eof).take(n).collect();
let size: Vec<int> = repeat(0i).take(n).collect();
let scan_stack: Vec<uint> = repeat(0u).take(n).collect();
Printer {
@ -312,20 +311,18 @@ impl Printer {
pub fn replace_last_token(&mut self, t: Token) {
self.token[self.right] = t;
}
pub fn pretty_print(&mut self, t: Token) -> io::IoResult<()> {
pub fn pretty_print(&mut self, token: Token) -> io::IoResult<()> {
debug!("pp ~[{},{}]", self.left, self.right);
match t {
Eof => {
match token {
Token::Eof => {
if !self.scan_stack_empty {
self.check_stack(0);
let left = self.token[self.left].clone();
let left_size = self.size[self.left];
try!(self.advance_left(left, left_size));
try!(self.advance_left());
}
self.indent(0);
Ok(())
}
Begin(b) => {
Token::Begin(b) => {
if self.scan_stack_empty {
self.left_total = 1;
self.right_total = 1;
@ -334,27 +331,27 @@ impl Printer {
} else { self.advance_right(); }
debug!("pp Begin({})/buffer ~[{},{}]",
b.offset, self.left, self.right);
self.token[self.right] = t;
self.token[self.right] = token;
self.size[self.right] = -self.right_total;
let right = self.right;
self.scan_push(right);
Ok(())
}
End => {
Token::End => {
if self.scan_stack_empty {
debug!("pp End/print ~[{},{}]", self.left, self.right);
self.print(t, 0)
self.print(token, 0)
} else {
debug!("pp End/buffer ~[{},{}]", self.left, self.right);
self.advance_right();
self.token[self.right] = t;
self.token[self.right] = token;
self.size[self.right] = -1;
let right = self.right;
self.scan_push(right);
Ok(())
}
}
Break(b) => {
Token::Break(b) => {
if self.scan_stack_empty {
self.left_total = 1;
self.right_total = 1;
@ -366,21 +363,21 @@ impl Printer {
self.check_stack(0);
let right = self.right;
self.scan_push(right);
self.token[self.right] = t;
self.token[self.right] = token;
self.size[self.right] = -self.right_total;
self.right_total += b.blank_space;
Ok(())
}
String(ref s, len) => {
Token::String(s, len) => {
if self.scan_stack_empty {
debug!("pp String('{}')/print ~[{},{}]",
*s, self.left, self.right);
self.print(t.clone(), len)
s, self.left, self.right);
self.print(Token::String(s, len), len)
} else {
debug!("pp String('{}')/buffer ~[{},{}]",
*s, self.left, self.right);
s, self.left, self.right);
self.advance_right();
self.token[self.right] = t.clone();
self.token[self.right] = Token::String(s, len);
self.size[self.right] = len;
self.right_total += len;
self.check_stream()
@ -401,9 +398,7 @@ impl Printer {
self.size[scanned] = SIZE_INFINITY;
}
}
let left = self.token[self.left].clone();
let left_size = self.size[self.left];
try!(self.advance_left(left, left_size));
try!(self.advance_left());
if self.left != self.right {
try!(self.check_stream());
}
@ -450,42 +445,52 @@ impl Printer {
self.right %= self.buf_len;
assert!((self.right != self.left));
}
pub fn advance_left(&mut self, x: Token, l: int) -> io::IoResult<()> {
pub fn advance_left(&mut self) -> io::IoResult<()> {
debug!("advance_left ~[{},{}], sizeof({})={}", self.left, self.right,
self.left, l);
if l >= 0 {
let ret = self.print(x.clone(), l);
match x {
Break(b) => self.left_total += b.blank_space,
String(_, len) => {
assert_eq!(len, l); self.left_total += len;
}
_ => ()
self.left, self.size[self.left]);
let mut left_size = self.size[self.left];
while left_size >= 0 {
let left = self.token[self.left].clone();
let len = match left {
Token::Break(b) => b.blank_space,
Token::String(_, len) => {
assert_eq!(len, left_size);
len
}
_ => 0
};
try!(self.print(left, left_size));
self.left_total += len;
if self.left == self.right {
break;
}
if self.left != self.right {
self.left += 1u;
self.left %= self.buf_len;
let left = self.token[self.left].clone();
let left_size = self.size[self.left];
try!(self.advance_left(left, left_size));
}
ret
} else {
Ok(())
self.left += 1u;
self.left %= self.buf_len;
left_size = self.size[self.left];
}
Ok(())
}
pub fn check_stack(&mut self, k: int) {
if !self.scan_stack_empty {
let x = self.scan_top();
match self.token[x] {
Begin(_) => {
Token::Begin(_) => {
if k > 0 {
let popped = self.scan_pop();
self.size[popped] = self.size[x] + self.right_total;
self.check_stack(k - 1);
}
}
End => {
Token::End => {
// paper says + not =, but that makes no sense.
let popped = self.scan_pop();
self.size[popped] = 1;
@ -520,7 +525,7 @@ impl Printer {
} else {
PrintStackElem {
offset: 0,
pbreak: Broken(Inconsistent)
pbreak: PrintStackBreak::Broken(Breaks::Inconsistent)
}
}
}
@ -531,56 +536,56 @@ impl Printer {
}
write!(self.out, "{}", s)
}
pub fn print(&mut self, x: Token, l: int) -> io::IoResult<()> {
debug!("print {} {} (remaining line space={})", tok_str(x.clone()), l,
pub fn print(&mut self, token: Token, l: int) -> io::IoResult<()> {
debug!("print {} {} (remaining line space={})", tok_str(&token), l,
self.space);
debug!("{}", buf_str(self.token.clone(),
self.size.clone(),
debug!("{}", buf_str(&self.token[],
&self.size[],
self.left,
self.right,
6));
match x {
Begin(b) => {
match token {
Token::Begin(b) => {
if l > self.space {
let col = self.margin - self.space + b.offset;
debug!("print Begin -> push broken block at col {}", col);
self.print_stack.push(PrintStackElem {
offset: col,
pbreak: Broken(b.breaks)
pbreak: PrintStackBreak::Broken(b.breaks)
});
} else {
debug!("print Begin -> push fitting block");
self.print_stack.push(PrintStackElem {
offset: 0,
pbreak: Fits
pbreak: PrintStackBreak::Fits
});
}
Ok(())
}
End => {
Token::End => {
debug!("print End -> pop End");
let print_stack = &mut self.print_stack;
assert!((print_stack.len() != 0u));
print_stack.pop().unwrap();
Ok(())
}
Break(b) => {
Token::Break(b) => {
let top = self.get_top();
match top.pbreak {
Fits => {
PrintStackBreak::Fits => {
debug!("print Break({}) in fitting block", b.blank_space);
self.space -= b.blank_space;
self.indent(b.blank_space);
Ok(())
}
Broken(Consistent) => {
PrintStackBreak::Broken(Breaks::Consistent) => {
debug!("print Break({}+{}) in consistent block",
top.offset, b.offset);
let ret = self.print_newline(top.offset + b.offset);
self.space = self.margin - (top.offset + b.offset);
ret
}
Broken(Inconsistent) => {
PrintStackBreak::Broken(Breaks::Inconsistent) => {
if l > self.space {
debug!("print Break({}+{}) w/ newline in inconsistent",
top.offset, b.offset);
@ -597,14 +602,14 @@ impl Printer {
}
}
}
String(s, len) => {
Token::String(s, len) => {
debug!("print String({})", s);
assert_eq!(l, len);
// assert!(l <= space);
self.space -= len;
self.print_str(&s[])
}
Eof => {
Token::Eof => {
// Eof should never get here.
panic!();
}
@ -616,41 +621,45 @@ impl Printer {
//
// "raw box"
pub fn rbox(p: &mut Printer, indent: uint, b: Breaks) -> io::IoResult<()> {
p.pretty_print(Begin(BeginToken {
p.pretty_print(Token::Begin(BeginToken {
offset: indent as int,
breaks: b
}))
}
pub fn ibox(p: &mut Printer, indent: uint) -> io::IoResult<()> {
rbox(p, indent, Inconsistent)
rbox(p, indent, Breaks::Inconsistent)
}
pub fn cbox(p: &mut Printer, indent: uint) -> io::IoResult<()> {
rbox(p, indent, Consistent)
rbox(p, indent, Breaks::Consistent)
}
pub fn break_offset(p: &mut Printer, n: uint, off: int) -> io::IoResult<()> {
p.pretty_print(Break(BreakToken {
p.pretty_print(Token::Break(BreakToken {
offset: off,
blank_space: n as int
}))
}
pub fn end(p: &mut Printer) -> io::IoResult<()> { p.pretty_print(End) }
pub fn end(p: &mut Printer) -> io::IoResult<()> {
p.pretty_print(Token::End)
}
pub fn eof(p: &mut Printer) -> io::IoResult<()> { p.pretty_print(Eof) }
pub fn eof(p: &mut Printer) -> io::IoResult<()> {
p.pretty_print(Token::Eof)
}
pub fn word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
p.pretty_print(String(/* bad */ wrd.to_string(), wrd.len() as int))
p.pretty_print(Token::String(/* bad */ wrd.to_string(), wrd.len() as int))
}
pub fn huge_word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
p.pretty_print(String(/* bad */ wrd.to_string(), SIZE_INFINITY))
p.pretty_print(Token::String(/* bad */ wrd.to_string(), SIZE_INFINITY))
}
pub fn zero_word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
p.pretty_print(String(/* bad */ wrd.to_string(), 0))
p.pretty_print(Token::String(/* bad */ wrd.to_string(), 0))
}
pub fn spaces(p: &mut Printer, n: uint) -> io::IoResult<()> {
@ -670,7 +679,9 @@ pub fn hardbreak(p: &mut Printer) -> io::IoResult<()> {
}
pub fn hardbreak_tok_offset(off: int) -> Token {
Break(BreakToken {offset: off, blank_space: SIZE_INFINITY})
Token::Break(BreakToken {offset: off, blank_space: SIZE_INFINITY})
}
pub fn hardbreak_tok() -> Token { return hardbreak_tok_offset(0); }
pub fn hardbreak_tok() -> Token {
hardbreak_tok_offset(0)
}

View File

@ -25,7 +25,8 @@ use parse::token::{self, BinOpToken, Token};
use parse::lexer::comments;
use parse;
use print::pp::{self, break_offset, word, space, zerobreak, hardbreak};
use print::pp::{Breaks, Consistent, Inconsistent, eof};
use print::pp::{Breaks, eof};
use print::pp::Breaks::{Consistent, Inconsistent};
use ptr::P;
use std::{ascii, mem};
@ -459,7 +460,7 @@ fn needs_parentheses(expr: &ast::Expr) -> bool {
impl<'a> State<'a> {
pub fn ibox(&mut self, u: uint) -> IoResult<()> {
self.boxes.push(pp::Inconsistent);
self.boxes.push(pp::Breaks::Inconsistent);
pp::ibox(&mut self.s, u)
}
@ -469,7 +470,7 @@ impl<'a> State<'a> {
}
pub fn cbox(&mut self, u: uint) -> IoResult<()> {
self.boxes.push(pp::Consistent);
self.boxes.push(pp::Breaks::Consistent);
pp::cbox(&mut self.s, u)
}
@ -531,11 +532,17 @@ impl<'a> State<'a> {
}
pub fn is_begin(&mut self) -> bool {
match self.s.last_token() { pp::Begin(_) => true, _ => false }
match self.s.last_token() {
pp::Token::Begin(_) => true,
_ => false,
}
}
pub fn is_end(&mut self) -> bool {
match self.s.last_token() { pp::End => true, _ => false }
match self.s.last_token() {
pp::Token::End => true,
_ => false,
}
}
// is this the beginning of a line?
@ -545,7 +552,7 @@ impl<'a> State<'a> {
pub fn in_cbox(&self) -> bool {
match self.boxes.last() {
Some(&last_box) => last_box == pp::Consistent,
Some(&last_box) => last_box == pp::Breaks::Consistent,
None => false
}
}
@ -1497,108 +1504,168 @@ impl<'a> State<'a> {
Ok(())
}
fn print_expr_box(&mut self,
place: &Option<P<ast::Expr>>,
expr: &ast::Expr) -> IoResult<()> {
try!(word(&mut self.s, "box"));
try!(word(&mut self.s, "("));
try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
try!(self.word_space(")"));
self.print_expr(expr)
}
fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) -> IoResult<()> {
try!(self.ibox(indent_unit));
try!(word(&mut self.s, "["));
try!(self.commasep_exprs(Inconsistent, &exprs[]));
try!(word(&mut self.s, "]"));
self.end()
}
fn print_expr_repeat(&mut self,
element: &ast::Expr,
count: &ast::Expr) -> IoResult<()> {
try!(self.ibox(indent_unit));
try!(word(&mut self.s, "["));
try!(self.print_expr(element));
try!(self.word_space(";"));
try!(self.print_expr(count));
try!(word(&mut self.s, "]"));
self.end()
}
fn print_expr_struct(&mut self,
path: &ast::Path,
fields: &[ast::Field],
wth: &Option<P<ast::Expr>>) -> IoResult<()> {
try!(self.print_path(path, true));
if !(fields.is_empty() && wth.is_none()) {
try!(word(&mut self.s, "{"));
try!(self.commasep_cmnt(
Consistent,
&fields[],
|s, field| {
try!(s.ibox(indent_unit));
try!(s.print_ident(field.ident.node));
try!(s.word_space(":"));
try!(s.print_expr(&*field.expr));
s.end()
},
|f| f.span));
match *wth {
Some(ref expr) => {
try!(self.ibox(indent_unit));
if !fields.is_empty() {
try!(word(&mut self.s, ","));
try!(space(&mut self.s));
}
try!(word(&mut self.s, ".."));
try!(self.print_expr(&**expr));
try!(self.end());
}
_ => try!(word(&mut self.s, ",")),
}
try!(word(&mut self.s, "}"));
}
Ok(())
}
fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) -> IoResult<()> {
try!(self.popen());
try!(self.commasep_exprs(Inconsistent, &exprs[]));
if exprs.len() == 1 {
try!(word(&mut self.s, ","));
}
self.pclose()
}
fn print_expr_call(&mut self,
func: &ast::Expr,
args: &[P<ast::Expr>]) -> IoResult<()> {
try!(self.print_expr_maybe_paren(func));
self.print_call_post(args)
}
fn print_expr_method_call(&mut self,
ident: ast::SpannedIdent,
tys: &[P<ast::Ty>],
args: &[P<ast::Expr>]) -> IoResult<()> {
let base_args = args.slice_from(1);
try!(self.print_expr(&*args[0]));
try!(word(&mut self.s, "."));
try!(self.print_ident(ident.node));
if tys.len() > 0u {
try!(word(&mut self.s, "::<"));
try!(self.commasep(Inconsistent, tys,
|s, ty| s.print_type(&**ty)));
try!(word(&mut self.s, ">"));
}
self.print_call_post(base_args)
}
fn print_expr_binary(&mut self,
op: ast::BinOp,
lhs: &ast::Expr,
rhs: &ast::Expr) -> IoResult<()> {
try!(self.print_expr(lhs));
try!(space(&mut self.s));
try!(self.word_space(ast_util::binop_to_string(op)));
self.print_expr(rhs)
}
fn print_expr_unary(&mut self,
op: ast::UnOp,
expr: &ast::Expr) -> IoResult<()> {
try!(word(&mut self.s, ast_util::unop_to_string(op)));
self.print_expr_maybe_paren(expr)
}
fn print_expr_addr_of(&mut self,
mutability: ast::Mutability,
expr: &ast::Expr) -> IoResult<()> {
try!(word(&mut self.s, "&"));
try!(self.print_mutability(mutability));
self.print_expr_maybe_paren(expr)
}
pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
try!(self.maybe_print_comment(expr.span.lo));
try!(self.ibox(indent_unit));
try!(self.ann.pre(self, NodeExpr(expr)));
match expr.node {
ast::ExprBox(ref p, ref e) => {
try!(word(&mut self.s, "box"));
try!(word(&mut self.s, "("));
try!(p.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
try!(self.word_space(")"));
try!(self.print_expr(&**e));
ast::ExprBox(ref place, ref expr) => {
try!(self.print_expr_box(place, &**expr));
}
ast::ExprVec(ref exprs) => {
try!(self.ibox(indent_unit));
try!(word(&mut self.s, "["));
try!(self.commasep_exprs(Inconsistent, &exprs[]));
try!(word(&mut self.s, "]"));
try!(self.end());
try!(self.print_expr_vec(&exprs[]));
}
ast::ExprRepeat(ref element, ref count) => {
try!(self.ibox(indent_unit));
try!(word(&mut self.s, "["));
try!(self.print_expr(&**element));
try!(self.word_space(";"));
try!(self.print_expr(&**count));
try!(word(&mut self.s, "]"));
try!(self.end());
try!(self.print_expr_repeat(&**element, &**count));
}
ast::ExprStruct(ref path, ref fields, ref wth) => {
try!(self.print_path(path, true));
if !(fields.is_empty() && wth.is_none()) {
try!(word(&mut self.s, "{"));
try!(self.commasep_cmnt(
Consistent,
&fields[],
|s, field| {
try!(s.ibox(indent_unit));
try!(s.print_ident(field.ident.node));
try!(s.word_space(":"));
try!(s.print_expr(&*field.expr));
s.end()
},
|f| f.span));
match *wth {
Some(ref expr) => {
try!(self.ibox(indent_unit));
if !fields.is_empty() {
try!(word(&mut self.s, ","));
try!(space(&mut self.s));
}
try!(word(&mut self.s, ".."));
try!(self.print_expr(&**expr));
try!(self.end());
}
_ => try!(word(&mut self.s, ",")),
}
try!(word(&mut self.s, "}"));
}
try!(self.print_expr_struct(path, &fields[], wth));
}
ast::ExprTup(ref exprs) => {
try!(self.popen());
try!(self.commasep_exprs(Inconsistent, &exprs[]));
if exprs.len() == 1 {
try!(word(&mut self.s, ","));
}
try!(self.pclose());
try!(self.print_expr_tup(&exprs[]));
}
ast::ExprCall(ref func, ref args) => {
try!(self.print_expr_maybe_paren(&**func));
try!(self.print_call_post(&args[]));
try!(self.print_expr_call(&**func, &args[]));
}
ast::ExprMethodCall(ident, ref tys, ref args) => {
let base_args = args.slice_from(1);
try!(self.print_expr(&*args[0]));
try!(word(&mut self.s, "."));
try!(self.print_ident(ident.node));
if tys.len() > 0u {
try!(word(&mut self.s, "::<"));
try!(self.commasep(Inconsistent, &tys[],
|s, ty| s.print_type(&**ty)));
try!(word(&mut self.s, ">"));
}
try!(self.print_call_post(base_args));
try!(self.print_expr_method_call(ident, &tys[], &args[]));
}
ast::ExprBinary(op, ref lhs, ref rhs) => {
try!(self.print_expr(&**lhs));
try!(space(&mut self.s));
try!(self.word_space(ast_util::binop_to_string(op)));
try!(self.print_expr(&**rhs));
try!(self.print_expr_binary(op, &**lhs, &**rhs));
}
ast::ExprUnary(op, ref expr) => {
try!(word(&mut self.s, ast_util::unop_to_string(op)));
try!(self.print_expr_maybe_paren(&**expr));
try!(self.print_expr_unary(op, &**expr));
}
ast::ExprAddrOf(m, ref expr) => {
try!(word(&mut self.s, "&"));
try!(self.print_mutability(m));
try!(self.print_expr_maybe_paren(&**expr));
try!(self.print_expr_addr_of(m, &**expr));
}
ast::ExprLit(ref lit) => {
try!(self.print_literal(&**lit));
}
ast::ExprLit(ref lit) => try!(self.print_literal(&**lit)),
ast::ExprCast(ref expr, ref ty) => {
try!(self.print_expr(&**expr));
try!(space(&mut self.s));
@ -2891,7 +2958,7 @@ impl<'a> State<'a> {
comments::BlankLine => {
// We need to do at least one, possibly two hardbreaks.
let is_semi = match self.s.last_token() {
pp::String(s, _) => ";" == s,
pp::Token::String(s, _) => ";" == s,
_ => false
};
if is_semi || self.is_begin() || self.is_end() {

View File

@ -211,6 +211,8 @@ pub struct TestDesc {
pub should_fail: ShouldFail,
}
unsafe impl Send for TestDesc {}
#[derive(Show)]
pub struct TestDescAndFn {
pub desc: TestDesc,
@ -525,6 +527,8 @@ pub enum TestResult {
TrBench(BenchSamples),
}
unsafe impl Send for TestResult {}
enum OutputLocation<T> {
Pretty(Box<term::Terminal<term::WriterWrapper> + Send>),
Raw(T),
@ -978,7 +982,6 @@ enum TestEvent {
pub type MonitorMsg = (TestDesc, TestResult, Vec<u8> );
unsafe impl Send for MonitorMsg {}
fn run_tests<F>(opts: &TestOpts,
tests: Vec<TestDescAndFn> ,
@ -1332,10 +1335,11 @@ impl MetricMap {
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
pub fn black_box<T>(dummy: T) {
pub fn black_box<T>(dummy: T) -> T {
// we need to "use" the argument in some way LLVM can't
// introspect.
unsafe {asm!("" : : "r"(&dummy))}
dummy
}

View File

@ -20,6 +20,7 @@ use error::{Error, CliResult, CommandResult};
use book;
use book::{Book, BookItem};
use css;
use javascript;
use regex::Regex;
@ -63,7 +64,7 @@ fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()>
Ok(())
}
try!(writeln!(out, "<div id='toc'>"));
try!(writeln!(out, "<div id='toc' class='mobile-hidden'>"));
try!(writeln!(out, "<ul class='chapter'>"));
try!(walk_items(&book.chapters[], "", path_to_root, out));
try!(writeln!(out, "</ul>"));
@ -102,6 +103,14 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
let prelude = tmp.path().join("prelude.html");
{
let mut toc = BufferedWriter::new(try!(File::create(&prelude)));
try!(writeln!(&mut toc, r#"<div id="nav">
<button id="toggle-nav">
<span class="sr-only">Toggle navigation</span>
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</button>
</div>"#));
let _ = write_toc(book, &item.path_to_root, &mut toc);
try!(writeln!(&mut toc, "<div id='page-wrapper'>"));
try!(writeln!(&mut toc, "<div id='page'>"));
@ -111,6 +120,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
let postlude = tmp.path().join("postlude.html");
{
let mut toc = BufferedWriter::new(try!(File::create(&postlude)));
try!(toc.write_str(javascript::JAVASCRIPT));
try!(writeln!(&mut toc, "</div></div>"));
}

View File

@ -45,7 +45,7 @@ body {
#page {
margin-left: auto;
margin-right:auto;
width: 750px;
max-width: 750px;
}
.chapter {
@ -69,4 +69,58 @@ body {
.chapter li a {
color: #000000;
}
@media only screen and (max-width: 1060px) {
#toc {
width: 100%;
margin-right: 0;
top: 40px;
}
#page-wrapper {
top: 40px;
left: 15px;
padding-right: 15px;
}
.mobile-hidden {
display: none;
}
}
#toggle-nav {
height: 20px;
width: 30px;
padding: 3px 3px 0 3px;
}
#toggle-nav {
margin-top: 5px;
width: 30px;
height: 30px;
background-color: #FFF;
border: 1px solid #666;
border-radius: 3px 3px 3px 3px;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
.bar {
display: block;
background-color: #000;
border-radius: 2px;
width: 100%;
height: 2px;
margin: 2px 0 3px;
padding: 0;
}
"#;

View File

@ -0,0 +1,43 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// The rust-book JavaScript in string form.
pub static JAVASCRIPT: &'static str = r#"
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
document.getElementById("toggle-nav").onclick = toggleNav;
function toggleNav() {
var toc = document.getElementById("toc");
var pagewrapper = document.getElementById("page-wrapper");
toggleClass(toc, "mobile-hidden");
toggleClass(pagewrapper, "mobile-hidden");
};
function toggleClass(el, className) {
// from http://youmightnotneedjquery.com/
if (el.classList) {
el.classList.toggle(className);
} else {
var classes = el.className.split(' ');
var existingIndex = classes.indexOf(className);
if (existingIndex >= 0) {
classes.splice(existingIndex, 1);
} else {
classes.push(className);
}
el.className = classes.join(' ');
}
}
});
</script>
"#;

View File

@ -39,6 +39,7 @@ mod serve;
mod test;
mod css;
mod javascript;
#[cfg(not(test))] // thanks #12327
fn main() {

View File

@ -0,0 +1,37 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::marker::Send;
enum TestE {
A
}
struct MyType;
unsafe impl Send for TestE {}
unsafe impl Send for MyType {}
unsafe impl Send for (MyType, MyType) {}
//~^ ERROR builtin traits can only be implemented on structs or enums
unsafe impl Send for &'static MyType {}
//~^ ERROR builtin traits can only be implemented on structs or enums
unsafe impl Send for [MyType] {}
//~^ ERROR builtin traits can only be implemented on structs or enums
unsafe impl Send for &'static [MyType] {}
//~^ ERROR builtin traits can only be implemented on structs or enums
fn is_send<T: Send>() {}
fn main() {
is_send::<(MyType, TestE)>();
}

View File

@ -0,0 +1,49 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Regression test for #20831: debruijn index account was thrown off
// by the (anonymous) lifetime in `<Self as Publisher>::Output`
// below. Note that changing to a named lifetime made the problem go
// away.
use std::ops::{Shl, Shr};
use std::cell::RefCell;
pub trait Subscriber {
type Input;
}
pub trait Publisher<'a> {
type Output;
fn subscribe(&mut self, Box<Subscriber<Input=Self::Output> + 'a>);
}
pub trait Processor<'a> : Subscriber + Publisher<'a> { }
impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { }
struct MyStruct<'a> {
sub: Box<Subscriber<Input=u64> + 'a>
}
impl<'a> Publisher<'a> for MyStruct<'a> {
type Output = u64;
fn subscribe(&mut self, t : Box<Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
// Not obvious, but there is an implicit lifetime here -------^
//~^^ ERROR cannot infer
//
// The fact that `Publisher` is using an implicit lifetime is
// what was causing the debruijn accounting to be off, so
// leave it that way!
self.sub = t;
}
}
fn main() {}

View File

@ -7,16 +7,10 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(asm)]
fn main() {
let x = [1is, 2, 3];
match x {
[a, b, ..c] => { //~ ERROR obsolete syntax
assert_eq!(a, 1);
assert_eq!(b, 2);
let expected: &[_] = &[3];
assert_eq!(c, expected);
}
}
let a;
asm!("nop" "nop"); //~ ERROR malformed inline assembly
asm!("nop" "nop" : "=r"(a)); //~ ERROR malformed inline assembly
}

View File

@ -1,4 +1,4 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -8,8 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn main() {
struct S(isize);
let s = S(0);
let x = *s; //~ ERROR single-field tuple-structs can no longer be dereferenced
struct Bar;
impl Bar {
fn hash<T>(&self, _: T) {}
}
#[derive(Hash)]
struct Foo(Bar);
//~^ error: the trait `core::hash::Hash<__S>` is not implemented for the type `Bar`
fn main() {}

View File

@ -1,21 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that ~ pointers give an obsolescence message.
fn foo(x: ~isize) {} //~ ERROR obsolete syntax: `~` notation for owned pointers
fn bar(x: ~str) {} //~ ERROR obsolete syntax: `~` notation for owned pointers
fn baz(x: ~[isize]) {} //~ ERROR obsolete syntax: `~[T]` is no longer a type
fn main() {
let x = ~4is; //~ ERROR obsolete syntax: `~` notation for owned pointer allocation
let y = ~"hello"; //~ ERROR obsolete syntax: `~` notation for owned pointer allocation
let z = ~[1is, 2, 3]; //~ ERROR obsolete syntax: `~[T]` is no longer a type
}

View File

@ -48,7 +48,11 @@ fn zzz() {()}
fn some_function(a: int, b: int) {
let some_variable = Struct { a: 11, b: 22 };
let some_other_variable = 23i;
zzz(); // #break
for x in range(0, 1) {
zzz(); // #break
}
}
fn some_other_function(a: int, b: int) -> bool { true }

View File

@ -28,7 +28,7 @@ $(TMPDIR)/%.pp: %.rs
$(TMPDIR)/%.dot: %.rs
$(eval $(call FIND_LAST_BLOCK,$<))
$(RUSTC_LIB) -Z unstable-options --xpretty flowgraph=$(LASTBLOCKNUM_$<) $< -o $@.tmp
$(RUSTC_LIB) -Z unstable-options --xpretty flowgraph,unlabelled=$(LASTBLOCKNUM_$<) $< -o $@.tmp
cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \
-e 's@\[label=""\]@@' \
-e 's@digraph [a-zA-Z0-9_]* @digraph block @' \

View File

@ -34,7 +34,7 @@ digraph block {
N11 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N6[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2is { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1is; if x == 2is { break ; \"unreachable\"; } }"];
N14 -> N6;
N15 -> N16;
N16 -> N17;
N17 -> N18;

View File

@ -61,7 +61,7 @@ digraph block {
N12 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1is { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1is { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l }\l y -= 4is;\l x -= 5is;\l}\l"];
N15 -> N9;
N16 -> N17;
N17 -> N18;
N18 -> N19;
@ -73,7 +73,7 @@ digraph block {
N23 -> N24;
N24 -> N25;
N25 -> N26;
N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2is { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2is { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l}\l"];
N26 -> N11;
N27 -> N28;
N28 -> N29;
N29 -> N30;

View File

@ -64,7 +64,7 @@ digraph block {
N12 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1is { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1is { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l }\l y -= 1is;\l x -= 1is;\l}\l"];
N15 -> N8;
N16 -> N17;
N17 -> N18;
N18 -> N19;
@ -76,7 +76,7 @@ digraph block {
N23 -> N24;
N24 -> N25;
N25 -> N26;
N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1is { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1is { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l}\l"];
N26 -> N11;
N27 -> N28;
N28 -> N29;
N29 -> N30;

Some files were not shown because too many files have changed in this diff Show More