# Compiler Test Documentation
-In the Rust project, we use a special set of comands embedded in
+In the Rust project, we use a special set of commands embedded in
comments to test the Rust compiler. There are two groups of commands:
1. Header commands
## Why aren't modules type-parametric?
-We want to maintain the option to parametrize at runtime. We may eventually change this limitation, but initially this is how type parameters were implemented.
+We want to maintain the option to parameterize at runtime. We may eventually change this limitation, but initially this is how type parameters were implemented.
## Why aren't values type-parametric? Why only items?
* zero-extend if the source is unsigned
* sign-extend if the source is signed
* casting from a float to an integer will round the float towards zero
- * **[NOTE: currently this will cause Undefined Behaviour if the rounded
+ * **[NOTE: currently this will cause Undefined Behavior if the rounded
value cannot be represented by the target integer type][float-int]**.
This includes Inf and NaN. This is a bug and will be fixed.
* casting from an integer to float will produce the floating point
* casting from an f32 to an f64 is perfect and lossless
* casting from an f64 to an f32 will produce the closest possible value
(rounding strategy unspecified)
- * **[NOTE: currently this will cause Undefined Behaviour if the value
+ * **[NOTE: currently this will cause Undefined Behavior if the value
is finite but larger or smaller than the largest or smallest finite
value representable by f32][float-float]**. This is a bug and will
be fixed.
when we talked about `'a: 'b`, it was ok for `'a` to live *exactly* as long as
`'b`. At first glance, this seems to be a meaningless distinction. Nothing ever
gets dropped at the same time as another, right? This is why we used the
-following desugarring of `let` statements:
+following desugaring of `let` statements:
```rust,ignore
let x;
There are two major DSTs exposed by the language: trait objects, and slices.
A trait object represents some type that implements the traits it specifies.
-The exact original type is *erased* in favour of runtime reflection
+The exact original type is *erased* in favor of runtime reflection
with a vtable containing all the information necessary to use the type.
This is the information that completes a trait object: a pointer to its vtable.
the ability to be confident that certain situations are statically impossible.
One final subtle detail about empty types is that raw pointers to them are
-actually valid to construct, but dereferencing them is Undefined Behaviour
+actually valid to construct, but dereferencing them is Undefined Behavior
because that doesn't actually make sense. That is, you could model C's `void *`
type with `*const Void`, but this doesn't necessarily gain anything over using
e.g. `*const ()`, which *is* safe to randomly dereference.
println!("{}", vec[0]);
```
-This is pretty clearly Not Good. Unfortunately, we're kind've stuck between a
+This is pretty clearly Not Good. Unfortunately, we're kind of stuck between a
rock and a hard place: maintaining consistent state at every step has an
enormous cost (and would negate any benefits of the API). Failing to maintain
consistent state gives us Undefined Behavior in safe code (making the API
```
Dang. Here the destructor running was pretty fundamental to the API, and it had
-to be scrapped in favour of a completely different design.
+to be scrapped in favor of a completely different design.
Safe Rust is the *true* Rust programming language. If all you do is write Safe
Rust, you will never have to worry about type-safety or memory-safety. You will
-never endure a null or dangling pointer, or any of that Undefined Behaviour
+never endure a null or dangling pointer, or any of that Undefined Behavior
nonsense.
*That's totally awesome.*
* Mutate statics
That's it. The reason these operations are relegated to Unsafe is that misusing
-any of these things will cause the ever dreaded Undefined Behaviour. Invoking
-Undefined Behaviour gives the compiler full rights to do arbitrarily bad things
-to your program. You definitely *should not* invoke Undefined Behaviour.
+any of these things will cause the ever dreaded Undefined Behavior. Invoking
+Undefined Behavior gives the compiler full rights to do arbitrarily bad things
+to your program. You definitely *should not* invoke Undefined Behavior.
-Unlike C, Undefined Behaviour is pretty limited in scope in Rust. All the core
+Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core
language cares about is preventing the following things:
* Dereferencing null or dangling pointers
* Unwinding into another language
* Causing a [data race][race]
-That's it. That's all the causes of Undefined Behaviour baked into Rust. Of
+That's it. That's all the causes of Undefined Behavior baked into Rust. Of
course, unsafe functions and traits are free to declare arbitrary other
-constraints that a program must maintain to avoid Undefined Behaviour. However,
+constraints that a program must maintain to avoid Undefined Behavior. However,
generally violations of these constraints will just transitively lead to one of
the above problems. Some additional constraints may also derive from compiler
intrinsics that make special assumptions about how code can be optimized.
* one of them is a write
* one of them is unsynchronized
-A data race has Undefined Behaviour, and is therefore impossible to perform
+A data race has Undefined Behavior, and is therefore impossible to perform
in Safe Rust. Data races are *mostly* prevented through rust's ownership system:
it's impossible to alias a mutable reference, so it's impossible to perform a
data race. Interior mutability makes this more complicated, which is largely why
// bounds checked, and there's no chance of the value getting changed
// in the middle. However our program may panic if the thread we spawned
// managed to increment before this ran. A race condition because correct
-// program execution (panicing is rarely correct) depends on order of
+// program execution (panicking is rarely correct) depends on order of
// thread execution.
println!("{}", data[idx.load(Ordering::SeqCst)]);
```
* `slice::get_unchecked` will perform unchecked indexing, allowing memory
safety to be freely violated.
-* `ptr::offset` is an intrinsic that invokes Undefined Behaviour if it is
+* `ptr::offset` is an intrinsic that invokes Undefined Behavior if it is
not "in bounds" as defined by LLVM.
* `mem::transmute` reinterprets some value as having the given type,
bypassing type safety in arbitrary ways. (see [conversions] for details)
The need for unsafe traits boils down to the fundamental property of safe code:
**No matter how completely awful Safe code is, it can't cause Undefined
-Behaviour.**
+Behavior.**
-This means that Unsafe Rust, **the royal vanguard of Undefined Behaviour**, has to be
+This means that Unsafe Rust, **the royal vanguard of Undefined Behavior**, has to be
*super paranoid* about generic safe code. To be clear, Unsafe Rust is totally free to trust
specific safe code. Anything else would degenerate into infinite spirals of
paranoid despair. In particular it's generally regarded as ok to trust the standard library
implemented. Since they're *marker traits* (they have no associated items like
methods), correctly implemented simply means that they have the intrinsic
properties an implementor should have. Incorrectly implementing Send or Sync can
-cause Undefined Behaviour.
+cause Undefined Behavior.
Send and Sync are also automatically derived traits. This means that, unlike
every other trait, if a type is composed entirely of Send or Sync types, then it
`mem::transmute<T, U>` takes a value of type `T` and reinterprets it to have
type `U`. The only restriction is that the `T` and `U` are verified to have the
-same size. The ways to cause Undefined Behaviour with this are mind boggling.
+same size. The ways to cause Undefined Behavior with this are mind boggling.
* First and foremost, creating an instance of *any* type with an invalid state
is going to cause arbitrary chaos that can't really be predicted.
`mem::transmute_copy<T, U>` somehow manages to be *even more* wildly unsafe than
this. It copies `size_of<U>` bytes out of an `&T` and interprets them as a `U`.
The size check that `mem::transmute` has is gone (as it may be valid to copy
-out a prefix), though it is Undefined Behaviour for `U` to be larger than `T`.
+out a prefix), though it is Undefined Behavior for `U` to be larger than `T`.
Also of course you can get most of the functionality of these functions using
pointer casts.
Unsafe code can often end up producing references or lifetimes out of thin air.
Such lifetimes come into the world as *unbounded*. The most common source of this
-is derefencing a raw pointer, which produces a reference with an unbounded lifetime.
+is dereferencing a raw pointer, which produces a reference with an unbounded lifetime.
Such a lifetime becomes as big as context demands. This is in fact more powerful
than simply becoming `'static`, because for instance `&'static &'a T`
will fail to typecheck, but the unbound lifetime will perfectly mold into
lifetime can be regarded as `'static`.
Almost no reference is `'static`, so this is probably wrong. `transmute` and
-`transmute_copy` are the two other primary offenders. One should endeavour to
+`transmute_copy` are the two other primary offenders. One should endeavor to
bound an unbounded lifetime as quick as possible, especially across function
boundaries.
(this is equivalent to memcpy -- note that the argument order is reversed!)
It should go without saying that these functions, if misused, will cause serious
-havoc or just straight up Undefined Behaviour. The only things that these
+havoc or just straight up Undefined Behavior. The only things that these
functions *themselves* require is that the locations you want to read and write
are allocated. However the ways writing arbitrary bits to arbitrary
locations of memory can break things are basically uncountable!
*uninitialized*. In this state the value of the memory is an indeterminate pile
of bits that may or may not even reflect a valid state for the type that is
supposed to inhabit that location of memory. Attempting to interpret this memory
-as a value of *any* type will cause Undefined Behaviour. Do Not Do This.
+as a value of *any* type will cause Undefined Behavior. Do Not Do This.
Rust provides mechanisms to work with uninitialized memory in checked (safe) and
-unchecked (unsafe) ways.
\ No newline at end of file
+unchecked (unsafe) ways.
Rust's unwinding strategy is not specified to be fundamentally compatible
with any other language's unwinding. As such, unwinding into Rust from another
-language, or unwinding into another language from Rust is Undefined Behaviour.
+language, or unwinding into another language from Rust is Undefined Behavior.
You must *absolutely* catch any panics at the FFI boundary! What you do at that
point is up to you, but *something* must be done. If you fail to do this,
at best, your application will crash and burn. At worst, your application *won't*
If you don't care about the null-pointer optimization, then you can use the
stable code. However we will be designing the rest of the code around enabling
the optimization. In particular, `Unique::new` is unsafe to call, because
-putting `null` inside of it is Undefined Behaviour. Our stable Unique doesn't
+putting `null` inside of it is Undefined Behavior. Our stable Unique doesn't
need `new` to be unsafe because it doesn't make any interesting guarantees about
its contents.
initialized, Rust won't just let us dereference the location of memory to move
the value out, because that would leave the memory uninitialized! For this we
need `ptr::read`, which just copies out the bits from the target address and
-intrprets it as a value of type T. This will leave the memory at this address
+interprets it as a value of type T. This will leave the memory at this address
logically uninitialized, even though there is in fact a perfectly good instance
of T there.
% Handling Zero-Sized Types
-It's time. We're going to fight the spectre that is zero-sized types. Safe Rust
+It's time. We're going to fight the specter that is zero-sized types. Safe Rust
*never* needs to care about this, but Vec is very intensive on raw pointers and
raw allocations, which are exactly the two things that care about
zero-sized types. We need to be careful of two things:
### Symbols
Symbols are a general class of printable [tokens](#tokens) that play structural
-roles in a variety of grammar productions. They are cataloged here for
-completeness as the set of remaining miscellaneous printable tokens that do not
+roles in a variety of grammar productions. They are a
+set of remaining miscellaneous printable tokens that do not
otherwise appear as [unary operators](#unary-operator-expressions), [binary
operators](#binary-operator-expressions), or [keywords][keywords].
+They are catalogued in [the Symbols section][symbols] of the Grammar document.
+
+[symbols]: grammar.html#symbols
## Paths
### Structs
-A _structure_ is a nominal [structure type](#structure-types) defined with the
+A _struct_ is a nominal [struct type](#struct-types) defined with the
keyword `struct`.
An example of a `struct` item and its use:
let px: i32 = p.x;
```
-A _tuple structure_ is a nominal [tuple type](#tuple-types), also defined with
+A _tuple struct_ is a nominal [tuple type](#tuple-types), also defined with
the keyword `struct`. For example:
```
let px: i32 = match p { Point(x, _) => x };
```
-A _unit-like struct_ is a structure without any fields, defined by leaving off
-the list of fields entirely. Such a structure implicitly defines a constant of
+A _unit-like struct_ is a struct without any fields, defined by leaving off
+the list of fields entirely. Such a struct implicitly defines a constant of
its type with the same name. For example:
```
let c = [Cookie, Cookie {}, Cookie, Cookie {}];
```
-The precise memory layout of a structure is not specified. One can specify a
+The precise memory layout of a struct is not specified. One can specify a
particular layout using the [`repr` attribute](#ffi-attributes).
### Enumerations
trait Shape { fn area(&self) -> f64; }
trait Circle : Shape { fn radius(&self) -> f64; }
-# impl Shape for Foo {
-# fn area(&self) -> f64 {
-# 0.0
-# }
-# }
+impl Shape for Foo {
+ fn area(&self) -> f64 {
+ 0.0
+ }
+}
impl Circle for Foo {
fn radius(&self) -> f64 {
println!("calling area: {}", self.area());
terms of encapsulation).
* - `default_type_parameter_fallback` - Allows type parameter defaults to
influence type inference.
-* - `braced_empty_structs` - Allows use of empty structs with braces.
+* - `braced_empty_structs` - Allows use of empty structs and enum variants with braces.
If a feature is promoted to a language feature, then all existing programs will
start to receive compilation warnings about `#![feature]` directives which enabled
An _item declaration statement_ has a syntactic form identical to an
[item](#items) declaration within a module. Declaring an item — a
-function, enumeration, structure, type, static, trait, implementation or module
+function, enumeration, struct, type, static, trait, implementation or module
— locally within a statement block is simply a way of restricting its
scope to a narrow region containing all of its uses; it is otherwise identical
in meaning to declaring the item outside the statement block.
(0); // zero in parentheses
```
-### Structure expressions
+### Struct expressions
-There are several forms of structure expressions. A _structure expression_
-consists of the [path](#paths) of a [structure item](#structs), followed by
+There are several forms of struct expressions. A _struct expression_
+consists of the [path](#paths) of a [struct item](#structs), followed by
a brace-enclosed list of one or more comma-separated name-value pairs,
-providing the field values of a new instance of the structure. A field name
+providing the field values of a new instance of the struct. A field name
can be any identifier, and is separated from its value expression by a colon.
-The location denoted by a structure field is mutable if and only if the
-enclosing structure is mutable.
+The location denoted by a struct field is mutable if and only if the
+enclosing struct is mutable.
-A _tuple structure expression_ consists of the [path](#paths) of a [structure
+A _tuple struct expression_ consists of the [path](#paths) of a [struct
item](#structs), followed by a parenthesized list of one or more
-comma-separated expressions (in other words, the path of a structure item
-followed by a tuple expression). The structure item must be a tuple structure
+comma-separated expressions (in other words, the path of a struct item
+followed by a tuple expression). The struct item must be a tuple struct
item.
-A _unit-like structure expression_ consists only of the [path](#paths) of a
-[structure item](#structs).
+A _unit-like struct expression_ consists only of the [path](#paths) of a
+[struct item](#structs).
-The following are examples of structure expressions:
+The following are examples of struct expressions:
```
# struct Point { x: f64, y: f64 }
some_fn::<Cookie>(Cookie);
```
-A structure expression forms a new value of the named structure type. Note
-that for a given *unit-like* structure type, this will always be the same
+A struct expression forms a new value of the named struct type. Note
+that for a given *unit-like* struct type, this will always be the same
value.
-A structure expression can terminate with the syntax `..` followed by an
+A struct expression can terminate with the syntax `..` followed by an
expression to denote a functional update. The expression following `..` (the
-base) must have the same structure type as the new structure type being formed.
-The entire expression denotes the result of constructing a new structure (with
+base) must have the same struct type as the new struct type being formed.
+The entire expression denotes the result of constructing a new struct (with
the same type as the base expression) with the given values for the fields that
were explicitly specified and the values in the base expression for all other
fields.
A _field expression_ consists of an expression followed by a single dot and an
identifier, when not immediately followed by a parenthesized expression-list
(the latter is a [method call expression](#method-call-expressions)). A field
-expression denotes a field of a [structure](#structure-types).
+expression denotes a field of a [struct](#struct-types).
```{.ignore .field}
mystruct.myfield;
All in-bounds elements of arrays and slices are always initialized, and access
to an array or slice is always bounds-checked.
-### Structure types
+### Struct types
A `struct` *type* is a heterogeneous product of other types, called the
*fields* of the type.[^structtype]
[^structtype]: `struct` types are analogous to `struct` types in C,
the *record* types of the ML family,
- or the *structure* types of the Lisp family.
+ or the *struct* types of the Lisp family.
New instances of a `struct` can be constructed with a [struct
-expression](#structure-expressions).
+expression](#struct-expressions).
The memory layout of a `struct` is undefined by default to allow for compiler
optimizations like field reordering, but it can be fixed with the
The fields of a `struct` may be qualified by [visibility
modifiers](#visibility-and-privacy), to allow access to data in a
-structure outside a module.
+struct outside a module.
-A _tuple struct_ type is just like a structure type, except that the fields are
+A _tuple struct_ type is just like a struct type, except that the fields are
anonymous.
-A _unit-like struct_ type is like a structure type, except that it has no
-fields. The one value constructed by the associated [structure
-expression](#structure-expressions) is the only value that inhabits such a
+A _unit-like struct_ type is like a struct type, except that it has no
+fields. The one value constructed by the associated [struct
+expression](#struct-expressions) is the only value that inhabits such a
type.
### Enumerated types
### Recursive types
Nominal types — [enumerations](#enumerated-types) and
-[structs](#structure-types) — may be recursive. That is, each `enum`
+[structs](#struct-types) — may be recursive. That is, each `enum`
constructor or `struct` field may refer, directly or indirectly, to the
enclosing `enum` or `struct` type itself. Such recursion has restrictions:
Each sub-expression is a coercion site to the respective type, e.g. the
zeroth sub-expression is a coercion site to type `U_0`.
-* Parenthesised sub-expressions (`(e)`): if the expression has type `U`, then
+* Parenthesized sub-expressions (`(e)`): if the expression has type `U`, then
the sub-expression is a coercion site to `U`.
* Blocks: if a block has type `U`, then the last expression in the block (if
* SML, OCaml: algebraic data types, pattern matching, type inference,
semicolon statement separation
-* C++: references, RAII, smart pointers, move semantics, monomorphisation,
+* C++: references, RAII, smart pointers, move semantics, monomorphization,
memory model
* ML Kit, Cyclone: region based memory management
* Haskell (GHC): typeclasses, type families
* [Testing](testing/README.md)
* [Unit testing](testing/unit.md)
* [FFI, platform-specific code](platform.md)
-* [APIs for a changing Rust](changing/README.md)
- * [Pre-1.0 changes](changing/pre-1-0.md)
- * [Post-1.0 changes](changing/post-1-0.md)
- * [Timing unclear](changing/unclear.md)
+++ /dev/null
-% API design for a changing Rust
-
-A number of planned Rust features will drastically affect the API design
-story. This section collects some of the biggest features with concrete examples
-of how the API will change.
+++ /dev/null
-% Post-1.0 changes
-
-### Higher-kinded types
-
-* A trait encompassing both `Iterable<T>` for some fixed `T` and
- `FromIterator<U>` for _all_ `U` (where HKT comes in). The train
- could provide e.g. a default `map` method producing the same kind of
- the container, but with a new type parameter.
-
-* **Monadic-generic programming**? Can we add this without deprecating
- huge swaths of the API (including `Option::map`, `option::collect`,
- `result::collect`, `try!` etc.
+++ /dev/null
-% Pre-1.0 changes
-
-### `std` facade
-
-We should revisit some APIs in `libstd` now that the facade effort is complete.
-
-For example, the treatment of environment variables in the new
-`Command` API is waiting on access to hashtables before being
-approved.
-
-### Trait reform
-
-Potential for standard conversion traits (`to`, `into`, `as`).
-
-Probably many other opportunities here.
-
-### Unboxed closures
+++ /dev/null
-% Changes with unclear timing
-
-### Associated items
-
-* Many traits that currently take type parameters should instead use associated
- types; this will _drastically_ simplify signatures in some cases.
-
-* Associated constants would be useful in a few places, e.g. traits for
- numerics, traits for paths.
-
-### Anonymous, unboxed return types (aka `impl Trait` types)
-
-* See https://github.com/rust-lang/rfcs/pull/105
-
-* Could affect API design in several places, e.g. the `Iterator` trait.
-
-### Default type parameters
-
-We are already using this in a few places (e.g. `HashMap`), but it's
-feature-gated.
-
-### Compile-time function evaluation (CTFE)
-
-https://github.com/mozilla/rust/issues/11621
-
-### Improved constant folding
-
-https://github.com/rust-lang/rust/issues/7834
Avoid using `#[path="..."]` directives; make the file system and
module hierarchy match, instead.
-### Use the module hirearchy to organize APIs into coherent sections. [FIXME]
+### Use the module hierarchy to organize APIs into coherent sections. [FIXME]
> **[FIXME]** Flesh this out with examples; explain what a "coherent
> section" is with examples.
>
-> The module hirearchy defines both the public and internal API of your module.
+> The module hierarchy defines both the public and internal API of your module.
> Breaking related functionality into submodules makes it understandable to both
> users and contributors to the module.
```
While it is possible to define all of `io` within a single directory,
-mirroring the module hirearchy in the directory structure makes
+mirroring the module hierarchy in the directory structure makes
submodules of `io::net` easier to find.
### Consider top-level definitions or reexports. [FIXME: needs RFC]
[`TcpStream`](https://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
is defined in `io/net/tcp.rs` and reexported in the `io` module.
-### Use internal module hirearchies for organization. [FIXME: needs RFC]
+### Use internal module hierarchies for organization. [FIXME: needs RFC]
> **[FIXME]**
> - Referencing internal modules from the standard library is subject to
> becoming outdated.
-Internal module hirearchies (i.e., private submodules) may be used to
+Internal module hierarchies (i.e., private submodules) may be used to
hide implementation details that are not part of the module's API.
For example, in [`std::io`](https://doc.rust-lang.org/std/io/), `mod mem`
> **[FIXME]** We probably want to discourage this, at least when used in a way
> that is publicly exposed.
-Traits that provide default implmentations for function can provide code reuse
+Traits that provide default implementations for function can provide code reuse
across types. For example, a `print` method can be defined across multiple
types as follows:
down the channel and to the other thread. Therefore, we'd ensure that `Send` was
implemented for that type.
-In the opposite way, if we were wrapping a library with FFI that isn't
+In the opposite way, if we were wrapping a library with [FFI][ffi] that isn't
threadsafe, we wouldn't want to implement `Send`, and so the compiler will help
us enforce that it can't leave the current thread.
+[ffi]: ffi.html
+
### `Sync`
The second of these traits is called [`Sync`](../std/marker/trait.Sync.html).
> dining room, furnished with a circular table, surrounded by five chairs, each
> labelled by the name of the philosopher who was to sit in it. They sat
> anticlockwise around the table. To the left of each philosopher there was
-> laid a golden fork, and in the centre stood a large bowl of spaghetti, which
+> laid a golden fork, and in the center stood a large bowl of spaghetti, which
> was constantly replenished. A philosopher was expected to spend most of
> their time thinking; but when they felt hungry, they went to the dining
> room, sat down in their own chair, picked up their own fork on their left,
In this piece of code, we take `file` (which has the type
`Option<String>`), and convert it to a type that `search` can use, in
-this case, `&Option<AsRef<Path>>`. Do do this, we take a reference of
+this case, `&Option<AsRef<Path>>`. To do this, we take a reference of
file, and map `Path::new` onto it. In this case, `as_ref()` converts
the `Option<String>` into an `Option<&str>`, and from there, we can
execute `Path::new` to the content of the optional, and return the
the value to the identifiers in the pattern, then evaluates the expression. If
the pattern doesn’t match, nothing happens.
-If you’d rather to do something else when the pattern does not match, you can
+If you want to do something else when the pattern does not match, you can
use `else`:
```rust
loop {
match option {
Some(x) => println!("{}", x),
- _ => break,
+ None => break,
}
}
```
outside of the scope of this guide, Rust provides a number of useful iterators
to accomplish various tasks. But first, a few notes about limitations of ranges.
-Ranges are very primitive, and we often can use better alternatives. Consider
+Ranges are very primitive, and we often can use better alternatives. Consider the
following Rust anti-pattern: using ranges to emulate a C-style `for` loop. Let’s
suppose you needed to iterate over the contents of a vector. You may be tempted
to write this:
talk about what you do want instead.
There are three broad classes of things that are relevant here: iterators,
-*iterator adapters*, and *consumers*. Here's some definitions:
+*iterator adaptors*, and *consumers*. Here's some definitions:
* *iterators* give you a sequence of values.
-* *iterator adapters* operate on an iterator, producing a new iterator with a
+* *iterator adaptors* operate on an iterator, producing a new iterator with a
different output sequence.
* *consumers* operate on an iterator, producing some final set of values.
These two basic iterators should serve you well. There are some more
advanced iterators, including ones that are infinite.
-That's enough about iterators. Iterator adapters are the last concept
+That's enough about iterators. Iterator adaptors are the last concept
we need to talk about with regards to iterators. Let's get to it!
-## Iterator adapters
+## Iterator adaptors
-*Iterator adapters* take an iterator and modify it somehow, producing
+*Iterator adaptors* take an iterator and modify it somehow, producing
a new iterator. The simplest one is called `map`:
```rust,ignore
If you are trying to execute a closure on an iterator for its side effects,
just use `for` instead.
-There are tons of interesting iterator adapters. `take(n)` will return an
+There are tons of interesting iterator adaptors. `take(n)` will return an
iterator over the next `n` elements of the original iterator. Let's try it out
with an infinite iterator:
This will give you a vector containing `6`, `12`, `18`, `24`, and `30`.
-This is just a small taste of what iterators, iterator adapters, and consumers
+This is just a small taste of what iterators, iterator adaptors, and consumers
can help you with. There are a number of really useful iterators, and you can
write your own as well. Iterators provide a safe, efficient way to manipulate
all kinds of lists. They're a little unusual at first, but if you play with
% Lifetimes
-This guide is one of three presenting Rust’s ownership system. This is one of
+This guide is three of three presenting Rust’s ownership system. This is one of
Rust’s most unique and compelling features, with which Rust developers should
become quite acquainted. Ownership is how Rust achieves its largest goal,
memory safety. There are a few distinct concepts, each with its own chapter:
["Lifetime Elision"][lifetime-elision] below) them in common cases.
Before we get to that, though, let’s break the explicit example down:
-[lifetime-elision]: #user-content-lifetime-elision
+[lifetime-elision]: #lifetime-elision
```rust,ignore
fn bar<'a>(...)
% References and Borrowing
-This guide is one of three presenting Rust’s ownership system. This is one of
+This guide is two of three presenting Rust’s ownership system. This is one of
Rust’s most unique and compelling features, with which Rust developers should
become quite acquainted. Ownership is how Rust achieves its largest goal,
memory safety. There are a few distinct concepts, each with its own
let handles: Vec<_> = (0..10).map(|_| {
thread::spawn(|| {
let mut x = 0;
- for _ in (0..5_000_000) {
+ for _ in 0..5_000_000 {
x += 1
}
x
* `pub`: denotes public visibility in `struct` fields, `impl` blocks, and modules. See [Crates and Modules (Exporting a Public Interface)].
* `ref`: by-reference binding. See [Patterns (`ref` and `ref mut`)].
* `return`: return from function. See [Functions (Early Returns)].
-* `Self`: implementer type alias. See [Traits].
+* `Self`: implementor type alias. See [Traits].
* `self`: method subject. See [Method Syntax (Method Calls)].
* `static`: global variable. See [`const` and `static` (`static`)].
* `struct`: structure definition. See [Structs].
* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`).
* `/=` (`var /= expr`): arithmetic division & assignment.
* `:` (`pat: type`, `ident: type`): constraints. See [Variable Bindings], [Functions], [Structs], [Traits].
-* `:` (`ident: expr`): struct field initialiser. See [Structs].
+* `:` (`ident: expr`): struct field initializer. See [Structs].
* `:` (`'a: loop {…}`): loop label. See [Loops (Loops Labels)].
* `;`: statement and item terminator.
* `;` (`[…; len]`): part of fixed-size array syntax. See [Primitive Types (Arrays)].
<!-- Various things involving parens and tuples -->
* `()`: empty tuple (*a.k.a.* unit), both literal and type.
-* `(expr)`: parenthesised expression.
+* `(expr)`: parenthesized expression.
* `(expr,)`: single-element tuple expression. See [Primitive Types (Tuples)].
* `(type,)`: single-element tuple type. See [Primitive Types (Tuples)].
* `(expr, …)`: tuple expression. See [Primitive Types (Tuples)].
* `(type, …)`: tuple type. See [Primitive Types (Tuples)].
-* `expr(expr, …)`: function call expression. Also used to initialise tuple `struct`s and tuple `enum` variants. See [Functions].
+* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants. See [Functions].
* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation. See [Macros].
* `expr.0`, `expr.1`, …: tuple indexing. See [Primitive Types (Tuple Indexing)].
```
`assert!` is a macro provided by Rust which takes one argument: if the argument
-is `true`, nothing happens. If the argument is false, it `panic!`s. Let's run
+is `true`, nothing happens. If the argument is `false`, it `panic!`s. Let's run
our tests again:
```bash
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```
-The `--ignored` argument is an argument to the test binary, and not to cargo,
+The `--ignored` argument is an argument to the test binary, and not to Cargo,
which is why the command is `cargo test -- --ignored`.
# The `tests` module
The current convention is to use the `tests` module to hold your "unit-style"
tests. Anything that just tests one small bit of functionality makes sense to
go here. But what about "integration-style" tests instead? For that, we have
-the `tests` directory
+the `tests` directory.
# The `tests` directory
To learn more, run the command again with --verbose.
```
-Additionaly, variable bindings can be shadowed. This means that a later
+Additionally, variable bindings can be shadowed. This means that a later
variable binding with the same name as another binding, that's currently in
scope, will override the previous binding.
#[cfg(rustc)]
extern crate rustc_driver as this;
-fn main() { this::main() }
+fn main() {
+ this::main()
+}
let path = try!(entry).path();
let mut metadata_str = String::new();
- try!(
- File::open(&path).and_then(|mut f|
- f.read_to_string(&mut metadata_str))
- );
+ try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str)));
let some_errors: ErrorMetadataMap = try!(json::decode(&metadata_str));
// Enclose each error in a div so they can be shown/hidden en masse.
let desc_desc = match info.description {
Some(_) => "error-described",
- None => "error-undescribed"
+ None => "error-undescribed",
};
let use_desc = match info.use_site {
Some(_) => "error-used",
- None => "error-unused"
+ None => "error-unused",
};
try!(write!(&mut output_file, "<div class=\"{} {}\">", desc_desc, use_desc));
// Error title (with self-link).
try!(write!(&mut output_file,
- "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
- err_code
- ));
+ "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
+ err_code));
// Description rendered as markdown.
match info.description {
Some(ref desc) => try!(write!(&mut output_file, "{}", Markdown(desc))),
- None => try!(write!(&mut output_file, "<p>No description.</p>\n"))
+ None => try!(write!(&mut output_file, "<p>No description.</p>\n")),
}
try!(write!(&mut output_file, "</div>\n"));
///
/// # Examples
///
-/// In this example, a large vector of floats is shared between several threads.
+/// In this example, a large vector is shared between several threads.
/// With simple pipes, without `Arc`, a copy would have to be made for each
/// thread.
///
if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire);
- deallocate(ptr as *mut u8,
- size_of_val(&*ptr),
- align_of_val(&*ptr))
+ deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
}
}
}
// ref, which can only happen after the lock is released.
if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire);
- unsafe {
- deallocate(ptr as *mut u8,
- size_of_val(&*ptr),
- align_of_val(&*ptr))
- }
+ unsafe { deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) }
}
}
}
#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")]
impl<T: ?Sized> AsRef<T> for Arc<T> {
- fn as_ref(&self) -> &T { &**self }
+ fn as_ref(&self) -> &T {
+ &**self
+ }
}
p
};
- IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData }
+ IntermediateBox {
+ ptr: p,
+ size: size,
+ align: align,
+ marker: marker::PhantomData,
+ }
}
impl<T> BoxPlace<T> for IntermediateBox<T> {
#[stable(feature = "box_slice_clone", since = "1.3.0")]
impl<T: Clone> Clone for Box<[T]> {
fn clone(&self) -> Self {
- let mut new = BoxBuilder { data: RawVec::with_capacity(self.len()), len: 0 };
+ let mut new = BoxBuilder {
+ data: RawVec::with_capacity(self.len()),
+ len: 0,
+ };
let mut target = new.data.ptr();
#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")]
impl<T: ?Sized> AsRef<T> for Box<T> {
- fn as_ref(&self) -> &T { &**self }
+ fn as_ref(&self) -> &T {
+ &**self
+ }
}
#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")]
impl<T: ?Sized> AsMut<T> for Box<T> {
- fn as_mut(&mut self) -> &mut T { &mut **self }
+ fn as_mut(&mut self) -> &mut T {
+ &mut **self
+ }
}
};
// heap::EMPTY doubles as "unallocated" and "zero-sized allocation"
- RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap }
+ RawVec {
+ ptr: Unique::new(heap::EMPTY as *mut T),
+ cap: cap,
+ }
}
}
ptr
};
- RawVec { ptr: Unique::new(ptr as *mut _), cap: cap }
+ RawVec {
+ ptr: Unique::new(ptr as *mut _),
+ cap: cap,
+ }
}
}
/// Reconstitutes a RawVec from a pointer and capacity.
///
- /// # Undefined Behaviour
+ /// # Undefined Behavior
///
/// The ptr must be allocated, and with the given capacity. The
/// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems).
/// If the ptr and capacity come from a RawVec, then this is guaranteed.
pub unsafe fn from_raw_parts(ptr: *mut T, cap: usize) -> Self {
- RawVec { ptr: Unique::new(ptr), cap: cap }
+ RawVec {
+ ptr: Unique::new(ptr),
+ cap: cap,
+ }
}
/// Converts a `Box<[T]>` into a `RawVec<T>`.
///
/// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
/// the requested space. This is not really unsafe, but the unsafe
- /// code *you* write that relies on the behaviour of this function may break.
+ /// code *you* write that relies on the behavior of this function may break.
///
/// # Panics
///
/// Ensures that the buffer contains at least enough space to hold
/// `used_cap + needed_extra_cap` elements. If it doesn't already have
/// enough capacity, will reallocate enough space plus comfortable slack
- /// space to get amortized `O(1)` behaviour. Will limit this behaviour
+ /// space to get amortized `O(1)` behavior. Will limit this behavior
/// if it would needlessly cause itself to panic.
///
/// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
/// the requested space. This is not really unsafe, but the unsafe
- /// code *you* write that relies on the behaviour of this function may break.
+ /// code *you* write that relies on the behavior of this function may break.
///
/// This is ideal for implementing a bulk-push operation like `extend`.
///
}
// This check is my waterloo; it's the only thing Vec wouldn't have to do.
- assert!(self.cap >= amount,
- "Tried to shrink to a larger capacity");
+ assert!(self.cap >= amount, "Tried to shrink to a larger capacity");
if amount == 0 {
mem::replace(self, RawVec::new());
/// Converts the entire buffer into `Box<[T]>`.
///
- /// While it is not *strictly* Undefined Behaviour to call
+ /// While it is not *strictly* Undefined Behavior to call
/// this procedure while some of the RawVec is unintialized,
/// it cetainly makes it trivial to trigger it.
///
self.dec_weak();
if self.weak() == 0 {
- deallocate(ptr as *mut u8,
- size_of_val(&*ptr),
- align_of_val(&*ptr))
+ deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
}
}
}
// the weak count starts at 1, and will only go to zero if all
// the strong pointers have disappeared.
if self.weak() == 0 {
- deallocate(ptr as *mut u8,
- size_of_val(&*ptr),
- align_of_val(&*ptr))
+ deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
}
}
}
#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")]
impl<T: ?Sized> AsRef<T> for Rc<T> {
- fn as_ref(&self) -> &T { &**self }
+ fn as_ref(&self) -> &T {
+ &**self
+ }
}
extern {
fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
- fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
- flags: c_int) -> size_t;
+ fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
fn je_nallocx(size: size_t, flags: c_int) -> size_t;
}
const MIN_ALIGN: usize = 16;
// MALLOCX_ALIGN(a) macro
-fn mallocx_align(a: usize) -> c_int { a.trailing_zeros() as c_int }
+fn mallocx_align(a: usize) -> c_int {
+ a.trailing_zeros() as c_int
+}
fn align_to_flags(align: usize) -> c_int {
- if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
+ if align <= MIN_ALIGN {
+ 0
+ } else {
+ mallocx_align(align)
+ }
}
#[no_mangle]
-pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
+pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { je_mallocx(size as size_t, flags) as *mut u8 }
}
#[no_mangle]
-pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
- align: usize) -> *mut u8 {
+pub extern "C" fn __rust_reallocate(ptr: *mut u8,
+ _old_size: usize,
+ size: usize,
+ align: usize)
+ -> *mut u8 {
let flags = align_to_flags(align);
unsafe { je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle]
-pub extern fn __rust_reallocate_inplace(ptr: *mut u8, _old_size: usize,
- size: usize, align: usize) -> usize {
+pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
+ _old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize {
let flags = align_to_flags(align);
unsafe { je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}
#[no_mangle]
-pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
+pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
unsafe { je_sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}
#[no_mangle]
-pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
+pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { je_nallocx(size as size_t, flags) as usize }
}
const MIN_ALIGN: usize = 16;
#[no_mangle]
-pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
+pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
unsafe { imp::allocate(size, align) }
}
#[no_mangle]
-pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
+pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
unsafe { imp::deallocate(ptr, old_size, align) }
}
#[no_mangle]
-pub extern fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> *mut u8 {
+pub extern "C" fn __rust_reallocate(ptr: *mut u8,
+ old_size: usize,
+ size: usize,
+ align: usize)
+ -> *mut u8 {
unsafe { imp::reallocate(ptr, old_size, size, align) }
}
#[no_mangle]
-pub extern fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize,
- size: usize, align: usize) -> usize {
+pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
+ old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize {
unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
}
#[no_mangle]
-pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
+pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
imp::usable_size(size, align)
}
#[cfg(not(target_os = "android"))]
fn posix_memalign(memptr: *mut *mut libc::c_void,
align: libc::size_t,
- size: libc::size_t) -> libc::c_int;
+ size: libc::size_t)
+ -> libc::c_int;
}
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
#[cfg(not(target_os = "android"))]
unsafe fn more_aligned_malloc(size: usize, align: usize) -> *mut u8 {
let mut out = ptr::null_mut();
- let ret = posix_memalign(&mut out,
- align as libc::size_t,
- size as libc::size_t);
+ let ret = posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
if ret != 0 {
ptr::null_mut()
} else {
}
}
- pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> *mut u8 {
+ pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
} else {
}
}
- pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize,
- _align: usize) -> usize {
+ pub unsafe fn reallocate_inplace(_ptr: *mut u8,
+ old_size: usize,
+ _size: usize,
+ _align: usize)
+ -> usize {
old_size
}
extern "system" {
fn GetProcessHeap() -> HANDLE;
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
- fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID,
- dwBytes: SIZE_T) -> LPVOID;
+ fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
}
if align <= MIN_ALIGN {
HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
} else {
- let ptr = HeapAlloc(GetProcessHeap(), 0,
- (size + align) as SIZE_T) as *mut u8;
- if ptr.is_null() { return ptr }
+ let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
+ if ptr.is_null() {
+ return ptr
+ }
align_ptr(ptr, align)
}
}
- pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize,
- align: usize) -> *mut u8 {
+ pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
} else {
let header = get_header(ptr);
- let new = HeapReAlloc(GetProcessHeap(), 0, header.0 as LPVOID,
+ let new = HeapReAlloc(GetProcessHeap(),
+ 0,
+ header.0 as LPVOID,
(size + align) as SIZE_T) as *mut u8;
- if new.is_null() { return new }
+ if new.is_null() {
+ return new
+ }
align_ptr(new, align)
}
}
- pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> usize {
+ pub unsafe fn reallocate_inplace(ptr: *mut u8,
+ old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize {
if align <= MIN_ALIGN {
- let new = HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY,
- ptr as LPVOID, size as SIZE_T) as *mut u8;
- if new.is_null() { old_size } else { size }
+ let new = HeapReAlloc(GetProcessHeap(),
+ HEAP_REALLOC_IN_PLACE_ONLY,
+ ptr as LPVOID,
+ size as SIZE_T) as *mut u8;
+ if new.is_null() {
+ old_size
+ } else {
+ size
+ }
} else {
old_size
}
head: RefCell<Chunk>,
copy_head: RefCell<Chunk>,
chunks: RefCell<Vec<Chunk>>,
- _marker: marker::PhantomData<*mut &'longer_than_self()>,
+ _marker: marker::PhantomData<*mut &'longer_than_self ()>,
}
impl<'a> Arena<'a> {
struct TyDesc {
drop_glue: fn(*const i8),
size: usize,
- align: usize
+ align: usize,
}
trait AllTypes { fn dummy(&self) { } }
let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
self.chunks.borrow_mut().push(self.copy_head.borrow().clone());
- *self.copy_head.borrow_mut() =
- chunk((new_min_chunk_size + 1).next_power_of_two(), true);
+ *self.copy_head.borrow_mut() = chunk((new_min_chunk_size + 1).next_power_of_two(), true);
self.alloc_copy_inner(n_bytes, align)
}
let copy_head = self.copy_head.borrow();
copy_head.fill.set(end);
- unsafe {
- copy_head.as_ptr().offset(start as isize)
- }
+ unsafe { copy_head.as_ptr().offset(start as isize) }
}
#[inline]
fn alloc_copy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
unsafe {
- let ptr = self.alloc_copy_inner(mem::size_of::<T>(),
- mem::align_of::<T>());
+ let ptr = self.alloc_copy_inner(mem::size_of::<T>(), mem::align_of::<T>());
let ptr = ptr as *mut T;
ptr::write(&mut (*ptr), op());
&mut *ptr
}
// Functions for the non-POD part of the arena
- fn alloc_noncopy_grow(&self, n_bytes: usize,
- align: usize) -> (*const u8, *const u8) {
+ fn alloc_noncopy_grow(&self, n_bytes: usize, align: usize) -> (*const u8, *const u8) {
// Allocate a new chunk.
let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
self.chunks.borrow_mut().push(self.head.borrow().clone());
- *self.head.borrow_mut() =
- chunk((new_min_chunk_size + 1).next_power_of_two(), false);
+ *self.head.borrow_mut() = chunk((new_min_chunk_size + 1).next_power_of_two(), false);
self.alloc_noncopy_inner(n_bytes, align)
}
#[inline]
- fn alloc_noncopy_inner(&self, n_bytes: usize,
- align: usize) -> (*const u8, *const u8) {
+ fn alloc_noncopy_inner(&self, n_bytes: usize, align: usize) -> (*const u8, *const u8) {
// Be careful to not maintain any `head` borrows active, because
// `alloc_noncopy_grow` borrows it mutably.
let (start, end, tydesc_start, head_capacity) = {
unsafe {
let buf = head.as_ptr();
- (buf.offset(tydesc_start as isize), buf.offset(start as isize))
+ (buf.offset(tydesc_start as isize),
+ buf.offset(start as isize))
}
}
fn alloc_noncopy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
unsafe {
let tydesc = get_tydesc::<T>();
- let (ty_ptr, ptr) =
- self.alloc_noncopy_inner(mem::size_of::<T>(),
- mem::align_of::<T>());
+ let (ty_ptr, ptr) = self.alloc_noncopy_inner(mem::size_of::<T>(), mem::align_of::<T>());
let ty_ptr = ty_ptr as *mut usize;
let ptr = ptr as *mut T;
// Write in our tydesc along with a bit indicating that it
// has *not* been initialized yet.
*ty_ptr = bitpack_tydesc_ptr(tydesc, false);
// Actually initialize it
- ptr::write(&mut(*ptr), op());
+ ptr::write(&mut (*ptr), op());
// Now that we are done, update the tydesc to indicate that
// the object is there.
*ty_ptr = bitpack_tydesc_ptr(tydesc, true);
for i in 0..10 {
// Arena allocate something with drop glue to make sure it
// doesn't leak.
- arena.alloc(|| { Rc::new(i) });
+ arena.alloc(|| Rc::new(i));
// Allocate something with funny size and alignment, to keep
// things interesting.
- arena.alloc(|| { [0u8, 1, 2] });
+ arena.alloc(|| [0u8, 1, 2]);
}
// Now, panic while allocating
arena.alloc::<Rc<i32>, _>(|| {
impl<T> TypedArenaChunk<T> {
#[inline]
- unsafe fn new(next: *mut TypedArenaChunk<T>, capacity: usize)
- -> *mut TypedArenaChunk<T> {
+ unsafe fn new(next: *mut TypedArenaChunk<T>, capacity: usize) -> *mut TypedArenaChunk<T> {
let size = calculate_size::<T>(capacity);
- let chunk = allocate(size, mem::align_of::<TypedArenaChunk<T>>())
- as *mut TypedArenaChunk<T>;
- if chunk.is_null() { alloc::oom() }
+ let chunk =
+ allocate(size, mem::align_of::<TypedArenaChunk<T>>()) as *mut TypedArenaChunk<T>;
+ if chunk.is_null() {
+ alloc::oom()
+ }
(*chunk).next = next;
(*chunk).capacity = capacity;
chunk
let next = self.next;
let size = calculate_size::<T>(self.capacity);
let self_ptr: *mut TypedArenaChunk<T> = self;
- deallocate(self_ptr as *mut u8, size,
+ deallocate(self_ptr as *mut u8,
+ size,
mem::align_of::<TypedArenaChunk<T>>());
if !next.is_null() {
let capacity = (*next).capacity;
#[inline]
fn start(&self) -> *const u8 {
let this: *const TypedArenaChunk<T> = self;
- unsafe {
- round_up(this.offset(1) as usize, mem::align_of::<T>()) as *const u8
- }
+ unsafe { round_up(this.offset(1) as usize, mem::align_of::<T>()) as *const u8 }
}
// Returns a pointer to the end of the allocated space.
#[test]
fn test_arena_alloc_nested() {
- struct Inner { value: u8 }
- struct Outer<'a> { inner: &'a Inner }
- enum EI<'e> { I(Inner), O(Outer<'e>) }
+ struct Inner {
+ value: u8,
+ }
+ struct Outer<'a> {
+ inner: &'a Inner,
+ }
+ enum EI<'e> {
+ I(Inner),
+ O(Outer<'e>),
+ }
struct Wrap<'a>(TypedArena<EI<'a>>);
impl<'a> Wrap<'a> {
- fn alloc_inner<F:Fn() -> Inner>(&self, f: F) -> &Inner {
+ fn alloc_inner<F: Fn() -> Inner>(&self, f: F) -> &Inner {
let r: &EI = self.0.alloc(EI::I(f()));
if let &EI::I(ref i) = r {
i
panic!("mismatch");
}
}
- fn alloc_outer<F:Fn() -> Outer<'a>>(&self, f: F) -> &Outer {
+ fn alloc_outer<F: Fn() -> Outer<'a>>(&self, f: F) -> &Outer {
let r: &EI = self.0.alloc(EI::O(f()));
if let &EI::O(ref o) = r {
o
let arena = Wrap(TypedArena::new());
- let result = arena.alloc_outer(|| Outer {
- inner: arena.alloc_inner(|| Inner { value: 10 }) });
+ let result = arena.alloc_outer(|| {
+ Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }
+ });
assert_eq!(result.inner.value, 10);
}
pub fn test_copy() {
let arena = TypedArena::new();
for _ in 0..100000 {
- arena.alloc(Point {
- x: 1,
- y: 2,
- z: 3,
- });
+ arena.alloc(Point { x: 1, y: 2, z: 3 });
}
}
#[bench]
pub fn bench_copy(b: &mut Bencher) {
let arena = TypedArena::new();
- b.iter(|| {
- arena.alloc(Point {
- x: 1,
- y: 2,
- z: 3,
- })
- })
+ b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 }))
}
#[bench]
pub fn bench_copy_nonarena(b: &mut Bencher) {
b.iter(|| {
- let _: Box<_> = box Point {
- x: 1,
- y: 2,
- z: 3,
- };
+ let _: Box<_> = box Point { x: 1, y: 2, z: 3 };
})
}
#[bench]
pub fn bench_copy_old_arena(b: &mut Bencher) {
let arena = Arena::new();
- b.iter(|| {
- arena.alloc(|| {
- Point {
- x: 1,
- y: 2,
- z: 3,
- }
- })
- })
+ b.iter(|| arena.alloc(|| Point { x: 1, y: 2, z: 3 }))
}
#[allow(dead_code)]
for _ in 0..100000 {
arena.alloc(Noncopy {
string: "hello world".to_string(),
- array: vec!( 1, 2, 3, 4, 5 ),
+ array: vec!(1, 2, 3, 4, 5),
});
}
}
b.iter(|| {
arena.alloc(Noncopy {
string: "hello world".to_string(),
- array: vec!( 1, 2, 3, 4, 5 ),
+ array: vec!(1, 2, 3, 4, 5),
})
})
}
b.iter(|| {
let _: Box<_> = box Noncopy {
string: "hello world".to_string(),
- array: vec!( 1, 2, 3, 4, 5 ),
+ array: vec!(1, 2, 3, 4, 5),
};
})
}
pub fn bench_noncopy_old_arena(b: &mut Bencher) {
let arena = Arena::new();
b.iter(|| {
- arena.alloc(|| Noncopy {
- string: "hello world".to_string(),
- array: vec!( 1, 2, 3, 4, 5 ),
+ arena.alloc(|| {
+ Noncopy {
+ string: "hello world".to_string(),
+ array: vec!(1, 2, 3, 4, 5),
+ }
})
})
}
}
}
-/// Genericises over how to get the correct type of iterator from the correct type
+/// Genericizes over how to get the correct type of iterator from the correct type
/// of Node ownership.
trait Traverse<N> {
fn traverse(node: N) -> Self;
}
}
- /// Handle an underflow in this node's child. We favour handling "to the left" because we know
+ /// Handle an underflow in this node's child. We favor handling "to the left" because we know
/// we're empty, but our neighbour can be full. Handling to the left means when we choose to
/// steal, we pop off the end of our neighbour (always fast) and "unshift" ourselves
/// (always slow, but at least faster since we know we're half-empty).
/// Converts a vector of bytes to a `String` without checking that the
/// string contains valid UTF-8.
///
- /// See the safe version, [`from_utrf8()`][fromutf8], for more.
+ /// See the safe version, [`from_utf8()`][fromutf8], for more.
///
/// [fromutf8]: struct.String.html#method.from_utf8
///
self.write_str(unsafe { str::from_utf8_unchecked(&utf_8[..bytes_written]) })
}
- /// Glue for usage of the `write!` macro with implementers of this trait.
+ /// Glue for usage of the `write!` macro with implementors of this trait.
///
/// This method should generally not be invoked manually, but rather through
/// the `write!` macro itself.
/// Format trait for the `x` character.
///
-/// The `LowerHex` trait should format its output as a number in hexidecimal, with `a` through `f`
+/// The `LowerHex` trait should format its output as a number in hexadecimal, with `a` through `f`
/// in lower case.
///
/// The alternate flag, `#`, adds a `0x` in front of the output.
/// Format trait for the `X` character.
///
-/// The `UpperHex` trait should format its output as a number in hexidecimal, with `A` through `F`
+/// The `UpperHex` trait should format its output as a number in hexadecimal, with `A` through `F`
/// in upper case.
///
/// The alternate flag, `#`, adds a `0x` in front of the output.
/// Format trait for the `p` character.
///
/// The `Pointer` trait should format its output as a memory location. This is commonly presented
-/// as hexidecimal.
+/// as hexadecimal.
///
/// For more information on formatters, see [the module-level documentation][module].
///
/// # Safety
///
/// Beyond requiring that the program must be allowed to access both regions
- /// of memory, it is Undefined Behaviour for source and destination to
+ /// of memory, it is Undefined Behavior for source and destination to
/// overlap. Care must also be taken with the ownership of `src` and
/// `dst`. This method semantically moves the values of `src` into `dst`.
/// However it does not drop the contents of `dst`, or prevent the contents
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Composable external iterators
+//! Composable external iteration
//!
-//! # The `Iterator` trait
+//! If you've found yourself with a collection of some kind, and needed to
+//! perform an operation on the elements of said collection, you'll quickly run
+//! into 'iterators'. Iterators are heavily used in idiomatic Rust code, so
+//! it's worth becoming familiar with them.
//!
-//! This module defines Rust's core iteration trait. The `Iterator` trait has
-//! one unimplemented method, `next`. All other methods are derived through
-//! default methods to perform operations such as `zip`, `chain`, `enumerate`,
-//! and `fold`.
+//! Before explaining more, let's talk about how this module is structured:
//!
-//! The goal of this module is to unify iteration across all containers in Rust.
-//! An iterator can be considered as a state machine which is used to track
-//! which element will be yielded next.
+//! # Organization
//!
-//! There are various extensions also defined in this module to assist with
-//! various types of iteration, such as the `DoubleEndedIterator` for iterating
-//! in reverse, the `FromIterator` trait for creating a container from an
-//! iterator, and much more.
+//! This module is largely organized by type:
//!
-//! # Rust's `for` loop
+//! * [Traits] are the core portion: these traits define what kind of iterators
+//! exist and what you can do with them. The methods of these traits are worth
+//! putting some extra study time into.
+//! * [Functions] provide some helpful ways to create some basic iterators.
+//! * [Structs] are often the return types of the various methods on this
+//! module's traits. You'll usually want to look at the method that creates
+//! the `struct`, rather than the `struct` itself. For more detail about why,
+//! see '[Implementing Iterator](#implementing-iterator)'.
//!
-//! The special syntax used by rust's `for` loop is based around the
-//! `IntoIterator` trait defined in this module. `for` loops can be viewed as a
-//! syntactical expansion into a `loop`, for example, the `for` loop in this
-//! example is essentially translated to the `loop` below.
+//! [Traits]: #traits
+//! [Functions]: #functions
+//! [Structs]: #structs
//!
+//! That's it! Let's dig into iterators.
+//!
+//! # Iterator
+//!
+//! The heart and soul of this module is the [`Iterator`] trait. The core of
+//! [`Iterator`] looks like this:
+//!
+//! ```
+//! trait Iterator {
+//! type Item;
+//! fn next(&mut self) -> Option<Self::Item>;
+//! }
+//! ```
+//!
+//! An iterator has a method, [`next()`], which when called, returns an
+//! [`Option`]`<Item>`. [`next()`] will return `Some(Item)` as long as there
+//! are elements, and once they've all been exhausted, will return `None` to
+//! indicate that iteration is finished. Individual iterators may choose to
+//! resume iteration, and so calling [`next()`] again may or may not eventually
+//! start returning `Some(Item)` again at some point.
+//!
+//! [`Iterator`]'s full definition includes a number of other methods as well,
+//! but they are default methods, built on top of [`next()`], and so you get
+//! them for free.
+//!
+//! Iterators are also composable, and it's common to chain them together to do
+//! more complex forms of processing. See the [Adapters](#adapters) section
+//! below for more details.
+//!
+//! [`Iterator`]: trait.Iterator.html
+//! [`next()`]: trait.Iterator.html#tymethod.next
+//! [`Option`]: ../option/enum.Option.html
+//!
+//! # The three forms of iteration
+//!
+//! There are three common methods which can create iterators from a collection:
+//!
+//! * `iter()`, which iterates over `&T`.
+//! * `iter_mut()`, which iterates over `&mut T`.
+//! * `into_iter()`, which iterates over `T`.
+//!
+//! Various things in the standard library may implement one or more of the
+//! three, where appropriate.
+//!
+//! # Implementing Iterator
+//!
+//! Creating an iterator of your own involves two steps: creating a `struct` to
+//! hold the iterator's state, and then `impl`ementing [`Iterator`] for that
+//! `struct`. This is why there are so many `struct`s in this module: there is
+//! one for each iterator and iterator adapter.
+//!
+//! Let's make an iterator named `Counter` which counts from `1` to `5`:
+//!
+//! ```
+//! // First, the struct:
+//!
+//! /// An iterator which counts from one to five
+//! struct Counter {
+//! count: i32,
+//! }
+//!
+//! // we want our count to start at one, so let's add a new() method to help.
+//! // This isn't strictly necessary, but is convenient. Note that we start
+//! // `count` at zero, we'll see why in `next()`'s implementation below.
+//! impl Counter {
+//! fn new() -> Counter {
+//! Counter { count: 0 }
+//! }
+//! }
+//!
+//! // Then, we implement `Iterator` for our `Counter`:
+//!
+//! impl Iterator for Counter {
+//! // we will be counting with i32
+//! type Item = i32;
+//!
+//! // next() is the only required method
+//! fn next(&mut self) -> Option<i32> {
+//! // increment our count. This is why we started at zero.
+//! self.count += 1;
+//!
+//! // check to see if we've finished counting or not.
+//! if self.count < 6 {
+//! Some(self.count)
+//! } else {
+//! None
+//! }
+//! }
+//! }
+//!
+//! // And now we can use it!
+//!
+//! let mut counter = Counter::new();
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
//! ```
-//! let values = vec![1, 2, 3];
+//!
+//! This will print `1` through `5`, each on their own line.
+//!
+//! Calling `next()` this way gets repetitive. Rust has a construct which can
+//! call `next()` on your iterator, until it reaches `None`. Let's go over that
+//! next.
+//!
+//! # for Loops and IntoIterator
+//!
+//! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic
+//! example of `for`:
+//!
+//! ```
+//! let values = vec![1, 2, 3, 4, 5];
//!
//! for x in values {
//! println!("{}", x);
//! }
+//! ```
//!
-//! // Rough translation of the iteration without a `for` iterator.
-//! # let values = vec![1, 2, 3];
-//! let mut it = values.into_iter();
-//! loop {
-//! match it.next() {
-//! Some(x) => println!("{}", x),
-//! None => break,
-//! }
+//! This will print the numbers one through five, each on their own line. But
+//! you'll notice something here: we never called anything on our vector to
+//! produce an iterator. What gives?
+//!
+//! There's a trait in the standard library for converting something into an
+//! iterator: [`IntoIterator`]. This trait has one method, [`into_iter()`],
+//! which converts the thing implementing [`IntoIterator`] into an iterator.
+//! Let's take a look at that `for` loop again, and what the compiler converts
+//! it into:
+//!
+//! [`IntoIterator`]: trait.IntoIterator.html
+//! [`into_iter()`]: trait.IntoIterator.html#tymethod.into_iter
+//!
+//! ```
+//! let values = vec![1, 2, 3, 4, 5];
+//!
+//! for x in values {
+//! println!("{}", x);
+//! }
+//! ```
+//!
+//! Rust de-sugars this into:
+//!
+//! ```
+//! let values = vec![1, 2, 3, 4, 5];
+//! {
+//! let result = match values.into_iter() {
+//! mut iter => loop {
+//! match iter.next() {
+//! Some(x) => { println!("{}", x); },
+//! None => break,
+//! }
+//! },
+//! };
+//! result
//! }
//! ```
//!
-//! Because `Iterator`s implement `IntoIterator`, this `for` loop syntax can be
-//! applied to any iterator over any type.
+//! First, we call `into_iter()` on the value. Then, we match on the iterator
+//! that returns, calling [`next()`] over and over until we see a `None`. At
+//! that point, we `break` out of the loop, and we're done iterating.
+//!
+//! There's one more subtle bit here: the standard library contains an
+//! interesting implementation of [`IntoIterator`]:
+//!
+//! ```ignore
+//! impl<I> IntoIterator for I where I: Iterator
+//! ```
+//!
+//! In other words, all [`Iterator`]s implement [`IntoIterator`], by just
+//! returning themselves. This means two things:
+//!
+//! 1. If you're writing an [`Iterator`], you can use it with a `for` loop.
+//! 2. If you're creating a collection, implementing [`IntoIterator`] for it
+//! will allow your collection to be used with the `for` loop.
+//!
+//! # Adapters
+//!
+//! Functions which take an [`Iterator`] and return another [`Iterator`] are
+//! often called 'iterator adapters', as they're a form of the 'adapter
+//! pattern'.
+//!
+//! Common iterator adapters include [`map()`], [`take()`], and [`collect()`].
+//! For more, see their documentation.
+//!
+//! [`map()`]: trait.Iterator.html#method.map
+//! [`take()`]: trait.Iterator.html#method.take
+//! [`collect()`]: trait.Iterator.html#method.collect
+//!
+//! # Laziness
+//!
+//! Iterators (and iterator [adapters](#adapters)) are *lazy*. This means that
+//! just creating an iterator doesn't _do_ a whole lot. Nothing really happens
+//! until you call [`next()`]. This is sometimes a source of confusion when
+//! creating an iterator solely for its side effects. For example, the [`map()`]
+//! method calls a closure on each element it iterates over:
+//!
+//! ```
+//! let v = vec![1, 2, 3, 4, 5];
+//! v.iter().map(|x| println!("{}", x));
+//! ```
+//!
+//! This will not print any values, as we only created an iterator, rather than
+//! using it. The compiler will warn us about this kind of behavior:
+//!
+//! ```text
+//! warning: unused result which must be used: iterator adaptors are lazy and
+//! do nothing unless consumed
+//! ```
+//!
+//! The idiomatic way to write a [`map()`] for its side effects is to use a
+//! `for` loop instead:
+//!
+//! ```
+//! let v = vec![1, 2, 3, 4, 5];
+//!
+//! for x in &v {
+//! println!("{}", x);
+//! }
+//! ```
+//!
+//! [`map()`]: trait.Iterator.html#method.map
+//!
+//! The two most common ways to evaluate an iterator are to use a `for` loop
+//! like this, or using the [`collect()`] adapter to produce a new collection.
+//!
+//! [`collect()`]: trait.Iterator.html#method.collect
+//!
+//! # Infinity
+//!
+//! Iterators do not have to be finite. As an example, an open-ended range is
+//! an infinite iterator:
+//!
+//! ```
+//! let numbers = 0..;
+//! ```
+//!
+//! It is common to use the [`take()`] iterator adapter to turn an infinite
+//! iterator into a finite one:
+//!
+//! ```
+//! let numbers = 0..;
+//! let five_numbers = numbers.take(5);
+//!
+//! for number in five_numbers {
+//! println!("{}", number);
+//! }
+//! ```
+//!
+//! This will print the numbers `0` through `4`, each on their own line.
+//!
+//! [`take()`]: trait.Iterator.html#method.take
#![stable(feature = "rust1", since = "1.0.0")]
///
/// This is an idiosyncratic helper to try to factor out the
/// commonalities of {max,min}{,_by}. In particular, this avoids
-/// having to implement optimisations several times.
+/// having to implement optimizations several times.
#[inline]
fn select_fold1<I,B, FProj, FCmp>(mut it: I,
mut f_proj: FProj,
fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
}
-/// Creates a new iterator that endlessly repeats the element `elt`.
+/// Creates a new iterator that endlessly repeats a single element.
+///
+/// The `repeat()` function repeats a single value over and over and over and
+/// over and over and 🔁.
+///
+/// Infinite iterators like `repeat()` are often used with adapters like
+/// [`take()`], in order to make them finite.
+///
+/// [`take()`]: trait.Iterator.html#method.take
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // the number four 4ever:
+/// let mut fours = iter::repeat(4);
+///
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+///
+/// // yup, still four
+/// assert_eq!(Some(4), fours.next());
+/// ```
+///
+/// Going finite with [`take()`]:
+///
+/// ```
+/// use std::iter;
+///
+/// // that last example was too many fours. Let's only have four fours.
+/// let mut four_fours = iter::repeat(4).take(4);
+///
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+///
+/// // ... and now we're done
+/// assert_eq!(None, four_fours.next());
+/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
}
/// Creates an iterator that yields nothing.
+///
+/// # Exampes
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // this could have been an iterator over i32, but alas, it's just not.
+/// let mut nope = iter::empty::<i32>();
+///
+/// assert_eq!(None, nope.next());
+/// ```
#[stable(feature = "iter_empty", since = "1.2.0")]
pub fn empty<T>() -> Empty<T> {
Empty(marker::PhantomData)
}
/// Creates an iterator that yields an element exactly once.
+///
+/// This is commonly used to adapt a single value into a [`chain()`] of other
+/// kinds of iteration. Maybe you have an iterator that covers almost
+/// everything, but you need an extra special case. Maybe you have a function
+/// which works on iterators, but you only need to process one value.
+///
+/// [`chain()`]: trait.Iterator.html#method.chain
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // one is the loneliest number
+/// let mut one = iter::once(1);
+///
+/// assert_eq!(Some(1), one.next());
+///
+/// // just one, that's all we get
+/// assert_eq!(None, one.next());
+/// ```
+///
+/// Chaining together with another iterator. Let's say that we want to iterate
+/// over each file of the `.foo` directory, but also a configuration file,
+/// `.foorc`:
+///
+/// ```no_run
+/// use std::iter;
+/// use std::fs;
+/// use std::path::PathBuf;
+///
+/// let dirs = fs::read_dir(".foo").unwrap();
+///
+/// // we need to convert from an iterator of DirEntry-s to an iterator of
+/// // PathBufs, so we use map
+/// let dirs = dirs.map(|file| file.unwrap().path());
+///
+/// // now, our iterator just for our config file
+/// let config = iter::once(PathBuf::from(".foorc"));
+///
+/// // chain the two iterators together into one big iterator
+/// let files = dirs.chain(config);
+///
+/// // this will give us all of the files in .foo as well as .foorc
+/// for f in files {
+/// println!("{:?}", f);
+/// }
+/// ```
#[stable(feature = "iter_once", since = "1.2.0")]
pub fn once<T>(value: T) -> Once<T> {
Once { inner: Some(value).into_iter() }
});
}
-/// A standardised placeholder for marking unfinished code. It panics with the
+/// A standardized placeholder for marking unfinished code. It panics with the
/// message `"not yet implemented"` when executed.
///
/// This can be useful if you are prototyping and are just looking to have your
///
/// A somewhat surprising consequence of the definition is `&mut T` is
/// `Sync` (if `T` is `Sync`) even though it seems that it might
-/// provide unsynchronised mutation. The trick is a mutable reference
+/// provide unsynchronized mutation. The trick is a mutable reference
/// stored in an aliasable reference (that is, `& &mut T`) becomes
/// read-only, as if it were a `& &T`, hence there is no risk of a data
/// race.
///
/// Any types with interior mutability must also use the `std::cell::UnsafeCell`
/// wrapper around the value(s) which can be mutated when behind a `&`
-/// reference; not doing this is undefined behaviour (for example,
+/// reference; not doing this is undefined behavior (for example,
/// `transmute`-ing from `&T` to `&mut T` is invalid).
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sync"]
/// * You have two copies of a value (like when writing something like
/// [`mem::swap`][swap]), but need the destructor to only run once to
/// prevent a double `free`.
-/// * Transferring resources across [FFI][ffi] boundries.
+/// * Transferring resources across [FFI][ffi] boundaries.
///
/// [swap]: fn.swap.html
/// [ffi]: ../../book/ffi.html
/// This is useful for FFI functions and initializing arrays sometimes,
/// but should generally be avoided.
///
-/// # Undefined Behaviour
+/// # Undefined Behavior
///
-/// It is Undefined Behaviour to read uninitialized memory. Even just an
+/// It is Undefined Behavior to read uninitialized memory. Even just an
/// uninitialized boolean. For instance, if you branch on the value of such
/// a boolean your program may take one, both, or neither of the branches.
///
///
/// // DANGER ZONE: if anything panics or otherwise
/// // incorrectly reads the array here, we will have
-/// // Undefined Behaviour.
+/// // Undefined Behavior.
///
/// // It's ok to mutably iterate the data, since this
/// // doesn't involve reading it at all.
intrinsics::uninit()
}
-/// Swap the values at two mutable locations of the same type, without deinitialising or copying
+/// Swap the values at two mutable locations of the same type, without deinitializing or copying
/// either one.
///
/// # Examples
}
/// Replaces the value at a mutable location with a new one, returning the old value, without
-/// deinitialising or copying either one.
+/// deinitializing or copying either one.
///
/// This is primarily used for transferring and swapping ownership of a value in a mutable
/// location.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct NonZero<T: Zeroable>(T);
+#[cfg(stage0)]
+macro_rules! nonzero_new {
+ () => (
+ /// Creates an instance of NonZero with the provided value.
+ /// You must indeed ensure that the value is actually "non-zero".
+ #[inline(always)]
+ pub unsafe fn new(inner: T) -> NonZero<T> {
+ NonZero(inner)
+ }
+ )
+}
+#[cfg(not(stage0))]
+macro_rules! nonzero_new {
+ () => (
+ /// Creates an instance of NonZero with the provided value.
+ /// You must indeed ensure that the value is actually "non-zero".
+ #[inline(always)]
+ pub unsafe const fn new(inner: T) -> NonZero<T> {
+ NonZero(inner)
+ }
+ )
+}
+
impl<T: Zeroable> NonZero<T> {
- /// Creates an instance of NonZero with the provided value.
- /// You must indeed ensure that the value is actually "non-zero".
- #[inline(always)]
- pub unsafe fn new(inner: T) -> NonZero<T> {
- NonZero(inner)
- }
+ nonzero_new!{}
}
impl<T: Zeroable> Deref for NonZero<T> {
let s = s.as_bytes();
let (integral, s) = eat_digits(s);
match s.first() {
- None => Valid(Decimal::new(integral, b"", 0)),
+ None => {
+ if integral.is_empty() {
+ return Invalid; // No digits at all
+ }
+ Valid(Decimal::new(integral, b"", 0))
+ }
Some(&b'e') | Some(&b'E') => {
if integral.is_empty() {
return Invalid; // No digits before 'e'
use char::CharExt;
use cmp::{Eq, PartialOrd};
+use convert::From;
use fmt;
use intrinsics;
use marker::{Copy, Sized};
}
pub use num::dec2flt::ParseFloatError;
+
+// Conversion traits for primitive integer types
+// Conversions T -> T are covered by a blanket impl and therefore excluded
+// Some conversions from and to usize/isize are not implemented due to portability concerns
+macro_rules! impl_from {
+ ($Small: ty, $Large: ty) => {
+ #[stable(feature = "lossless_int_conv", since = "1.5.0")]
+ impl From<$Small> for $Large {
+ #[stable(feature = "lossless_int_conv", since = "1.5.0")]
+ #[inline]
+ fn from(small: $Small) -> $Large {
+ small as $Large
+ }
+ }
+ }
+}
+
+// Unsigned -> Unsigned
+impl_from! { u8, u16 }
+impl_from! { u8, u32 }
+impl_from! { u8, u64 }
+impl_from! { u8, usize }
+impl_from! { u16, u32 }
+impl_from! { u16, u64 }
+impl_from! { u32, u64 }
+
+// Signed -> Signed
+impl_from! { i8, i16 }
+impl_from! { i8, i32 }
+impl_from! { i8, i64 }
+impl_from! { i8, isize }
+impl_from! { i16, i32 }
+impl_from! { i16, i64 }
+impl_from! { i32, i64 }
+
+// Unsigned -> Signed
+impl_from! { u8, i16 }
+impl_from! { u8, i32 }
+impl_from! { u8, i64 }
+impl_from! { u16, i32 }
+impl_from! { u16, i64 }
+impl_from! { u32, i64 }
pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
/// Swaps the values at two mutable locations of the same type, without
-/// deinitialising either. They may overlap, unlike `mem::swap` which is
+/// deinitializing either. They may overlap, unlike `mem::swap` which is
/// otherwise equivalent.
///
/// # Safety
///
/// # Safety
///
-/// Beyond accepting a raw pointer, this operation is unsafe because it does
-/// not drop the contents of `dst`. This could leak allocations or resources,
-/// so care must be taken not to overwrite an object that should be dropped.
+/// This operation is marked unsafe because it accepts a raw pointer.
+///
+/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// allocations or resources, so care must be taken not to overwrite an object
+/// that should be dropped.
///
/// This is appropriate for initializing uninitialized memory, or overwriting
/// memory that has previously been `read` from.
/// # Safety
///
/// The offset must be in-bounds of the object, or one-byte-past-the-end.
- /// Otherwise `offset` invokes Undefined Behaviour, regardless of whether
+ /// Otherwise `offset` invokes Undefined Behavior, regardless of whether
/// the pointer is used.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
-/// behaviour.
+/// behavior.
///
/// # Examples
///
/// Converts a slice of bytes to a string slice without checking
/// that the string contains valid UTF-8.
///
-/// See the safe version, [`from_utrf8()`][fromutf8], for more.
+/// See the safe version, [`from_utf8()`][fromutf8], for more.
///
/// [fromutf8]: fn.from_utf8.html
///
#[allow(deprecated)]
pub struct LinesAny<'a>(Lines<'a>);
-/// A nameable, clonable fn type
+/// A nameable, cloneable fn type
#[derive(Clone)]
struct LinesAnyMap;
assert_eq!(".".parse(), Ok(0.0));
}
+#[test]
+fn lonely_sign() {
+ assert!("+".parse::<f32>().is_err());
+ assert!("-".parse::<f64>().is_err());
+}
+
+#[test]
+fn whitespace() {
+ assert!(" 1.0".parse::<f32>().is_err());
+ assert!("1.0 ".parse::<f64>().is_err());
+}
+
#[test]
fn nan() {
assert!("NaN".parse::<f32>().unwrap().is_nan());
assert_eq!("+".parse::<i8>().ok(), None);
assert_eq!("".parse::<u8>().ok(), None);
}
+
+ macro_rules! test_impl_from {
+ ($fn_name: ident, $Small: ty, $Large: ty) => {
+ #[test]
+ fn $fn_name() {
+ let small_max = <$Small>::max_value();
+ let small_min = <$Small>::min_value();
+ let large_max: $Large = small_max.into();
+ let large_min: $Large = small_min.into();
+ assert_eq!(large_max as $Small, small_max);
+ assert_eq!(large_min as $Small, small_min);
+ }
+ }
+ }
+
+ // Unsigned -> Unsigned
+ test_impl_from! { test_u8u16, u8, u16 }
+ test_impl_from! { test_u8u32, u8, u32 }
+ test_impl_from! { test_u8u64, u8, u64 }
+ test_impl_from! { test_u8usize, u8, usize }
+ test_impl_from! { test_u16u32, u16, u32 }
+ test_impl_from! { test_u16u64, u16, u64 }
+ test_impl_from! { test_u32u64, u32, u64 }
+
+ // Signed -> Signed
+ test_impl_from! { test_i8i16, i8, i16 }
+ test_impl_from! { test_i8i32, i8, i32 }
+ test_impl_from! { test_i8i64, i8, i64 }
+ test_impl_from! { test_i8isize, i8, isize }
+ test_impl_from! { test_i16i32, i16, i32 }
+ test_impl_from! { test_i16i64, i16, i64 }
+ test_impl_from! { test_i32i64, i32, i64 }
+
+ // Unsigned -> Signed
+ test_impl_from! { test_u8i16, u8, i16 }
+ test_impl_from! { test_u8i32, u8, i32 }
+ test_impl_from! { test_u8i64, u8, i64 }
+ test_impl_from! { test_u16i32, u16, i32 }
+ test_impl_from! { test_u16i64, u16, i64 }
+ test_impl_from! { test_u32i64, u32, i64 }
}
#![feature(unique)]
#![cfg_attr(test, feature(rustc_private, rand, vec_push_all))]
-#[cfg(test)] #[macro_use] extern crate log;
+#[cfg(test)]
+#[macro_use]
+extern crate log;
extern crate libc;
impl Error {
fn new() -> Error {
- Error {
- _unused: (),
- }
+ Error { _unused: () }
}
}
impl Drop for Bytes {
fn drop(&mut self) {
- unsafe { libc::free(*self.ptr as *mut _); }
+ unsafe {
+ libc::free(*self.ptr as *mut _);
+ }
}
}
deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
}
-fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result<Bytes,Error> {
+fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result<Bytes, Error> {
unsafe {
let mut outsz: size_t = 0;
let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _,
}
/// Decompress a buffer, without parsing any sort of header on the input.
-pub fn inflate_bytes(bytes: &[u8]) -> Result<Bytes,Error> {
+pub fn inflate_bytes(bytes: &[u8]) -> Result<Bytes, Error> {
inflate_bytes_internal(bytes, 0)
}
/// Decompress a buffer that starts with a zlib header.
-pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result<Bytes,Error> {
+pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result<Bytes, Error> {
inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
}
let cmp = deflate_bytes(&input);
let out = inflate_bytes(&cmp).unwrap();
debug!("{} bytes deflated to {} ({:.1}% size)",
- input.len(), cmp.len(),
+ input.len(),
+ cmp.len(),
100.0 * ((cmp.len() as f64) / (input.len() as f64)));
assert_eq!(&*input, &*out);
}
/// The descriptor string representing the name of the format desired for
/// this argument, this can be empty or any number of characters, although
/// it is required to be one word.
- pub ty: &'a str
+ pub ty: &'a str,
}
/// Enum describing where an argument for a format can be located.
}
/// The parser structure for interpreting the input format string. This is
-/// modelled as an iterator over `Piece` structures to form a stream of tokens
+/// modeled as an iterator over `Piece` structures to form a stream of tokens
/// being output.
///
/// This is a recursive-descent parser for the sake of simplicity, and if
/// returned, otherwise the character is consumed and true is returned.
fn consume(&mut self, c: char) -> bool {
if let Some(&(_, maybe)) = self.cur.peek() {
- if c == maybe { self.cur.next(); true } else { false }
+ if c == maybe {
+ self.cur.next();
+ true
+ } else {
+ false
+ }
} else {
false
}
/// character
fn ws(&mut self) {
while let Some(&(_, c)) = self.cur.peek() {
- if c.is_whitespace() { self.cur.next(); } else { break }
+ if c.is_whitespace() {
+ self.cur.next();
+ } else {
+ break
+ }
}
}
// we may not consume the character, peek the iterator
while let Some(&(pos, c)) = self.cur.peek() {
match c {
- '{' | '}' => { return &self.input[start..pos]; }
- _ => { self.cur.next(); }
+ '{' | '}' => {
+ return &self.input[start..pos];
+ }
+ _ => {
+ self.cur.next();
+ }
}
}
&self.input[start..self.input.len()]
Some(&(_, c)) if c.is_alphabetic() => {
ArgumentNamed(self.word())
}
- _ => ArgumentNext
+ _ => ArgumentNext,
}
}
}
width: CountImplied,
ty: &self.input[..0],
};
- if !self.consume(':') { return spec }
+ if !self.consume(':') {
+ return spec
+ }
// fill character
if let Some(&(_, c)) = self.cur.peek() {
/// width.
fn count(&mut self) -> Count<'a> {
if let Some(i) = self.integer() {
- if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
+ if self.consume('$') {
+ CountIsParam(i)
+ } else {
+ CountIs(i)
+ }
} else {
let tmp = self.cur.clone();
let word = self.word();
/// characters.
fn word(&mut self) -> &'a str {
let start = match self.cur.peek() {
- Some(&(pos, c)) if c.is_xid_start() => { self.cur.next(); pos }
- _ => { return &self.input[..0]; }
+ Some(&(pos, c)) if c.is_xid_start() => {
+ self.cur.next();
+ pos
+ }
+ _ => {
+ return &self.input[..0];
+ }
};
while let Some(&(pos, c)) = self.cur.peek() {
if c.is_xid_continue() {
break
}
}
- if found { Some(cur) } else { None }
+ if found {
+ Some(cur)
+ } else {
+ None
+ }
}
}
same("\\}}", &[String("\\"), String("}")]);
}
- #[test] fn invalid01() { musterr("{") }
- #[test] fn invalid02() { musterr("}") }
- #[test] fn invalid04() { musterr("{3a}") }
- #[test] fn invalid05() { musterr("{:|}") }
- #[test] fn invalid06() { musterr("{:>>>}") }
+ #[test]
+ fn invalid01() {
+ musterr("{")
+ }
+ #[test]
+ fn invalid02() {
+ musterr("}")
+ }
+ #[test]
+ fn invalid04() {
+ musterr("{3a}")
+ }
+ #[test]
+ fn invalid05() {
+ musterr("{:|}")
+ }
+ #[test]
+ fn invalid06() {
+ musterr("{:>>>}")
+ }
#[test]
fn format_nothing() {
- same("{}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: fmtdflt(),
- })]);
+ same("{}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: fmtdflt(),
+ })]);
}
#[test]
fn format_position() {
- same("{3}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: fmtdflt(),
- })]);
+ same("{3}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: fmtdflt(),
+ })]);
}
#[test]
fn format_position_nothing_else() {
- same("{3:}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: fmtdflt(),
- })]);
+ same("{3:}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: fmtdflt(),
+ })]);
}
#[test]
fn format_type() {
- same("{3:a}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "a",
- },
- })]);
+ same("{3:a}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "a",
+ },
+ })]);
}
#[test]
fn format_align_fill() {
- same("{3:>}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: None,
- align: AlignRight,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "",
- },
- })]);
- same("{3:0<}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: Some('0'),
- align: AlignLeft,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "",
- },
- })]);
- same("{3:*<abcd}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: Some('*'),
- align: AlignLeft,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "abcd",
- },
- })]);
+ same("{3:>}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: AlignRight,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ })]);
+ same("{3:0<}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: Some('0'),
+ align: AlignLeft,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ })]);
+ same("{3:*<abcd}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: Some('*'),
+ align: AlignLeft,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "abcd",
+ },
+ })]);
}
#[test]
fn format_counts() {
- same("{:10s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountImplied,
- width: CountIs(10),
- ty: "s",
- },
- })]);
- same("{:10$.10s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountIs(10),
- width: CountIsParam(10),
- ty: "s",
- },
- })]);
- same("{:.*s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountIsNextParam,
- width: CountImplied,
- ty: "s",
- },
- })]);
- same("{:.10$s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountIsParam(10),
- width: CountImplied,
- ty: "s",
- },
- })]);
- same("{:a$.b$s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountIsName("b"),
- width: CountIsName("a"),
- ty: "s",
- },
- })]);
+ same("{:10s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountImplied,
+ width: CountIs(10),
+ ty: "s",
+ },
+ })]);
+ same("{:10$.10s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIs(10),
+ width: CountIsParam(10),
+ ty: "s",
+ },
+ })]);
+ same("{:.*s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIsNextParam,
+ width: CountImplied,
+ ty: "s",
+ },
+ })]);
+ same("{:.10$s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIsParam(10),
+ width: CountImplied,
+ ty: "s",
+ },
+ })]);
+ same("{:a$.b$s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIsName("b"),
+ width: CountIsName("a"),
+ ty: "s",
+ },
+ })]);
}
#[test]
fn format_flags() {
- same("{:-}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: (1 << FlagSignMinus as u32),
- precision: CountImplied,
- width: CountImplied,
- ty: "",
- },
- })]);
- same("{:+#}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
- precision: CountImplied,
- width: CountImplied,
- ty: "",
- },
- })]);
+ same("{:-}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: (1 << FlagSignMinus as u32),
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ })]);
+ same("{:+#}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ })]);
}
#[test]
fn format_mixture() {
- same("abcd {3:a} efg", &[String("abcd "), NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "a",
- },
- }), String(" efg")]);
+ same("abcd {3:a} efg",
+ &[String("abcd "),
+ NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "a",
+ },
+ }),
+ String(" efg")]);
}
}
fn graph_id(&'a self) -> Id<'a>;
/// Maps `n` to a unique identifier with respect to `self`. The
- /// implementer is responsible for ensuring that the returned name
+ /// implementor is responsible for ensuring that the returned name
/// is a valid DOT identifier.
fn node_id(&'a self, n: &N) -> Id<'a>;
/// that is bound by the self lifetime `'a`.
///
/// The `nodes` and `edges` method each return instantiations of
-/// `Cow<[T]>` to leave implementers the freedom to create
+/// `Cow<[T]>` to leave implementors the freedom to create
/// entirely new vectors or to pass back slices into internally owned
/// vectors.
pub trait GraphWalk<'a, N: Clone, E: Clone> {
pub level: u32,
}
-pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO",
- "DEBUG"];
+pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO", "DEBUG"];
/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
- level.parse::<u32>().ok().or_else(|| {
- let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
- pos.map(|p| p as u32 + 1)
- }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
+ level.parse::<u32>()
+ .ok()
+ .or_else(|| {
+ let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
+ pos.map(|p| p as u32 + 1)
+ })
+ .map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
let mods = parts.next();
let filter = parts.next();
if parts.next().is_some() {
- println!("warning: invalid logging spec '{}', \
- ignoring it (too many '/'s)", spec);
+ println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)",
+ spec);
return (dirs, None);
}
- mods.map(|m| { for s in m.split(',') {
- if s.is_empty() { continue }
- let mut parts = s.split('=');
- let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
- (Some(part0), None, None) => {
- // if the single argument is a log-level string or number,
- // treat that as a global fallback
- match parse_log_level(part0) {
- Some(num) => (num, None),
- None => (::MAX_LOG_LEVEL, Some(part0)),
- }
+ if let Some(m) = mods {
+ for s in m.split(',') {
+ if s.is_empty() {
+ continue
}
- (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
- (Some(part0), Some(part1), None) => {
- match parse_log_level(part1) {
- Some(num) => (num, Some(part0)),
- _ => {
- println!("warning: invalid logging spec '{}', \
- ignoring it", part1);
- continue
+ let mut parts = s.split('=');
+ let (log_level, name) = match (parts.next(),
+ parts.next().map(|s| s.trim()),
+ parts.next()) {
+ (Some(part0), None, None) => {
+ // if the single argument is a log-level string or number,
+ // treat that as a global fallback
+ match parse_log_level(part0) {
+ Some(num) => (num, None),
+ None => (::MAX_LOG_LEVEL, Some(part0)),
}
}
- },
- _ => {
- println!("warning: invalid logging spec '{}', \
- ignoring it", s);
- continue
- }
- };
- dirs.push(LogDirective {
- name: name.map(str::to_owned),
- level: log_level,
- });
- }});
+ (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
+ (Some(part0), Some(part1), None) => {
+ match parse_log_level(part1) {
+ Some(num) => (num, Some(part0)),
+ _ => {
+ println!("warning: invalid logging spec '{}', ignoring it", part1);
+ continue
+ }
+ }
+ }
+ _ => {
+ println!("warning: invalid logging spec '{}', ignoring it", s);
+ continue
+ }
+ };
+ dirs.push(LogDirective {
+ name: name.map(str::to_owned),
+ level: log_level,
+ });
+ }
+ }
(dirs, filter.map(str::to_owned))
}
fn log(&mut self, record: &LogRecord);
}
-struct DefaultLogger { handle: Stderr }
+struct DefaultLogger {
+ handle: Stderr,
+}
/// Wraps the log level with fmt implementations.
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
let LogLevel(level) = *self;
match LOG_LEVEL_NAMES.get(level as usize - 1) {
Some(ref name) => fmt::Display::fmt(name, fmt),
- None => fmt::Display::fmt(&level, fmt)
+ None => fmt::Display::fmt(&level, fmt),
}
}
}
// Completely remove the local logger from TLS in case anyone attempts to
// frob the slot while we're doing the logging. This will destroy any logger
// set during logging.
- let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| {
- s.borrow_mut().take()
- }).unwrap_or_else(|| {
- box DefaultLogger { handle: io::stderr() }
- });
+ let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| s.borrow_mut().take())
+ .unwrap_or_else(|| {
+ box DefaultLogger { handle: io::stderr() }
+ });
logger.log(&LogRecord {
level: LogLevel(level),
args: args,
/// safely
#[doc(hidden)]
#[inline(always)]
-pub fn log_level() -> u32 { unsafe { LOG_LEVEL } }
+pub fn log_level() -> u32 {
+ unsafe { LOG_LEVEL }
+}
/// Replaces the thread-local logger with the specified logger, returning the old
/// logger.
pub fn set_logger(logger: Box<Logger + Send>) -> Option<Box<Logger + Send>> {
- let mut l = Some(logger);
- LOCAL_LOGGER.with(|slot| {
- mem::replace(&mut *slot.borrow_mut(), l.take())
- })
+ LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger)))
}
/// A LogRecord is created by the logging macros, and passed as the only
/// argument to Loggers.
#[derive(Debug)]
pub struct LogRecord<'a> {
-
/// The module path of where the LogRecord originated.
pub module_path: &'a str,
// again to whether they should really be here or not. Hence, despite this
// check being expanded manually in the logging macro, this function checks
// the log level again.
- if level > unsafe { LOG_LEVEL } { return false }
+ if level > unsafe { LOG_LEVEL } {
+ return false
+ }
// This assertion should never get tripped unless we're in an at_exit
// handler after logging has been torn down and a logging attempt was made.
}
}
-fn enabled(level: u32,
- module: &str,
- iter: slice::Iter<directive::LogDirective>)
- -> bool {
+fn enabled(level: u32, module: &str, iter: slice::Iter<directive::LogDirective>) -> bool {
// Search for the longest match, the vector is assumed to be pre-sorted.
for directive in iter.rev() {
match directive.name {
- Some(ref name) if !module.starts_with(&name[..]) => {},
+ Some(ref name) if !module.starts_with(&name[..]) => {}
Some(..) | None => {
return level <= directive.level
}
#[test]
fn match_full_path() {
- let dirs = [
- LogDirective {
- name: Some("crate2".to_string()),
- level: 3
- },
- LogDirective {
- name: Some("crate1::mod1".to_string()),
- level: 2
- }
- ];
+ let dirs = [LogDirective {
+ name: Some("crate2".to_string()),
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(enabled(2, "crate1::mod1", dirs.iter()));
assert!(!enabled(3, "crate1::mod1", dirs.iter()));
assert!(enabled(3, "crate2", dirs.iter()));
#[test]
fn no_match() {
- let dirs = [
- LogDirective { name: Some("crate2".to_string()), level: 3 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
- ];
+ let dirs = [LogDirective {
+ name: Some("crate2".to_string()),
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(!enabled(2, "crate3", dirs.iter()));
}
#[test]
fn match_beginning() {
- let dirs = [
- LogDirective { name: Some("crate2".to_string()), level: 3 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
- ];
+ let dirs = [LogDirective {
+ name: Some("crate2".to_string()),
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(enabled(3, "crate2::mod1", dirs.iter()));
}
#[test]
fn match_beginning_longest_match() {
- let dirs = [
- LogDirective { name: Some("crate2".to_string()), level: 3 },
- LogDirective { name: Some("crate2::mod".to_string()), level: 4 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
- ];
+ let dirs = [LogDirective {
+ name: Some("crate2".to_string()),
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate2::mod".to_string()),
+ level: 4,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(enabled(4, "crate2::mod1", dirs.iter()));
assert!(!enabled(4, "crate2", dirs.iter()));
}
#[test]
fn match_default() {
- let dirs = [
- LogDirective { name: None, level: 3 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
- ];
+ let dirs = [LogDirective {
+ name: None,
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(enabled(2, "crate1::mod1", dirs.iter()));
assert!(enabled(3, "crate2::mod2", dirs.iter()));
}
#[test]
fn zero_level() {
- let dirs = [
- LogDirective { name: None, level: 3 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 0 }
- ];
+ let dirs = [LogDirective {
+ name: None,
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 0,
+ }];
assert!(!enabled(1, "crate1::mod1", dirs.iter()));
assert!(enabled(3, "crate2::mod2", dirs.iter()));
}
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
-/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2,
+/// `k`, this uses the equivalent characterization `χ²(k) = Gamma(k/2,
/// 2)`.
pub struct ChiSquared {
repr: ChiSquaredRepr,
pub struct StandardNormal(pub f64);
impl Rand for StandardNormal {
- fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
+ fn rand<R: Rng>(rng: &mut R) -> StandardNormal {
#[inline]
fn pdf(x: f64) -> f64 {
- (-x*x/2.0).exp()
+ (-x * x / 2.0).exp()
}
#[inline]
- fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
+ fn zero_case<R: Rng>(rng: &mut R, u: f64) -> f64 {
// compute a random number in the tail by hand
// strange initial conditions, because the loop is not
y = y_.ln();
}
- if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
+ if u < 0.0 {
+ x - ziggurat_tables::ZIG_NORM_R
+ } else {
+ ziggurat_tables::ZIG_NORM_R - x
+ }
}
- StandardNormal(ziggurat(
- rng,
- true, // this is symmetric
- &ziggurat_tables::ZIG_NORM_X,
- &ziggurat_tables::ZIG_NORM_F,
- pdf, zero_case))
+ StandardNormal(ziggurat(rng,
+ true, // this is symmetric
+ &ziggurat_tables::ZIG_NORM_X,
+ &ziggurat_tables::ZIG_NORM_F,
+ pdf,
+ zero_case))
}
}
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
Normal {
mean: mean,
- std_dev: std_dev
+ std_dev: std_dev,
}
}
}
impl Sample<f64> for Normal {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for Normal {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
/// std_dev**2)` distributed.
#[derive(Copy, Clone)]
pub struct LogNormal {
- norm: Normal
+ norm: Normal,
}
impl LogNormal {
}
}
impl Sample<f64> for LogNormal {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for LogNormal {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
use std::prelude::v1::*;
use self::test::Bencher;
use std::mem::size_of;
- use distributions::{Sample};
+ use distributions::Sample;
use super::Normal;
#[bench]
ItemEnum(ref enum_definition, _) => {
for v in &enum_definition.variants {
let variant_def_index =
- self.insert_def(v.node.id,
+ self.insert_def(v.node.data.id(),
NodeVariant(&**v),
DefPathData::EnumVariant(v.node.name));
- match v.node.kind {
- TupleVariantKind(ref args) => {
- for arg in args {
- self.create_def_with_parent(Some(variant_def_index),
- arg.id,
- DefPathData::PositionalField);
- }
- }
- StructVariantKind(ref def) => {
- for field in &def.fields {
- self.create_def_with_parent(
- Some(variant_def_index),
- field.node.id,
- DefPathData::Field(field.node.kind));
- }
- }
+ for field in v.node.data.fields() {
+ self.create_def_with_parent(
+ Some(variant_def_index),
+ field.node.id,
+ DefPathData::Field(field.node.kind));
}
}
}
}
ItemStruct(ref struct_def, _) => {
// If this is a tuple-like struct, register the constructor.
- if let Some(ctor_id) = struct_def.ctor_id {
- self.insert_def(ctor_id,
+ if !struct_def.is_struct() {
+ self.insert_def(struct_def.id(),
NodeStructCtor(&**struct_def),
DefPathData::StructCtor);
}
- for field in &struct_def.fields {
+ for field in struct_def.fields() {
self.create_def(field.node.id, DefPathData::Field(field.node.kind));
}
}
NodeBlock(&'ast Block),
/// NodeStructCtor represents a tuple struct.
- NodeStructCtor(&'ast StructDef),
+ NodeStructCtor(&'ast VariantData),
NodeLifetime(&'ast Lifetime),
NodeTyParam(&'ast TyParam)
EntryLocal(NodeId, &'ast Pat),
EntryPat(NodeId, &'ast Pat),
EntryBlock(NodeId, &'ast Block),
- EntryStructCtor(NodeId, &'ast StructDef),
+ EntryStructCtor(NodeId, &'ast VariantData),
EntryLifetime(NodeId, &'ast Lifetime),
EntryTyParam(NodeId, &'ast TyParam),
}
}
- pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef {
+ pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData {
match self.find(id) {
Some(NodeItem(i)) => {
match i.node {
- ItemStruct(ref struct_def, _) => &**struct_def,
+ ItemStruct(ref struct_def, _) => struct_def,
_ => panic!("struct ID bound to non-struct")
}
}
Some(NodeVariant(variant)) => {
- match variant.node.kind {
- StructVariantKind(ref struct_def) => &**struct_def,
- _ => panic!("struct ID bound to enum variant that isn't struct-like"),
+ if variant.node.data.is_struct() {
+ &variant.node.data
+ } else {
+ panic!("struct ID bound to enum variant that isn't struct-like")
}
}
_ => panic!(format!("expected struct, found {}", self.node_to_string(id))),
NodeTraitItem(ti) => PathName(ti.name),
NodeVariant(v) => PathName(v.node.name),
NodeLifetime(lt) => PathName(lt.name),
+ NodeTyParam(tp) => PathName(tp.name),
+ NodeLocal(&Pat { node: PatIdent(_,l,_), .. }) => {
+ PathName(l.node.name)
+ },
_ => panic!("no path elem for {:?}", node)
}
}
}
}
}
-
hir_visit::walk_fn(self, fk, decl, body, span);
}
- fn visit_struct_def(&mut self,
- s: &hir::StructDef,
+ fn visit_variant_data(&mut self,
+ s: &hir::VariantData,
name: ast::Name,
g: &hir::Generics,
- id: ast::NodeId) {
- run_lints!(self, check_struct_def, late_passes, s, name, g, id);
+ item_id: ast::NodeId,
+ _: Span) {
+ run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
hir_visit::walk_struct_def(self, s);
- run_lints!(self, check_struct_def_post, late_passes, s, name, g, id);
+ run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
}
fn visit_struct_field(&mut self, s: &hir::StructField) {
})
}
- fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) {
+ fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
self.with_lint_attrs(&v.node.attrs, |cx| {
run_lints!(cx, check_variant, late_passes, v, g);
- hir_visit::walk_variant(cx, v, g);
+ hir_visit::walk_variant(cx, v, g, item_id);
run_lints!(cx, check_variant_post, late_passes, v, g);
})
}
ast_visit::walk_fn(self, fk, decl, body, span);
}
- fn visit_struct_def(&mut self,
- s: &ast::StructDef,
+ fn visit_variant_data(&mut self,
+ s: &ast::VariantData,
ident: ast::Ident,
g: &ast::Generics,
- id: ast::NodeId) {
- run_lints!(self, check_struct_def, early_passes, s, ident, g, id);
+ item_id: ast::NodeId,
+ _: Span) {
+ run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
ast_visit::walk_struct_def(self, s);
- run_lints!(self, check_struct_def_post, early_passes, s, ident, g, id);
+ run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
}
fn visit_struct_field(&mut self, s: &ast::StructField) {
})
}
- fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics) {
+ fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) {
self.with_lint_attrs(&v.node.attrs, |cx| {
run_lints!(cx, check_variant, early_passes, v, g);
- ast_visit::walk_variant(cx, v, g);
+ ast_visit::walk_variant(cx, v, g, item_id);
run_lints!(cx, check_variant_post, early_passes, v, g);
})
}
fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { }
fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { }
fn check_struct_def(&mut self, _: &LateContext,
- _: &hir::StructDef, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
+ _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
fn check_struct_def_post(&mut self, _: &LateContext,
- _: &hir::StructDef, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
+ _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { }
fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { }
fn check_struct_def(&mut self, _: &EarlyContext,
- _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
+ _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
fn check_struct_def_post(&mut self, _: &EarlyContext,
- _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
+ _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { }
fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
let vid = variant.did;
let variant_node_id = ecx.local_id(vid);
- if let ty::VariantKind::Dict = variant.kind() {
+ if let ty::VariantKind::Struct = variant.kind() {
// tuple-like enum variant fields aren't really items so
// don't try to encode them.
for field in &variant.fields {
encode_def_id_and_key(ecx, rbml_w, vid);
encode_family(rbml_w, match variant.kind() {
ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v',
- ty::VariantKind::Dict => 'V'
+ ty::VariantKind::Struct => 'V'
});
encode_name(rbml_w, variant.name);
encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
match item.node {
hir::ItemStruct(ref struct_def, _) => {
// If this is a newtype struct, return the constructor.
- match struct_def.ctor_id {
- Some(ctor_id) if !struct_def.fields.is_empty() &&
- struct_def.fields[0].node.kind.is_unnamed() => {
- continue_ = callback(ctor_id);
- }
- _ => {}
+ if struct_def.is_tuple() {
+ continue_ = callback(struct_def.id());
}
}
_ => {}
encode_attributes(rbml_w, &item.attrs);
encode_repr_attrs(rbml_w, ecx, &item.attrs);
for v in &enum_definition.variants {
- encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.id));
+ encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
}
encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
encode_path(rbml_w, path);
// Encode inherent implementations for this structure.
encode_inherent_implementations(ecx, rbml_w, def_id);
- if let Some(ctor_id) = struct_def.ctor_id {
- let ctor_did = ecx.tcx.map.local_def_id(ctor_id);
+ if !struct_def.is_struct() {
+ let ctor_did = ecx.tcx.map.local_def_id(struct_def.id());
rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
def_to_u64(ctor_did));
}
}
// If this is a tuple-like struct, encode the type of the constructor.
- if let Some(ctor_id) = struct_def.ctor_id {
- encode_info_for_struct_ctor(ecx, rbml_w, item.name,
- ctor_id, index, item.id);
+ if !struct_def.is_struct() {
+ encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id);
}
}
hir::ItemDefaultImpl(unsafety, _) => {
def.variants.iter().zip(orig_def.variants.iter())
{
debug!("astencode: copying variant {:?} => {:?}",
- orig_variant.did, i_variant.node.id);
- copy_item_type(dcx, i_variant.node.id, orig_variant.did);
+ orig_variant.did, i_variant.node.data.id());
+ copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did);
}
}
hir::ItemStruct(ref def, _) => {
- if let Some(ctor_id) = def.ctor_id {
+ if !def.is_struct() {
let ctor_did = dcx.tcx.lookup_adt_def(orig_did)
.struct_variant().did;
debug!("astencode: copying ctor {:?} => {:?}", ctor_did,
- ctor_id);
- copy_item_type(dcx, ctor_id, ctor_did);
+ def.id());
+ copy_item_type(dcx, def.id(), ctor_did);
}
}
_ => {}
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
let v = adt.variant_of_ctor(ctor);
- if let VariantKind::Dict = v.kind() {
+ if let VariantKind::Struct = v.kind() {
let field_pats: Vec<_> = v.fields.iter()
.zip(pats)
.filter(|&(_, ref pat)| pat.node != hir::PatWild(hir::PatWildSingle))
let mut recursion_visitor =
CheckItemRecursionVisitor::new(self, &variant.span);
recursion_visitor.populate_enum_discriminants(enum_def);
- recursion_visitor.visit_variant(variant, generics);
+ recursion_visitor.visit_variant(variant, generics, it.id);
}
}
}
let mut discriminant_map = self.discriminant_map.borrow_mut();
match enum_definition.variants.first() {
None => { return; }
- Some(variant) if discriminant_map.contains_key(&variant.node.id) => {
+ Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => {
return;
}
_ => {}
// Go through all the variants.
let mut variant_stack: Vec<ast::NodeId> = Vec::new();
for variant in enum_definition.variants.iter().rev() {
- variant_stack.push(variant.node.id);
+ variant_stack.push(variant.node.data.id());
// When we find an expression, every variant currently on the stack
// is affected by that expression.
if let Some(ref expr) = variant.node.disr_expr {
}
fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef,
- generics: &'ast hir::Generics) {
+ generics: &'ast hir::Generics, item_id: ast::NodeId) {
self.populate_enum_discriminants(enum_definition);
- visit::walk_enum_def(self, enum_definition, generics);
+ visit::walk_enum_def(self, enum_definition, generics, item_id);
}
fn visit_variant(&mut self, variant: &'ast hir::Variant,
- _: &'ast hir::Generics) {
- let variant_id = variant.node.id;
+ _: &'ast hir::Generics, _: ast::NodeId) {
+ let variant_id = variant.node.data.id();
let maybe_expr;
if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) {
// This is necessary because we need to let the `discriminant_map`
self.ast_map.expect_item(enum_node_id).node
{
self.populate_enum_discriminants(enum_def);
+ let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap();
let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
let variant = self.ast_map.expect_variant(variant_id);
- self.visit_variant(variant, generics);
+ self.visit_variant(variant, generics, enum_id);
} else {
self.sess.span_bug(e.span,
"`check_static_recursion` found \
fn variant_expr<'a>(variants: &'a [P<hir::Variant>], id: ast::NodeId)
-> Option<&'a Expr> {
for variant in variants {
- if variant.node.id == id {
+ if variant.node.data.id() == id {
return variant.node.disr_expr.as_ref().map(|e| &**e);
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
- fn visit_struct_def(&mut self, def: &hir::StructDef, _: ast::Name,
- _: &hir::Generics, _: ast::NodeId) {
+ fn visit_variant_data(&mut self, def: &hir::VariantData, _: ast::Name,
+ _: &hir::Generics, _: ast::NodeId, _: codemap::Span) {
let has_extern_repr = self.struct_has_extern_repr;
let inherited_pub_visibility = self.inherited_pub_visibility;
- let live_fields = def.fields.iter().filter(|f| {
+ let live_fields = def.fields().filter(|f| {
has_extern_repr || inherited_pub_visibility || match f.node.kind {
hir::NamedField(_, hir::Public) => true,
_ => false
}
match item.node {
hir::ItemEnum(ref enum_def, _) if allow_dead_code => {
- self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id));
+ self.worklist.extend(enum_def.variants.iter()
+ .map(|variant| variant.node.data.id()));
}
hir::ItemTrait(_, _, _, ref trait_items) => {
for trait_item in trait_items {
fn get_struct_ctor_id(item: &hir::Item) -> Option<ast::NodeId> {
match item.node {
- hir::ItemStruct(ref struct_def, _) => struct_def.ctor_id,
+ hir::ItemStruct(ref struct_def, _) if !struct_def.is_struct() => {
+ Some(struct_def.id())
+ }
_ => None
}
}
}
fn should_warn_about_variant(&mut self, variant: &hir::Variant_) -> bool {
- !self.symbol_is_live(variant.id, None)
+ !self.symbol_is_live(variant.data.id(), None)
&& !has_allow_dead_code_or_lang_attr(&variant.attrs)
}
hir::ItemEnum(ref enum_def, _) => {
for variant in &enum_def.variants {
if self.should_warn_about_variant(&variant.node) {
- self.warn_dead_code(variant.node.id, variant.span,
+ self.warn_dead_code(variant.node.data.id(), variant.span,
variant.node.name, "variant");
}
}
ast::NodeId), // expr node that creates the closure
/// Note that if it's a tuple struct's definition, the node id of the DefId
- /// may either refer to the item definition's id or the StructDef.ctor_id.
+ /// may either refer to the item definition's id or the VariantData.ctor_id.
///
/// The cases that I have encountered so far are (this is not exhaustive):
/// - If it's a ty_path referring to some tuple struct, then DefMap maps
/// it to a def whose id is the item definition's id.
/// - If it's an ExprPath referring to some tuple struct, then DefMap maps
- /// it to a def whose id is the StructDef.ctor_id.
+ /// it to a def whose id is the VariantData.ctor_id.
DefStruct(DefId),
DefLabel(ast::NodeId),
DefMethod(DefId),
|v| visit::walk_item(v, i), required);
if let hir::ItemStruct(ref sd, _) = i.node {
- sd.ctor_id.map(|id| {
- self.annotate(id, true, &i.attrs, i.span, |_| {}, true)
- });
+ if !sd.is_struct() {
+ self.annotate(sd.id(), true, &i.attrs, i.span, |_| {}, true)
+ }
}
}
|v| visit::walk_impl_item(v, ii), true);
}
- fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
- self.annotate(var.node.id, true, &var.node.attrs, var.span,
- |v| visit::walk_variant(v, var, g), true)
+ fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) {
+ self.annotate(var.node.data.id(), true, &var.node.attrs, var.span,
+ |v| visit::walk_variant(v, var, g, item_id), true)
}
fn visit_struct_field(&mut self, s: &StructField) {
pub enum AdtKind { Struct, Enum }
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum VariantKind { Dict, Tuple, Unit }
+pub enum VariantKind { Struct, Tuple, Unit }
impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
fn new(tcx: &ctxt<'tcx>,
Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => {
VariantKind::Tuple
}
- Some(_) => VariantKind::Dict
+ Some(_) => VariantKind::Struct
}
}
}
impl<'a, 'v> Visitor<'v> for StrictVersionHashVisitor<'a> {
- fn visit_struct_def(&mut self, s: &StructDef, name: Name,
- g: &Generics, _: NodeId) {
+ fn visit_variant_data(&mut self, s: &VariantData, name: Name,
+ g: &Generics, _: NodeId, _: Span) {
SawStructDef(name.as_str()).hash(self.st);
visit::walk_generics(self, g);
visit::walk_struct_def(self, s)
}
- fn visit_variant(&mut self, v: &Variant, g: &Generics) {
+ fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) {
SawVariant.hash(self.st);
// walk_variant does not call walk_generics, so do it here.
visit::walk_generics(self, g);
- visit::walk_variant(self, v, g)
+ visit::walk_variant(self, v, g, item_id)
}
// All of the remaining methods just record (in the hash
//! A typesafe bitmask flag generator.
-#[cfg(test)] #[macro_use] extern crate std;
+#[cfg(test)]
+#[macro_use]
+extern crate std;
/// The `bitflags!` macro generates a `struct` that holds a set of C-style
/// bitmask flags. It is useful for creating typesafe wrappers for C APIs.
}
#[test]
- fn test_bits(){
+ fn test_bits() {
assert_eq!(Flags::empty().bits(), 0b00000000);
assert_eq!(Flags::FlagA.bits(), 0b00000001);
assert_eq!(Flags::FlagABC.bits(), 0b00000111);
}
#[test]
- fn test_is_empty(){
+ fn test_is_empty() {
assert!(Flags::empty().is_empty());
assert!(!Flags::FlagA.is_empty());
assert!(!Flags::FlagABC.is_empty());
}
#[test]
- fn test_insert(){
+ fn test_insert() {
let mut e1 = Flags::FlagA;
let e2 = Flags::FlagA | Flags::FlagB;
e1.insert(e2);
}
#[test]
- fn test_remove(){
+ fn test_remove() {
let mut e1 = Flags::FlagA | Flags::FlagB;
let e2 = Flags::FlagA | Flags::FlagC;
e1.remove(e2);
#[test]
fn test_hash() {
- let mut x = Flags::empty();
- let mut y = Flags::empty();
- assert!(hash(&x) == hash(&y));
- x = Flags::all();
- y = Flags::FlagABC;
- assert!(hash(&x) == hash(&y));
+ let mut x = Flags::empty();
+ let mut y = Flags::empty();
+ assert!(hash(&x) == hash(&y));
+ x = Flags::all();
+ y = Flags::FlagABC;
+ assert!(hash(&x) == hash(&y));
}
fn hash<T: Hash>(t: &T) -> u64 {
noop_fold_poly_trait_ref(p, self)
}
- fn fold_struct_def(&mut self, struct_def: P<StructDef>) -> P<StructDef> {
+ fn fold_variant_data(&mut self, struct_def: P<VariantData>) -> P<VariantData> {
noop_fold_struct_def(struct_def, self)
}
noop_fold_opt_lifetime(o_lt, self)
}
- fn fold_variant_arg(&mut self, va: VariantArg) -> VariantArg {
- noop_fold_variant_arg(va, self)
- }
-
fn fold_opt_bounds(&mut self,
b: Option<OwnedSlice<TyParamBound>>)
-> Option<OwnedSlice<TyParamBound>> {
}
pub fn noop_fold_variant<T: Folder>(v: P<Variant>, fld: &mut T) -> P<Variant> {
- v.map(|Spanned { node: Variant_ { id, name, attrs, kind, disr_expr }, span }| {
- Spanned {
- node: Variant_ {
- id: fld.new_id(id),
- name: name,
- attrs: fold_attrs(attrs, fld),
- kind: match kind {
- TupleVariantKind(variant_args) => {
- TupleVariantKind(variant_args.move_map(|x| fld.fold_variant_arg(x)))
- }
- StructVariantKind(struct_def) => {
- StructVariantKind(fld.fold_struct_def(struct_def))
- }
- },
- disr_expr: disr_expr.map(|e| fld.fold_expr(e)),
- },
- span: fld.new_span(span),
- }
+ v.map(|Spanned {node: Variant_ {name, attrs, data, disr_expr}, span}| Spanned {
+ node: Variant_ {
+ name: name,
+ attrs: fold_attrs(attrs, fld),
+ data: fld.fold_variant_data(data),
+ disr_expr: disr_expr.map(|e| fld.fold_expr(e)),
+ },
+ span: fld.new_span(span),
})
}
}
}
-pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> {
- struct_def.map(|StructDef { fields, ctor_id }| {
- StructDef {
- fields: fields.move_map(|f| fld.fold_struct_field(f)),
- ctor_id: ctor_id.map(|cid| fld.new_id(cid)),
+pub fn noop_fold_struct_def<T: Folder>(struct_def: P<VariantData>, fld: &mut T) -> P<VariantData> {
+ struct_def.map(|vdata| {
+ match vdata {
+ VariantData::Struct(fields, id) => {
+ VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id))
+ }
+ VariantData::Tuple(fields, id) => {
+ VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id))
+ }
+ VariantData::Unit(id) => VariantData::Unit(fld.new_id(id))
}
})
}
bounds.move_map(|bound| folder.fold_ty_param_bound(bound))
}
-fn noop_fold_variant_arg<T: Folder>(VariantArg { id, ty }: VariantArg,
- folder: &mut T)
- -> VariantArg {
- VariantArg {
- id: folder.new_id(id),
- ty: folder.fold_ty(ty),
- }
-}
-
pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
b.map(|Block { id, stmts, expr, rules, span }| {
Block {
folder.fold_generics(generics))
}
ItemStruct(struct_def, generics) => {
- let struct_def = folder.fold_struct_def(struct_def);
+ let struct_def = folder.fold_variant_data(struct_def);
ItemStruct(struct_def, folder.fold_generics(generics))
}
ItemDefaultImpl(unsafety, ref trait_ref) => {
pub use self::TyParamBound::*;
pub use self::UnOp::*;
pub use self::UnsafeSource::*;
-pub use self::VariantKind::*;
pub use self::ViewPath_::*;
pub use self::Visibility::*;
pub use self::PathParameters::*;
use util;
use std::fmt;
+use std::{iter, option, slice};
use serialize::{Encodable, Encoder, Decoder};
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub items: Vec<P<ForeignItem>>,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct VariantArg {
- pub ty: P<Ty>,
- pub id: NodeId,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum VariantKind {
- /// Tuple variant, e.g. `Foo(A, B)`
- TupleVariantKind(Vec<VariantArg>),
- /// Struct variant, e.g. `Foo {x: A, y: B}`
- StructVariantKind(P<StructDef>),
-}
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct EnumDef {
pub variants: Vec<P<Variant>>,
pub struct Variant_ {
pub name: Name,
pub attrs: Vec<Attribute>,
- pub kind: VariantKind,
- pub id: NodeId,
+ pub data: P<VariantData>,
/// Explicit discriminant, eg `Foo = 1`
pub disr_expr: Option<P<Expr>>,
}
}
}
+/// Fields and Ids of enum variants and structs
+///
+/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all
+/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants).
+/// One shared Id can be successfully used for these two purposes.
+/// Id of the whole enum lives in `Item`.
+///
+/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually
+/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of
+/// the variant itself" from enum variants.
+/// Id of the whole struct lives in `Item`.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct StructDef {
- /// Fields, not including ctor
- pub fields: Vec<StructField>,
- /// ID of the constructor. This is only used for tuple- or enum-like
- /// structs.
- pub ctor_id: Option<NodeId>,
+pub enum VariantData {
+ Struct(Vec<StructField>, NodeId),
+ Tuple(Vec<StructField>, NodeId),
+ Unit(NodeId),
+}
+
+pub type FieldIter<'a> = iter::FlatMap<option::IntoIter<&'a Vec<StructField>>,
+ slice::Iter<'a, StructField>,
+ fn(&Vec<StructField>) -> slice::Iter<StructField>>;
+
+impl VariantData {
+ pub fn fields(&self) -> FieldIter {
+ fn vec_iter<T>(v: &Vec<T>) -> slice::Iter<T> { v.iter() }
+ match *self {
+ VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => Some(fields),
+ _ => None,
+ }.into_iter().flat_map(vec_iter)
+ }
+ pub fn id(&self) -> NodeId {
+ match *self {
+ VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id
+ }
+ }
+ pub fn is_struct(&self) -> bool {
+ if let VariantData::Struct(..) = *self { true } else { false }
+ }
+ pub fn is_tuple(&self) -> bool {
+ if let VariantData::Tuple(..) = *self { true } else { false }
+ }
+ pub fn is_unit(&self) -> bool {
+ if let VariantData::Unit(..) = *self { true } else { false }
+ }
}
/*
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
ItemEnum(EnumDef, Generics),
/// A struct definition, e.g. `struct Foo<A> {x: A}`
- ItemStruct(P<StructDef>, Generics),
+ ItemStruct(P<VariantData>, Generics),
/// Represents a Trait Declaration
ItemTrait(Unsafety, Generics, TyParamBounds, Vec<P<TraitItem>>),
pub fn lower_variant(_lctx: &LoweringContext, v: &Variant) -> P<hir::Variant> {
P(Spanned {
node: hir::Variant_ {
- id: v.node.id,
name: v.node.name.name,
attrs: v.node.attrs.clone(),
- kind: match v.node.kind {
- TupleVariantKind(ref variant_args) => {
- hir::TupleVariantKind(variant_args.iter()
- .map(|ref x| lower_variant_arg(_lctx, x))
- .collect())
- }
- StructVariantKind(ref struct_def) => {
- hir::StructVariantKind(lower_struct_def(_lctx, struct_def))
- }
- },
+ data: lower_struct_def(_lctx, &v.node.data),
disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(_lctx, e)),
},
span: v.span,
}
}
-pub fn lower_struct_def(_lctx: &LoweringContext, sd: &StructDef) -> P<hir::StructDef> {
- P(hir::StructDef {
- fields: sd.fields.iter().map(|f| lower_struct_field(_lctx, f)).collect(),
- ctor_id: sd.ctor_id,
+pub fn lower_struct_def(_lctx: &LoweringContext, sd: &VariantData) -> P<hir::VariantData> {
+ P(match *sd {
+ VariantData::Struct(ref fields, id) => {
+ hir::VariantData::Struct(fields.iter()
+ .map(|f| lower_struct_field(_lctx, f)).collect(), id)
+ }
+ VariantData::Tuple(ref fields, id) => {
+ hir::VariantData::Tuple(fields.iter()
+ .map(|f| lower_struct_field(_lctx, f)).collect(), id)
+ }
+ VariantData::Unit(id) => hir::VariantData::Unit(id)
})
}
bounds.iter().map(|bound| lower_ty_param_bound(_lctx, bound)).collect()
}
-fn lower_variant_arg(_lctx: &LoweringContext, va: &VariantArg) -> hir::VariantArg {
- hir::VariantArg {
- id: va.id,
- ty: lower_ty(_lctx, &va.ty),
- }
-}
-
pub fn lower_block(_lctx: &LoweringContext, b: &Block) -> P<hir::Block> {
P(hir::Block {
id: b.id,
vec![head])
};
- let match_expr = expr_match(lctx, e.span, into_iter_expr, vec![iter_arm]);
+ let match_expr = expr_match(lctx,
+ e.span,
+ into_iter_expr,
+ vec![iter_arm],
+ hir::MatchSource::ForLoopDesugar);
// `{ let result = ...; result }`
let result_ident = lctx.str_to_ident("result");
match *b {
DefaultBlock => hir::DefaultBlock,
UnsafeBlock(u) => hir::UnsafeBlock(lower_unsafe_source(_lctx, u)),
- PushUnsafeBlock(u) => hir::PushUnsafeBlock(lower_unsafe_source(_lctx, u)),
- PopUnsafeBlock(u) => hir::PopUnsafeBlock(lower_unsafe_source(_lctx, u)),
}
}
fn expr_match(lctx: &LoweringContext,
span: Span,
arg: P<hir::Expr>,
- arms: Vec<hir::Arm>)
+ arms: Vec<hir::Arm>,
+ source: hir::MatchSource)
-> P<hir::Expr> {
expr(lctx,
span,
- hir::ExprMatch(arg, arms, hir::MatchSource::Normal))
+ hir::ExprMatch(arg, arms, source))
}
fn expr_block(lctx: &LoweringContext, b: P<hir::Block>) -> P<hir::Expr> {
}
hir::ItemStruct(ref struct_def, ref generics) => {
try!(self.head(&visibility_qualified(item.vis, "struct")));
- try!(self.print_struct(&**struct_def, generics, item.name, item.span));
+ try!(self.print_struct(&**struct_def, generics, item.name, item.span, true));
}
hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
}
pub fn print_struct(&mut self,
- struct_def: &hir::StructDef,
+ struct_def: &hir::VariantData,
generics: &hir::Generics,
name: ast::Name,
- span: codemap::Span)
+ span: codemap::Span,
+ print_finalizer: bool)
-> io::Result<()> {
try!(self.print_name(name));
try!(self.print_generics(generics));
- if ::util::struct_def_is_tuple_like(struct_def) {
- if !struct_def.fields.is_empty() {
+ if !struct_def.is_struct() {
+ if struct_def.is_tuple() {
try!(self.popen());
- try!(self.commasep(Inconsistent,
- &struct_def.fields,
+ try!(self.commasep_iter(Inconsistent,
+ struct_def.fields(),
|s, field| {
match field.node.kind {
hir::NamedField(..) => panic!("unexpected named field"),
try!(self.pclose());
}
try!(self.print_where_clause(&generics.where_clause));
- try!(word(&mut self.s, ";"));
+ if print_finalizer {
+ try!(word(&mut self.s, ";"));
+ }
try!(self.end());
self.end() // close the outer-box
} else {
try!(self.bopen());
try!(self.hardbreak_if_not_bol());
- for field in &struct_def.fields {
+ for field in struct_def.fields() {
match field.node.kind {
hir::UnnamedField(..) => panic!("unexpected unnamed field"),
hir::NamedField(name, visibility) => {
}
pub fn print_variant(&mut self, v: &hir::Variant) -> io::Result<()> {
- match v.node.kind {
- hir::TupleVariantKind(ref args) => {
- try!(self.print_name(v.node.name));
- if !args.is_empty() {
- try!(self.popen());
- try!(self.commasep(Consistent, &args[..], |s, arg| s.print_type(&*arg.ty)));
- try!(self.pclose());
- }
- }
- hir::StructVariantKind(ref struct_def) => {
- try!(self.head(""));
- let generics = ::util::empty_generics();
- try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span));
- }
- }
+ try!(self.head(""));
+ let generics = ::util::empty_generics();
+ try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false));
match v.node.disr_expr {
Some(ref d) => {
try!(space(&mut self.s));
}
}
-/// Returns true if the given struct def is tuple-like; i.e. that its fields
-/// are unnamed.
-pub fn struct_def_is_tuple_like(struct_def: &hir::StructDef) -> bool {
- struct_def.ctor_id.is_some()
-}
-
pub fn stmt_id(s: &Stmt) -> NodeId {
match s.node {
StmtDecl(_, id) => id,
}
}
}
- ItemEnum(ref enum_definition, _) => {
- for variant in &enum_definition.variants {
- self.operation.visit_id(variant.node.id)
- }
- }
_ => {}
}
visit::walk_struct_field(self, struct_field)
}
- fn visit_struct_def(&mut self,
- struct_def: &StructDef,
+ fn visit_variant_data(&mut self,
+ struct_def: &VariantData,
_: Name,
_: &hir::Generics,
- id: NodeId) {
- self.operation.visit_id(id);
- struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id));
+ _: NodeId,
+ _: Span) {
+ self.operation.visit_id(struct_def.id());
visit::walk_struct_def(self, struct_def);
}
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
walk_poly_trait_ref(self, t, m)
}
- fn visit_struct_def(&mut self, s: &'v StructDef, _: Name, _: &'v Generics, _: NodeId) {
+ fn visit_variant_data(&mut self, s: &'v VariantData, _: Name,
+ _: &'v Generics, _: NodeId, _: Span) {
walk_struct_def(self, s)
}
fn visit_struct_field(&mut self, s: &'v StructField) {
walk_struct_field(self, s)
}
- fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, generics: &'v Generics) {
- walk_enum_def(self, enum_definition, generics)
+ fn visit_enum_def(&mut self, enum_definition: &'v EnumDef,
+ generics: &'v Generics, item_id: NodeId) {
+ walk_enum_def(self, enum_definition, generics, item_id)
}
-
- fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) {
- walk_variant(self, v, g)
+ fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) {
+ walk_variant(self, v, g, item_id)
}
-
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
walk_lifetime(self, lifetime)
}
}
ItemEnum(ref enum_definition, ref type_parameters) => {
visitor.visit_generics(type_parameters);
- visitor.visit_enum_def(enum_definition, type_parameters)
+ visitor.visit_enum_def(enum_definition, type_parameters, item.id)
}
ItemDefaultImpl(_, ref trait_ref) => {
visitor.visit_trait_ref(trait_ref)
}
ItemStruct(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
- visitor.visit_struct_def(struct_definition, item.name, generics, item.id)
+ visitor.visit_variant_data(struct_definition, item.name,
+ generics, item.id, item.span);
}
ItemTrait(_, ref generics, ref bounds, ref methods) => {
visitor.visit_generics(generics);
pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
enum_definition: &'v EnumDef,
- generics: &'v Generics) {
+ generics: &'v Generics,
+ item_id: NodeId) {
for variant in &enum_definition.variants {
- visitor.visit_variant(variant, generics);
+ visitor.visit_variant(variant, generics, item_id);
}
}
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
variant: &'v Variant,
- generics: &'v Generics) {
+ generics: &'v Generics,
+ item_id: NodeId) {
visitor.visit_name(variant.span, variant.node.name);
-
- match variant.node.kind {
- TupleVariantKind(ref variant_arguments) => {
- for variant_argument in variant_arguments {
- visitor.visit_ty(&variant_argument.ty)
- }
- }
- StructVariantKind(ref struct_definition) => {
- visitor.visit_struct_def(struct_definition,
- variant.node.name,
- generics,
- variant.node.id)
- }
- }
+ visitor.visit_variant_data(&variant.node.data, variant.node.name,
+ generics, item_id, variant.span);
walk_list!(visitor, visit_expr, &variant.node.disr_expr);
walk_list!(visitor, visit_attribute, &variant.node.attrs);
}
}
}
-pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v StructDef) {
- walk_list!(visitor, visit_struct_field, &struct_definition.fields);
+pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
+ walk_list!(visitor, visit_struct_field, struct_definition.fields());
}
pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) {
}
}
- fn check_struct_def(&mut self, cx: &LateContext, s: &hir::StructDef,
+ fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData,
_: ast::Name, _: &hir::Generics, _: ast::NodeId) {
- for sf in &s.fields {
+ for sf in s.fields() {
if let hir::StructField_ { kind: hir::NamedField(name, _), .. } = sf.node {
self.check_snake_case(cx, "structure field", &name.as_str(),
Some(sf.span));
// If it's a struct, we also have to check the fields' types
match it.node {
hir::ItemStruct(ref struct_def, _) => {
- for struct_field in &struct_def.fields {
+ for struct_field in struct_def.fields() {
self.check_heap_type(cx, struct_field.span,
cx.tcx.node_id_to_type(struct_field.node.id));
}
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
}
- fn check_struct_def(&mut self, _: &LateContext, _: &hir::StructDef,
- _: ast::Name, _: &hir::Generics, id: ast::NodeId) {
- self.struct_def_stack.push(id);
+ fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData,
+ _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
+ self.struct_def_stack.push(item_id);
}
- fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::StructDef,
- _: ast::Name, _: &hir::Generics, id: ast::NodeId) {
+ fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData,
+ _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
let popped = self.struct_def_stack.pop().expect("empty struct_def_stack");
- assert!(popped == id);
+ assert!(popped == item_id);
}
fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) {
}
fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
- self.check_missing_docs_attrs(cx, Some(v.node.id), &v.node.attrs, v.span, "a variant");
+ self.check_missing_docs_attrs(cx, Some(v.node.data.id()),
+ &v.node.attrs, v.span, "a variant");
assert!(!self.in_variant);
self.in_variant = true;
}
// The parent is considered the enclosing enum because the
// enum will dictate the privacy visibility of this variant
// instead.
- self.parents.insert(variant.node.id, item.id);
+ self.parents.insert(variant.node.data.id(), item.id);
}
}
visit::walk_impl_item(self, ii);
}
- fn visit_struct_def(&mut self, s: &hir::StructDef, _: ast::Name,
- _: &'v hir::Generics, n: ast::NodeId) {
+ fn visit_variant_data(&mut self, s: &hir::VariantData, _: ast::Name,
+ _: &'v hir::Generics, item_id: ast::NodeId, _: Span) {
// Struct constructors are parented to their struct definitions because
// they essentially are the struct definitions.
- match s.ctor_id {
- Some(id) => { self.parents.insert(id, n); }
- None => {}
+ if !s.is_struct() {
+ self.parents.insert(s.id(), item_id);
}
// While we have the id of the struct definition, go ahead and parent
// all the fields.
- for field in &s.fields {
+ for field in s.fields() {
self.parents.insert(field.node.id, self.curparent);
}
visit::walk_struct_def(self, s)
// public all variants are public unless they're explicitly priv
hir::ItemEnum(ref def, _) if public_first => {
for variant in &def.variants {
- self.exported_items.insert(variant.node.id);
- self.public_items.insert(variant.node.id);
+ self.exported_items.insert(variant.node.data.id());
+ self.public_items.insert(variant.node.data.id());
}
}
// Struct constructors are public if the struct is all public.
hir::ItemStruct(ref def, _) if public_first => {
- match def.ctor_id {
- Some(id) => { self.exported_items.insert(id); }
- None => {}
+ if !def.is_struct() {
+ self.exported_items.insert(def.id());
}
// fields can be public or private, so lets check
- for field in &def.fields {
+ for field in def.fields() {
let vis = match field.node.kind {
hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis
};
"visibility has no effect inside functions");
}
}
- let check_struct = |def: &hir::StructDef| {
- for f in &def.fields {
+ let check_struct = |def: &hir::VariantData| {
+ for f in def.fields() {
match f.node.kind {
hir::NamedField(_, p) => check_inherited(tcx, f.span, p),
hir::UnnamedField(..) => {}
visit::walk_ty(self, t)
}
- fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) {
- if self.exported_items.contains(&v.node.id) {
+ fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
+ if self.exported_items.contains(&v.node.data.id()) {
self.in_variant = true;
- visit::walk_variant(self, v, g);
+ visit::walk_variant(self, v, g, item_id);
self.in_variant = false;
}
}
fn visit_struct_field(&mut self, s: &hir::StructField) {
- match s.node.kind {
- hir::NamedField(_, vis) if vis == hir::Public || self.in_variant => {
- visit::walk_struct_field(self, s);
- }
- _ => {}
+ let vis = match s.node.kind {
+ hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis
+ };
+ if vis == hir::Public || self.in_variant {
+ visit::walk_struct_field(self, s);
}
}
use rustc_front::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse};
use rustc_front::hir::{NamedField, PathListIdent, PathListMod, Public};
use rustc_front::hir::StmtDecl;
-use rustc_front::hir::StructVariantKind;
-use rustc_front::hir::TupleVariantKind;
use rustc_front::hir::UnnamedField;
use rustc_front::hir::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use rustc_front::hir::Visibility;
// These items live in both the type and value namespaces.
ItemStruct(ref struct_def, _) => {
// Adding to both Type and Value namespaces or just Type?
- let (forbid, ctor_id) = match struct_def.ctor_id {
- Some(ctor_id) => (ForbidDuplicateTypesAndValues, Some(ctor_id)),
- None => (ForbidDuplicateTypesAndModules, None)
+ let (forbid, ctor_id) = if struct_def.is_struct() {
+ (ForbidDuplicateTypesAndModules, None)
+ } else {
+ (ForbidDuplicateTypesAndValues, Some(struct_def.id()))
};
let name_bindings = self.add_child(name, parent, forbid, sp);
}
// Record the def ID and fields of this struct.
- let named_fields = struct_def.fields.iter().filter_map(|f| {
+ let named_fields = struct_def.fields().filter_map(|f| {
match f.node.kind {
NamedField(name, _) => Some(name),
UnnamedField(_) => None
item_id: DefId,
parent: &Rc<Module>) {
let name = variant.node.name;
- let is_exported = match variant.node.kind {
- TupleVariantKind(_) => false,
- StructVariantKind(_) => {
- // Not adding fields for variants as they are not accessed with a self receiver
- let variant_def_id = self.ast_map.local_def_id(variant.node.id);
- self.structs.insert(variant_def_id, Vec::new());
- true
- }
+ let is_exported = if variant.node.data.is_struct() {
+ // Not adding fields for variants as they are not accessed with a self receiver
+ let variant_def_id = self.ast_map.local_def_id(variant.node.data.id());
+ self.structs.insert(variant_def_id, Vec::new());
+ true
+ } else {
+ false
};
let child = self.add_child(name, parent,
// variants are always treated as importable to allow them to be glob
// used
child.define_value(DefVariant(item_id,
- self.ast_map.local_def_id(variant.node.id), is_exported),
+ self.ast_map.local_def_id(variant.node.data.id()),
+ is_exported),
variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
child.define_type(DefVariant(item_id,
- self.ast_map.local_def_id(variant.node.id), is_exported),
+ self.ast_map.local_def_id(variant.node.data.id()),
+ is_exported),
variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
}
}
visit::walk_poly_trait_ref(self, tref, m);
}
- fn visit_variant(&mut self, variant: &hir::Variant, generics: &Generics) {
+ fn visit_variant(&mut self, variant: &hir::Variant, generics: &Generics, item_id: ast::NodeId) {
execute_callback!(hir_map::Node::NodeVariant(variant), self);
if let Some(ref dis_expr) = variant.node.disr_expr {
// resolve the discriminator expr as a constant
}
// `visit::walk_variant` without the discriminant expression.
- match variant.node.kind {
- hir::TupleVariantKind(ref variant_arguments) => {
- for variant_argument in variant_arguments {
- self.visit_ty(&*variant_argument.ty);
- }
- }
- hir::StructVariantKind(ref struct_definition) => {
- self.visit_struct_def(&**struct_definition,
- variant.node.name,
- generics,
- variant.node.id);
- }
- }
+ self.visit_variant_data(&variant.node.data, variant.node.name,
+ generics, item_id, variant.span);
}
fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem) {
execute_callback!(hir_map::Node::NodeForeignItem(foreign_item), self);
register_long_diagnostics! {
+E0510: r##"
+`return_address` was used in an invalid context. Erroneous code example:
+
+```
+extern "rust-intrinsic" {
+ fn return_address() -> *const u8;
+}
+
+pub unsafe fn by_value() -> i32 {
+ let _ = return_address();
+ // error: invalid use of `return_address` intrinsic: function does
+ // not use out pointer
+ 0
+}
+```
+
+Return values may be stored in a return register(s) or written into a so-called
+out pointer. In case the returned value is too big (this is
+target-ABI-dependent and generally not portable or future proof) to fit into
+the return register(s), the compiler will return the value by writing it into
+space allocated in the caller's stack frame. Example:
+
+```
+extern "rust-intrinsic" {
+ fn return_address() -> *const u8;
+}
+
+pub unsafe fn by_pointer() -> String {
+ let _ = return_address();
+ String::new() // ok!
+}
+```
+"##,
+
+E0511: r##"
+Invalid monomorphization of an intrinsic function was used. Erroneous code
+example:
+
+```
+extern "platform-intrinsic" {
+ fn simd_add<T>(a: T, b: T) -> T;
+}
+
+unsafe { simd_add(0, 1); }
+// error: invalid monomorphization of `simd_add` intrinsic
+```
+
+The generic type has to be a SIMD type. Example:
+
+```
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct i32x1(i32);
+
+extern "platform-intrinsic" {
+ fn simd_add<T>(a: T, b: T) -> T;
+}
+
+unsafe { simd_add(i32x1(0), i32x1(1)); } // ok!
+```
+"##,
+
+E0512: r##"
+Transmute with two differently sized types was attempted. Erroneous code
+example:
+
+```
+extern "rust-intrinsic" {
+ pub fn ctpop8(x: u8) -> u8;
+}
+
+fn main() {
+ unsafe { ctpop8(::std::mem::transmute(0u16)); }
+ // error: transmute called with differently sized types
+}
+```
+
+Please use types with same size or use the expected type directly. Example:
+
+```
+extern "rust-intrinsic" {
+ pub fn ctpop8(x: u8) -> u8;
+}
+
+fn main() {
+ unsafe { ctpop8(::std::mem::transmute(0i8)); } // ok!
+ // or:
+ unsafe { ctpop8(0u8); } // ok!
+}
+```
+"##,
+
E0515: r##"
A constant index expression was out of bounds. Erroneous code example:
Example:
```
-let x = &[0, 1, 2][2]; // ok!
+let x = &[0, 1, 2][2]; // ok
```
"##,
}
-
-register_diagnostics! {
- E0510, // invalid use of `return_address` intrinsic: function does not use out pointer
- E0511, // invalid monomorphization of `{}` intrinsic
- E0512, // transmute called on types with potentially different sizes...
-}
analysis: &'l ty::CrateAnalysis,
span: SpanUtils<'l>,
- fmt: FmtStrs<'l>,
+ fmt: FmtStrs<'l, 'tcx>,
cur_scope: NodeId,
}
out: output_file,
dump_spans: false,
},
- span_utils),
+ span_utils,
+ tcx),
cur_scope: 0,
}
}
fn process_struct(&mut self,
item: &ast::Item,
- def: &ast::StructDef,
+ def: &ast::VariantData,
ty_params: &ast::Generics) {
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
- let ctor_id = match def.ctor_id {
- Some(node_id) => node_id,
- None => ast::DUMMY_NODE_ID,
- };
let val = self.span.snippet(item.span);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
self.fmt.struct_str(item.span,
sub_span,
item.id,
- ctor_id,
+ def.id(),
&qualname,
self.cur_scope,
&val);
// fields
- for field in &def.fields {
+ for field in def.fields() {
self.process_struct_field_def(field, item.id);
self.visit_ty(&field.node.ty);
}
qualname.push_str("::");
qualname.push_str(name);
let val = self.span.snippet(variant.span);
- match variant.node.kind {
- ast::TupleVariantKind(ref args) => {
- // first ident in span is the variant's name
- self.fmt.tuple_variant_str(variant.span,
- self.span.span_for_first_ident(variant.span),
- variant.node.id,
- name,
- &qualname,
- &enum_data.qualname,
- &val,
- enum_data.id);
- for arg in args {
- self.visit_ty(&*arg.ty);
- }
- }
- ast::StructVariantKind(ref struct_def) => {
- let ctor_id = match struct_def.ctor_id {
- Some(node_id) => node_id,
- None => ast::DUMMY_NODE_ID,
- };
- self.fmt.struct_variant_str(variant.span,
- self.span.span_for_first_ident(variant.span),
- variant.node.id,
- ctor_id,
- &qualname,
- &enum_data.qualname,
- &val,
- enum_data.id);
-
- for field in &struct_def.fields {
- self.process_struct_field_def(field, variant.node.id);
- self.visit_ty(&*field.node.ty);
- }
- }
+
+ self.fmt.struct_variant_str(variant.span,
+ self.span.span_for_first_ident(variant.span),
+ variant.node.data.id(),
+ variant.node.data.id(),
+ &qualname,
+ &enum_data.qualname,
+ &val,
+ enum_data.id);
+
+ for field in variant.node.data.fields() {
+ self.process_struct_field_def(field, variant.node.data.id());
+ self.visit_ty(&*field.node.ty);
}
}
self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);
use metadata::cstore::LOCAL_CRATE;
use middle::def_id::{CRATE_DEF_INDEX, DefId};
+use middle::ty;
use std::io::Write;
}
}
-pub struct FmtStrs<'a> {
+pub struct FmtStrs<'a, 'tcx: 'a> {
pub recorder: Box<Recorder>,
span: SpanUtils<'a>,
+ tcx: &'a ty::ctxt<'tcx>,
}
macro_rules! s { ($e:expr) => { format!("{}", $e) }}
FnRef,
}
-impl<'a> FmtStrs<'a> {
- pub fn new(rec: Box<Recorder>, span: SpanUtils<'a>) -> FmtStrs<'a> {
+impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
+ pub fn new(rec: Box<Recorder>,
+ span: SpanUtils<'a>,
+ tcx: &'a ty::ctxt<'tcx>)
+ -> FmtStrs<'a, 'tcx> {
FmtStrs {
recorder: rec,
span: span,
+ tcx: tcx,
+ }
+ }
+
+ // Emitted ids are used to cross-reference items across crates. DefIds and
+ // NodeIds do not usually correspond in any way. The strategy is to use the
+ // index from the DefId as a crate-local id. However, within a crate, DefId
+ // indices and NodeIds can overlap. So, we must adjust the NodeIds. If an
+ // item can be identified by a DefId as well as a NodeId, then we use the
+ // DefId index as the id. If it can't, then we have to use the NodeId, but
+ // need to adjust it so it will not clash with any possible DefId index.
+ fn normalize_node_id(&self, id: NodeId) -> usize {
+ match self.tcx.map.opt_local_def_id(id) {
+ Some(id) => id.index.as_usize(),
+ None => id as usize + self.tcx.map.num_local_def_ids()
}
}
let mut qualname = String::from(name);
qualname.push_str("$");
qualname.push_str(&id.to_string());
+ let id = self.normalize_node_id(id);
self.check_and_record(Variable,
span,
sub_span,
let mut qualname = String::from(fn_name);
qualname.push_str("::");
qualname.push_str(name);
+ let id = self.normalize_node_id(id);
self.check_and_record(Variable,
span,
sub_span,
value: &str,
typ: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Variable,
span,
sub_span,
qualname: &str,
typ: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Variable,
span,
sub_span,
name: &str,
scope_id: NodeId,
value: &str) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Enum, span, sub_span, svec!(id, name, scope_id, value));
}
typ: &str,
val: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Variant,
span,
sub_span,
typ: &str,
val: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
+ let ctor_id = self.normalize_node_id(ctor_id);
self.check_and_record(VariantStruct,
span,
sub_span,
id: NodeId,
name: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Function,
span,
sub_span,
name: &str,
decl_id: Option<DefId>,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
let values = match decl_id {
Some(decl_id) => svec!(id,
name,
id: NodeId,
name: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(MethodDecl, span, sub_span, svec!(id, name, scope_id));
}
name: &str,
scope_id: NodeId,
value: &str) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
+ let ctor_id = self.normalize_node_id(ctor_id);
self.check_and_record(Struct,
span,
sub_span,
name: &str,
scope_id: NodeId,
value: &str) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Trait, span, sub_span, svec!(id, name, scope_id, value));
}
ref_id: Option<DefId>,
trait_id: Option<DefId>,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
let ref_id = ref_id.unwrap_or(CRATE_ROOT_DEF_ID);
let trait_id = trait_id.unwrap_or(CRATE_ROOT_DEF_ID);
self.check_and_record(Impl,
name: &str,
parent: NodeId,
filename: &str) {
+ let id = self.normalize_node_id(id);
+ let parent = self.normalize_node_id(parent);
self.check_and_record(Module,
span,
sub_span,
mod_id: Option<DefId>,
name: &str,
parent: NodeId) {
+ let id = self.normalize_node_id(id);
+ let parent = self.normalize_node_id(parent);
let mod_id = mod_id.unwrap_or(CRATE_ROOT_DEF_ID);
self.check_and_record(UseAlias,
span,
id: NodeId,
values: &str,
parent: NodeId) {
+ let id = self.normalize_node_id(id);
+ let parent = self.normalize_node_id(parent);
self.check_and_record(UseGlob, span, sub_span, svec!(id, values, parent));
}
name: &str,
loc: &str,
parent: NodeId) {
+ let id = self.normalize_node_id(id);
+ let parent = self.normalize_node_id(parent);
self.check_and_record(ExternCrate,
span,
sub_span,
sub_span: Option<Span>,
base_id: DefId,
deriv_id: NodeId) {
+ let deriv_id = self.normalize_node_id(deriv_id);
self.check_and_record(Inheritance,
span,
sub_span,
sub_span: Option<Span>,
id: DefId,
scope_id: NodeId) {
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(FnCall,
span,
sub_span,
defid: Option<DefId>,
declid: Option<DefId>,
scope_id: NodeId) {
+ let scope_id = self.normalize_node_id(scope_id);
let defid = defid.unwrap_or(CRATE_ROOT_DEF_ID);
let (dcn, dck) = match declid {
Some(declid) => (s!(declid.index.as_usize()), s!(declid.krate)),
}
pub fn sub_mod_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str, parent: NodeId) {
+ let parent = self.normalize_node_id(parent);
self.record_with_span(ModRef, span, sub_span, svec!(0, 0, qualname, parent));
}
id: NodeId,
qualname: &str,
value: &str) {
+ let id = self.normalize_node_id(id);
self.check_and_record(Typedef, span, sub_span, svec!(id, qualname, value));
}
sub_span: Option<Span>,
id: DefId,
scope_id: NodeId) {
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(kind,
span,
sub_span,
hir_map::NodeVariant(ref v) => {
let llfn;
- let args = match v.node.kind {
- hir::TupleVariantKind(ref args) => args,
- hir::StructVariantKind(_) => {
- ccx.sess().bug("struct variant kind unexpected in get_item_val")
- }
+ let fields = if v.node.data.is_struct() {
+ ccx.sess().bug("struct variant kind unexpected in get_item_val")
+ } else {
+ v.node.data.fields()
};
- assert!(!args.is_empty());
+ assert!(fields.count() != 0);
let ty = ccx.tcx().node_id_to_type(id);
let parent = ccx.tcx().map.get_parent(id);
let enm = ccx.tcx().map.expect_item(parent);
hir_map::NodeStructCtor(struct_def) => {
// Only register the constructor if this is a tuple-like struct.
- let ctor_id = match struct_def.ctor_id {
- None => {
- ccx.sess().bug("attempt to register a constructor of \
- a non-tuple-like struct")
- }
- Some(ctor_id) => ctor_id,
+ let ctor_id = if struct_def.is_struct() {
+ ccx.sess().bug("attempt to register a constructor of \
+ a non-tuple-like struct")
+ } else {
+ struct_def.id()
};
let parent = ccx.tcx().map.get_parent(id);
let struct_item = ccx.tcx().map.expect_item(parent);
}
}
- let mut arg_tys = Vec::new();
- for t in atys {
- let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), Attribute::ByVal);
- arg_tys.push(ty);
- }
+ let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
+ let mut sse_regs = 8;
let ret_ty = if ret_def {
- x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), Attribute::StructRet)
+ x86_64_ty(ccx, rty, |cls| {
+ if cls.is_ret_bysret() {
+ // `sret` parameter thus one less register available
+ int_regs -= 1;
+ true
+ } else {
+ false
+ }
+ }, Attribute::StructRet)
} else {
ArgType::direct(Type::void(ccx), None, None, None)
};
+ let mut arg_tys = Vec::new();
+ for t in atys {
+ let ty = x86_64_ty(ccx, *t, |cls| {
+ let needed_int = cls.iter().filter(|&&c| c == Int).count();
+ let needed_sse = cls.iter().filter(|c| c.is_sse()).count();
+ let in_mem = cls.is_pass_byval() ||
+ int_regs < needed_int ||
+ sse_regs < needed_sse;
+ if in_mem {
+ // `byval` parameter thus one less integer register available
+ int_regs -= 1;
+ } else {
+ // split into sized chunks passed individually
+ int_regs -= needed_int;
+ sse_regs -= needed_sse;
+ }
+ in_mem
+ }, Attribute::ByVal);
+ arg_tys.push(ty);
+
+ // An integer, pointer, double or float parameter
+ // thus the above closure passed to `x86_64_ty` won't
+ // get called.
+ if t.kind() == Integer || t.kind() == Pointer {
+ int_regs -= 1;
+ } else if t.kind() == Double || t.kind() == Float {
+ sse_regs -= 1;
+ }
+ }
+
return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
2 => ArgType::direct(t, Some(Type::i16(ccx)), None, None),
4 => ArgType::direct(t, Some(Type::i32(ccx)), None, None),
8 => ArgType::direct(t, Some(Type::i64(ccx)), None, None),
- _ => ArgType::indirect(t, Some(Attribute::ByVal))
+ _ => ArgType::indirect(t, None)
}
}
_ => {
|| "local item should be in ast map".to_string());
match map_node {
- hir_map::NodeVariant(v) => match v.node.kind {
- hir::TupleVariantKind(ref args) => !args.is_empty(),
- _ => false
- },
+ hir_map::NodeVariant(v) => {
+ v.node.data.is_tuple()
+ }
hir_map::NodeStructCtor(_) => true,
_ => false
}
ty::VariantKind::Tuple => {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
}
- ty::VariantKind::Dict => {
+ ty::VariantKind::Struct => {
cx.sess().span_bug(e.span, "path-expr refers to a dict variant!")
}
}
let sole_struct_member_description = MemberDescription {
name: match non_null_variant.kind() {
ty::VariantKind::Tuple => "__0".to_string(),
- ty::VariantKind::Dict => {
+ ty::VariantKind::Struct => {
non_null_variant.fields[0].name.to_string()
}
ty::VariantKind::Unit => unreachable!()
.map(|(i, _)| format!("__{}", i))
.collect()
}
- ty::VariantKind::Dict => {
+ ty::VariantKind::Struct => {
variant.fields
.iter()
.map(|f| f.name.to_string())
use trans::type_::Type;
use trans::type_of::*;
use trans::type_of;
+use middle::infer;
use middle::ty::{self, Ty};
use middle::subst::Substs;
_ => ccx.sess().bug("trans_native_call called on non-function type")
};
let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
+ let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
let llsig = foreign_signature(ccx, &fn_sig, &passed_arg_tys[..]);
let fn_type = cabi::compute_abi_info(ccx,
&llsig.llarg_tys,
-> ValueRef {
let _icx = push_ctxt("foreign::register_foreign_fn");
- let tys = foreign_types_for_id(ccx, node_id);
- let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let t = ccx.tcx().node_id_to_type(node_id);
let cconv = match t.sty {
ty::TyBareFn(_, ref fn_ty) => {
}
_ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
};
+ let tys = foreign_types_for_fn_ty(ccx, t);
+ let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
add_argument_attributes(&tys, llfn);
debug!("register_rust_fn_with_foreign_abi(node_id={}, llfn_ty={}, llfn={})",
}
}
-fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- id: ast::NodeId) -> ForeignTypes<'tcx> {
- foreign_types_for_fn_ty(ccx, ccx.tcx().node_id_to_type(id))
-}
-
fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
let fn_sig = match ty.sty {
_ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
};
let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
+ let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
let llsig = foreign_signature(ccx, &fn_sig, &fn_sig.inputs);
let fn_ty = cabi::compute_abi_info(ccx,
&llsig.llarg_tys,
let ty_vs = &ccx.tcx().lookup_adt_def(parent_id).variants;
assert_eq!(ast_vs.len(), ty_vs.len());
for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) {
- if ty_v.did == fn_id { my_id = ast_v.node.id; }
- ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.id));
+ if ty_v.did == fn_id { my_id = ast_v.node.data.id(); }
+ ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id()));
}
}
hir::ItemStruct(ref struct_def, _) => {
- match struct_def.ctor_id {
- None => ccx.sess().bug("instantiate_inline: called on a \
- non-tuple struct"),
- Some(ctor_id) => {
- ccx.external().borrow_mut().insert(fn_id, Some(ctor_id));
- my_id = ctor_id;
- }
+ if struct_def.is_struct() {
+ ccx.sess().bug("instantiate_inline: called on a \
+ non-tuple struct")
+ } else {
+ ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id()));
+ my_id = struct_def.id();
}
}
_ => ccx.sess().bug("instantiate_inline: item has a \
hir_map::NodeStructCtor(struct_def) => {
let d = mk_lldecl(abi::Rust);
attributes::inline(d, attributes::InlineAttr::Hint);
+ if struct_def.is_struct() {
+ panic!("ast-mapped struct didn't have a ctor id")
+ }
base::trans_tuple_struct(ccx,
- struct_def.ctor_id.expect("ast-mapped tuple struct \
- didn't have a ctor id"),
+ struct_def.id(),
psubsts,
d);
d
let tcx = pcx.fcx.ccx.tcx;
let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
- let variant = match fcx.def_struct_variant(def) {
+ let variant = match fcx.def_struct_variant(def, path.span) {
Some((_, variant)) => variant,
None => {
let name = pprust::path_to_string(path);
/// Return the dict-like variant corresponding to a given `Def`.
pub fn def_struct_variant(&self,
- def: def::Def)
+ def: def::Def,
+ span: Span)
-> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
{
let (adt, variant) = match def {
};
let var_kind = variant.kind();
- if var_kind == ty::VariantKind::Dict || var_kind == ty::VariantKind::Unit {
+ if var_kind == ty::VariantKind::Struct {
Some((adt, variant))
- } else {
- None
- }
+ } else if var_kind == ty::VariantKind::Unit {
+ if !self.tcx().sess.features.borrow().braced_empty_structs {
+ self.tcx().sess.span_err(span, "empty structs and enum variants \
+ with braces are unstable");
+ fileline_help!(self.tcx().sess, span, "add #![feature(braced_empty_structs)] to \
+ the crate features to enable");
+ }
+
+ Some((adt, variant))
+ } else {
+ None
+ }
}
pub fn write_nil(&self, node_id: ast::NodeId) {
// Find the relevant variant
let def = lookup_full_def(tcx, path.span, expr.id);
- let (adt, variant) = match fcx.def_struct_variant(def) {
+ let (adt, variant) = match fcx.def_struct_variant(def, path.span) {
Some((adt, variant)) => (adt, variant),
None => {
span_err!(fcx.tcx().sess, path.span, E0071,
};
substs_wf_in_scope(rcx, origin, &callee.substs, expr.span, expr_region);
+ type_must_outlive(rcx, infer::ExprTypeIsNotInScope(callee.ty, expr.span),
+ callee.ty, expr_region);
}
// Check any autoderefs or autorefs that appear.
}
}
+ debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs",
+ expr, rcx.repeating_scope);
match expr.node {
hir::ExprPath(..) => {
rcx.fcx.opt_node_ty_substs(expr.id, |item_substs| {
}
fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- struct_def: &hir::StructDef)
+ struct_def: &hir::VariantData)
-> AdtVariant<'tcx> {
let fields =
- struct_def.fields
- .iter()
+ struct_def.fields()
.map(|field| {
let field_ty = fcx.tcx().node_id_to_type(field.node.id);
let field_ty = fcx.instantiate_type_scheme(field.span,
enum_def: &hir::EnumDef)
-> Vec<AdtVariant<'tcx>> {
enum_def.variants.iter()
- .map(|variant| {
- match variant.node.kind {
- hir::TupleVariantKind(ref args) if !args.is_empty() => {
- let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id);
-
- // the regions in the argument types come from the
- // enum def'n, and hence will all be early bound
- let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap();
- AdtVariant {
- fields: args.iter().enumerate().map(|(index, arg)| {
- let arg_ty = arg_tys[index];
- let arg_ty =
- fcx.instantiate_type_scheme(variant.span,
- &fcx.inh
- .infcx
- .parameter_environment
- .free_substs,
- &arg_ty);
- AdtField {
- ty: arg_ty,
- span: arg.ty.span
- }
- }).collect()
- }
- }
- hir::TupleVariantKind(_) => {
- AdtVariant {
- fields: Vec::new()
- }
- }
- hir::StructVariantKind(ref struct_def) => {
- struct_variant(fcx, &**struct_def)
- }
- }
- })
+ .map(|variant| struct_variant(fcx, &variant.node.data))
.collect()
}
}
fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- struct_def: &hir::StructDef)
+ struct_def: &hir::VariantData)
-> AdtVariant<'tcx> {
let fields =
- struct_def.fields
- .iter()
+ struct_def.fields()
.map(|field| {
let field_ty = fcx.tcx().node_id_to_type(field.node.id);
let field_ty = fcx.instantiate_type_scheme(field.span,
enum_def: &hir::EnumDef)
-> Vec<AdtVariant<'tcx>> {
enum_def.variants.iter()
- .map(|variant| {
- match variant.node.kind {
- hir::TupleVariantKind(ref args) if !args.is_empty() => {
- let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id);
-
- // the regions in the argument types come from the
- // enum def'n, and hence will all be early bound
- let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap();
- AdtVariant {
- fields: args.iter().enumerate().map(|(index, arg)| {
- let arg_ty = arg_tys[index];
- let arg_ty =
- fcx.instantiate_type_scheme(variant.span,
- &fcx.inh
- .infcx
- .parameter_environment
- .free_substs,
- &arg_ty);
- AdtField {
- ty: arg_ty,
- span: arg.ty.span
- }
- }).collect()
- }
- }
- hir::TupleVariantKind(_) => {
- AdtVariant {
- fields: Vec::new()
- }
- }
- hir::StructVariantKind(ref struct_def) => {
- struct_variant(fcx, &**struct_def)
- }
- }
- })
+ .map(|variant| struct_variant(fcx, &variant.node.data))
.collect()
}
"overloaded augmented assignments are not stable");
fileline_help!(
tcx.sess, e.span,
- "add #![feature(augmented_assignments)] to the crate features \
+ "add #![feature(augmented_assignments)] to the crate root \
to enable");
}
}
let it_def_id = ccx.tcx.map.local_def_id(it.id);
let variant = tcx.lookup_adt_def_master(it_def_id).struct_variant();
- for (f, ty_f) in struct_def.fields.iter().zip(variant.fields.iter()) {
+ for (f, ty_f) in struct_def.fields().zip(variant.fields.iter()) {
convert_field(ccx, &scheme.generics, &predicates, f, ty_f)
}
- if let Some(ctor_id) = struct_def.ctor_id {
- convert_variant_ctor(tcx, ctor_id, variant, scheme, predicates);
+ if !struct_def.is_struct() {
+ convert_variant_ctor(tcx, struct_def.id(), variant, scheme, predicates);
}
},
hir::ItemTy(_, ref generics) => {
scheme: ty::TypeScheme<'tcx>,
predicates: ty::GenericPredicates<'tcx>) {
let ctor_ty = match variant.kind() {
- VariantKind::Unit | VariantKind::Dict => scheme.ty,
+ VariantKind::Unit | VariantKind::Struct => scheme.ty,
VariantKind::Tuple => {
let inputs: Vec<_> =
variant.fields
scheme: ty::TypeScheme<'tcx>,
predicates: ty::GenericPredicates<'tcx>,
variants: &[P<hir::Variant>]) {
- let tcx = ccx.tcx;
- let icx = ccx.icx(&predicates);
-
// fill the field types
for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) {
- match variant.node.kind {
- hir::TupleVariantKind(ref args) => {
- let rs = ExplicitRscope;
- let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect();
- for (field, &ty) in ty_variant.fields.iter().zip(input_tys.iter()) {
- field.fulfill_ty(ty);
- }
- }
-
- hir::StructVariantKind(ref struct_def) => {
- for (f, ty_f) in struct_def.fields.iter().zip(ty_variant.fields.iter()) {
- convert_field(ccx, &scheme.generics, &predicates, f, ty_f)
- }
- }
- };
+ for (f, ty_f) in variant.node.data.fields().zip(ty_variant.fields.iter()) {
+ convert_field(ccx, &scheme.generics, &predicates, f, ty_f)
+ }
// Convert the ctor, if any. This also registers the variant as
// an item.
convert_variant_ctor(
- tcx,
- variant.node.id,
+ ccx.tcx,
+ variant.node.data.id(),
ty_variant,
scheme.clone(),
predicates.clone()
did: DefId,
name: ast::Name,
disr_val: ty::Disr,
- def: &hir::StructDef) -> ty::VariantDefData<'tcx, 'tcx> {
+ def: &hir::VariantData) -> ty::VariantDefData<'tcx, 'tcx> {
let mut seen_fields: FnvHashMap<ast::Name, Span> = FnvHashMap();
- let fields = def.fields.iter().map(|f| {
+ let fields = def.fields().map(|f| {
let fid = tcx.map.local_def_id(f.node.id);
match f.node.kind {
hir::NamedField(name, vis) => {
fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>,
it: &hir::Item,
- def: &hir::StructDef)
+ def: &hir::VariantData)
-> ty::AdtDefMaster<'tcx>
{
let did = tcx.map.local_def_id(it.id);
- let ctor_id = def.ctor_id.map_or(did,
- |ctor_id| tcx.map.local_def_id(ctor_id));
+ let ctor_id = if !def.is_struct() {
+ tcx.map.local_def_id(def.id())
+ } else {
+ did
+ };
tcx.intern_adt_def(
did,
ty::AdtKind::Struct,
disr: ty::Disr)
-> ty::VariantDefData<'tcx, 'tcx>
{
- let did = tcx.map.local_def_id(v.node.id);
+ let did = tcx.map.local_def_id(v.node.data.id());
let name = v.node.name;
- match v.node.kind {
- hir::TupleVariantKind(ref va) => {
- ty::VariantDefData {
- did: did,
- name: name,
- disr_val: disr,
- fields: va.iter().map(|&hir::VariantArg { id, .. }| {
- ty::FieldDefData::new(
- tcx.map.local_def_id(id),
- special_idents::unnamed_field.name,
- hir::Visibility::Public
- )
- }).collect()
- }
- }
- hir::StructVariantKind(ref def) => {
- convert_struct_variant(tcx, did, name, disr, &def)
- }
- }
+ convert_struct_variant(tcx, did, name, disr, &v.node.data)
}
let did = tcx.map.local_def_id(it.id);
let repr_hints = tcx.lookup_repr_hints(did);
pub fields_stripped: bool,
}
-impl Clean<VariantStruct> for ::rustc_front::hir::StructDef {
+impl Clean<VariantStruct> for ::rustc_front::hir::VariantData {
fn clean(&self, cx: &DocContext) -> VariantStruct {
VariantStruct {
struct_type: doctree::struct_type_from_def(self),
- fields: self.fields.clean(cx),
+ fields: self.fields().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}
}
source: self.whence.clean(cx),
visibility: None,
stability: self.stab.clean(cx),
- def_id: cx.map.local_def_id(self.id),
+ def_id: cx.map.local_def_id(self.def.id()),
inner: VariantItem(Variant {
- kind: self.kind.clean(cx),
+ kind: struct_def_to_variant_kind(&self.def, cx),
}),
}
}
self.fields.iter().map(|f| f.unsubst_ty().clean(cx)).collect()
)
}
- ty::VariantKind::Dict => {
+ ty::VariantKind::Struct => {
StructVariant(VariantStruct {
struct_type: doctree::Plain,
fields_stripped: false,
StructVariant(VariantStruct),
}
-impl Clean<VariantKind> for hir::VariantKind {
- fn clean(&self, cx: &DocContext) -> VariantKind {
- match self {
- &hir::TupleVariantKind(ref args) => {
- if args.is_empty() {
- CLikeVariant
- } else {
- TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect())
- }
- },
- &hir::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)),
- }
+fn struct_def_to_variant_kind(struct_def: &hir::VariantData, cx: &DocContext) -> VariantKind {
+ if struct_def.is_struct() {
+ StructVariant(struct_def.clean(cx))
+ } else if struct_def.is_unit() {
+ CLikeVariant
+ } else {
+ TupleVariant(struct_def.fields().map(|x| x.node.ty.clean(cx)).collect())
}
}
pub struct Variant {
pub name: Name,
pub attrs: Vec<ast::Attribute>,
- pub kind: hir::VariantKind,
- pub id: ast::NodeId,
+ pub def: P<hir::VariantData>,
pub stab: Option<attr::Stability>,
pub whence: Span,
}
pub whence: Span,
}
-pub fn struct_type_from_def(sd: &hir::StructDef) -> StructType {
- if sd.ctor_id.is_some() {
+pub fn struct_type_from_def(sd: &hir::VariantData) -> StructType {
+ if !sd.is_struct() {
// We are in a tuple-struct
- match sd.fields.len() {
+ match sd.fields().count() {
0 => Unit,
1 => Newtype,
_ => Tuple
self.module.is_crate = true;
}
- pub fn visit_struct_def(&mut self, item: &hir::Item,
- name: ast::Name, sd: &hir::StructDef,
+ pub fn visit_variant_data(&mut self, item: &hir::Item,
+ name: ast::Name, sd: &hir::VariantData,
generics: &hir::Generics) -> Struct {
debug!("Visiting struct");
let struct_type = struct_type_from_def(&*sd);
stab: self.stability(item.id),
attrs: item.attrs.clone(),
generics: generics.clone(),
- fields: sd.fields.clone(),
+ fields: sd.fields().cloned().collect(),
whence: item.span
}
}
variants: def.variants.iter().map(|v| Variant {
name: v.node.name,
attrs: v.node.attrs.clone(),
- stab: self.stability(v.node.id),
- id: v.node.id,
- kind: v.node.kind.clone(),
+ stab: self.stability(v.node.data.id()),
+ def: v.node.data.clone(),
whence: v.span,
}).collect(),
vis: it.vis,
hir::ItemEnum(ref ed, ref gen) =>
om.enums.push(self.visit_enum_def(item, name, ed, gen)),
hir::ItemStruct(ref sd, ref gen) =>
- om.structs.push(self.visit_struct_def(item, name, &**sd, gen)),
+ om.structs.push(self.visit_variant_data(item, name, &**sd, gen)),
hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
constness, abi, gen)),
/// The hashes are all keyed by the thread-local random number generator
/// on creation by default. This means that the ordering of the keys is
/// randomized, but makes the tables more resistant to
-/// denial-of-service attacks (Hash DoS). This behaviour can be
+/// denial-of-service attacks (Hash DoS). This behavior can be
/// overridden with one of the constructors.
///
/// It is required that the keys implement the `Eq` and `Hash` traits, although
F: FnMut(&K) -> bool,
{
// This is the only function where capacity can be zero. To avoid
- // undefined behaviour when Bucket::new gets the raw bucket in this
+ // undefined behavior when Bucket::new gets the raw bucket in this
// case, immediately return the appropriate search result.
if table.capacity() == 0 {
return TableRef(table);
/// Returns the value of the 'HOME' environment variable if it is
/// set and not equal to the empty string. Otherwise, returns the value of the
/// 'USERPROFILE' environment variable if it is set and not equal to the empty
-/// string.
+/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to
+/// return the appropriate path.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx
///
/// # Examples
///
///
/// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
/// 'USERPROFILE' environment variable if any are set and not the empty
-/// string. Otherwise, tmpdir returns the path to the Windows directory.
+/// string. Otherwise, tmpdir returns the path to the Windows directory. This
+/// behavior is identical to that of [GetTempPath][msdn], which this function
+/// uses internally.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx
///
/// ```
/// use std::env;
/// represents known metadata about a file such as its permissions, size,
/// modification times, etc.
#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
pub struct Metadata(fs_imp::FileAttr);
/// Iterator over the entries in a directory.
use result;
use sys;
-/// A specialized [`Result`][result] type for I/O operations.
-///
-/// [result]: ../result/enum.Result.html
+/// A specialized [`Result`](../result/enum.Result.html) type for I/O
+/// operations.
///
/// This type is broadly used across `std::io` for any operation which may
/// produce an error.
b.iter(|| {
let mut rd = &buf[..];
- for _ in (0 .. 8) {
+ for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
b.iter(|| {
let mut wr = &mut buf[..];
- for _ in (0 .. 8) {
+ for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
b.iter(|| {
let mut rd = &buf[..];
- for _ in (0 .. 8) {
+ for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
b.iter(|| {
let mut wr = &mut buf[..];
- for _ in (0 .. 8) {
+ for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
//! not.
//!
//! Slices can only be handled through some kind of *pointer*, and as
-//! such come in many flavours such as:
+//! such come in many flavors such as:
//!
//! * `&[T]` - *shared slice*
//! * `&mut [T]` - *mutable slice*
/// to this listener. The port allocated can be queried via the
/// `socket_addr` function.
///
- /// The address type can be any implementer of `ToSocketAddrs` trait. See
+ /// The address type can be any implementor of `ToSocketAddrs` trait. See
/// its documentation for concrete examples.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
//! }.
//! Generic conversions, used by savvy API authors to create
//! overloaded methods.
-//! * `std::default::`[`Default`](../default/trait.Default).
+//! * `std::default::`[`Default`](../default/trait.Default.html).
//! Types that have default values.
//! * `std::iter::`{
//! [`Iterator`](../iter/trait.Iterator.html),
fn into_inner(self) -> imp::Process { self.handle }
}
-/// A handle to a child procesess's stdin
+/// A handle to a child process's stdin
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdin {
inner: AnonPipe
use cell::UnsafeCell;
use fmt;
use marker;
+use mem;
use ops::{Deref, DerefMut};
+use ptr;
use sys_common::mutex as sys;
use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
pub fn is_poisoned(&self) -> bool {
self.inner.poison.get()
}
+
+ /// Consumes this mutex, returning the underlying data.
+ ///
+ /// # Failure
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return an error instead.
+ #[unstable(feature = "mutex_into_inner", reason = "recently added", issue = "28968")]
+ pub fn into_inner(self) -> LockResult<T> where T: Sized {
+ // We know statically that there are no outstanding references to
+ // `self` so there's no need to lock the inner StaticMutex.
+ //
+ // To get the inner value, we'd like to call `data.into_inner()`,
+ // but because `Mutex` impl-s `Drop`, we can't move out of it, so
+ // we'll have to destructure it manually instead.
+ unsafe {
+ // Like `let Mutex { inner, data } = self`.
+ let (inner, data) = {
+ let Mutex { ref inner, ref data } = self;
+ (ptr::read(inner), ptr::read(data))
+ };
+ mem::forget(self);
+ inner.lock.destroy(); // Keep in sync with the `Drop` impl.
+
+ poison::map_result(inner.poison.borrow(), |_| data.into_inner())
+ }
+ }
+
+ /// Returns a mutable reference to the underlying data.
+ ///
+ /// Since this call borrows the `Mutex` mutably, no actual locking needs to
+ /// take place---the mutable borrow statically guarantees no locks exist.
+ ///
+ /// # Failure
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return an error instead.
+ #[unstable(feature = "mutex_get_mut", reason = "recently added", issue = "28968")]
+ pub fn get_mut(&mut self) -> LockResult<&mut T> {
+ // We know statically that there are no other references to `self`, so
+ // there's no need to lock the inner StaticMutex.
+ let data = unsafe { &mut *self.data.get() };
+ poison::map_result(self.inner.poison.borrow(), |_| data )
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
// This is actually safe b/c we know that there is no further usage of
// this mutex (it's up to the user to arrange for a mutex to get
// dropped, that's not our job)
+ //
+ // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
unsafe { self.inner.lock.destroy() }
}
}
use sync::mpsc::channel;
use sync::{Arc, Mutex, StaticMutex, Condvar};
+ use sync::atomic::{AtomicUsize, Ordering};
use thread;
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+ #[derive(Eq, PartialEq, Debug)]
+ struct NonCopy(i32);
+
unsafe impl<T: Send> Send for Packet<T> {}
unsafe impl<T> Sync for Packet<T> {}
*m.try_lock().unwrap() = ();
}
+ #[test]
+ fn test_into_inner() {
+ let m = Mutex::new(NonCopy(10));
+ assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+ }
+
+ #[test]
+ fn test_into_inner_drop() {
+ struct Foo(Arc<AtomicUsize>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+ let num_drops = Arc::new(AtomicUsize::new(0));
+ let m = Mutex::new(Foo(num_drops.clone()));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ {
+ let _inner = m.into_inner().unwrap();
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ }
+ assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+ }
+
+ #[test]
+ fn test_into_inner_poison() {
+ let m = Arc::new(Mutex::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.lock().unwrap();
+ panic!("test panic in inner thread to poison mutex");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().into_inner() {
+ Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
+ }
+ }
+
+ #[test]
+ fn test_get_mut() {
+ let mut m = Mutex::new(NonCopy(10));
+ *m.get_mut().unwrap() = NonCopy(20);
+ assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+ }
+
+ #[test]
+ fn test_get_mut_poison() {
+ let m = Arc::new(Mutex::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.lock().unwrap();
+ panic!("test panic in inner thread to poison mutex");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().get_mut() {
+ Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
+ }
+ }
+
#[test]
fn test_mutex_arc_condvar() {
let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
use cell::UnsafeCell;
use fmt;
use marker;
+use mem;
use ops::{Deref, DerefMut};
+use ptr;
use sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
use sys_common::rwlock as sys;
pub fn is_poisoned(&self) -> bool {
self.inner.poison.get()
}
+
+ /// Consumes this `RwLock`, returning the underlying data.
+ ///
+ /// # Failure
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
+ /// error will only be returned if the lock would have otherwise been
+ /// acquired.
+ #[unstable(feature = "rwlock_into_inner", reason = "recently added", issue = "28968")]
+ pub fn into_inner(self) -> LockResult<T> where T: Sized {
+ // We know statically that there are no outstanding references to
+ // `self` so there's no need to lock the inner StaticRwLock.
+ //
+ // To get the inner value, we'd like to call `data.into_inner()`,
+ // but because `RwLock` impl-s `Drop`, we can't move out of it, so
+ // we'll have to destructure it manually instead.
+ unsafe {
+ // Like `let RwLock { inner, data } = self`.
+ let (inner, data) = {
+ let RwLock { ref inner, ref data } = self;
+ (ptr::read(inner), ptr::read(data))
+ };
+ mem::forget(self);
+ inner.lock.destroy(); // Keep in sync with the `Drop` impl.
+
+ poison::map_result(inner.poison.borrow(), |_| data.into_inner())
+ }
+ }
+
+ /// Returns a mutable reference to the underlying data.
+ ///
+ /// Since this call borrows the `RwLock` mutably, no actual locking needs to
+ /// take place---the mutable borrow statically guarantees no locks exist.
+ ///
+ /// # Failure
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
+ /// error will only be returned if the lock would have otherwise been
+ /// acquired.
+ #[unstable(feature = "rwlock_get_mut", reason = "recently added", issue = "28968")]
+ pub fn get_mut(&mut self) -> LockResult<&mut T> {
+ // We know statically that there are no other references to `self`, so
+ // there's no need to lock the inner StaticRwLock.
+ let data = unsafe { &mut *self.data.get() };
+ poison::map_result(self.inner.poison.borrow(), |_| data )
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for RwLock<T> {
fn drop(&mut self) {
+ // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
unsafe { self.inner.lock.destroy() }
}
}
use sync::mpsc::channel;
use thread;
use sync::{Arc, RwLock, StaticRwLock, TryLockError};
+ use sync::atomic::{AtomicUsize, Ordering};
+
+ #[derive(Eq, PartialEq, Debug)]
+ struct NonCopy(i32);
#[test]
fn smoke() {
drop(read_guard);
}
+
+ #[test]
+ fn test_into_inner() {
+ let m = RwLock::new(NonCopy(10));
+ assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+ }
+
+ #[test]
+ fn test_into_inner_drop() {
+ struct Foo(Arc<AtomicUsize>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+ let num_drops = Arc::new(AtomicUsize::new(0));
+ let m = RwLock::new(Foo(num_drops.clone()));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ {
+ let _inner = m.into_inner().unwrap();
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ }
+ assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+ }
+
+ #[test]
+ fn test_into_inner_poison() {
+ let m = Arc::new(RwLock::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.write().unwrap();
+ panic!("test panic in inner thread to poison RwLock");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().into_inner() {
+ Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
+ }
+ }
+
+ #[test]
+ fn test_get_mut() {
+ let mut m = RwLock::new(NonCopy(10));
+ *m.get_mut().unwrap() = NonCopy(20);
+ assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+ }
+
+ #[test]
+ fn test_get_mut_poison() {
+ let m = Arc::new(RwLock::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.write().unwrap();
+ panic!("test panic in inner thread to poison RwLock");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().get_mut() {
+ Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
+ }
+ }
}
pub struct File(FileDesc);
+#[derive(Clone)]
pub struct FileAttr {
stat: raw::stat,
}
unsafe {
use libc::funcs::bsd44::*;
use libc::consts::os::extra::*;
- let mut mib = vec![CTL_KERN as c_int,
- KERN_PROC as c_int,
- KERN_PROC_PATHNAME as c_int,
- -1 as c_int];
+ let mut mib = [CTL_KERN as c_int,
+ KERN_PROC as c_int,
+ KERN_PROC_PATHNAME as c_int,
+ -1 as c_int];
let mut sz: libc::size_t = 0;
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
ptr::null_mut(), &mut sz, ptr::null_mut(),
let args = objc_msgSend(info, arguments_sel);
let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
- for i in (0..cnt) {
+ for i in 0..cnt {
let tmp = objc_msgSend(args, object_at_sel, i);
let utf_c_str: *const libc::c_char =
mem::transmute(objc_msgSend(tmp, utf8_sel));
pub type PCONSOLE_SCREEN_BUFFER_INFO = *mut CONSOLE_SCREEN_BUFFER_INFO;
#[repr(C)]
+#[derive(Clone)]
pub struct WIN32_FILE_ATTRIBUTE_DATA {
pub dwFileAttributes: libc::DWORD,
pub ftCreationTime: libc::FILETIME,
pub struct File { handle: Handle }
+#[derive(Clone)]
pub struct FileAttr {
data: c::WIN32_FILE_ATTRIBUTE_DATA,
reparse_tag: libc::DWORD,
pub use self::UintTy::*;
pub use self::UnOp::*;
pub use self::UnsafeSource::*;
-pub use self::VariantKind::*;
pub use self::ViewPath_::*;
pub use self::Visibility::*;
pub use self::PathParameters::*;
use std::rc::Rc;
use std::borrow::Cow;
use std::hash::{Hash, Hasher};
+use std::{iter, option, slice};
use serialize::{Encodable, Decodable, Encoder, Decoder};
/// A name is a part of an identifier, representing a string or gensym. It's
pub enum BlockCheckMode {
DefaultBlock,
UnsafeBlock(UnsafeSource),
- PushUnsafeBlock(UnsafeSource),
- PopUnsafeBlock(UnsafeSource),
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub items: Vec<P<ForeignItem>>,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct VariantArg {
- pub ty: P<Ty>,
- pub id: NodeId,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum VariantKind {
- /// Tuple variant, e.g. `Foo(A, B)`
- TupleVariantKind(Vec<VariantArg>),
- /// Struct variant, e.g. `Foo {x: A, y: B}`
- StructVariantKind(P<StructDef>),
-}
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct EnumDef {
pub variants: Vec<P<Variant>>,
pub struct Variant_ {
pub name: Ident,
pub attrs: Vec<Attribute>,
- pub kind: VariantKind,
- pub id: NodeId,
+ pub data: P<VariantData>,
/// Explicit discriminant, eg `Foo = 1`
pub disr_expr: Option<P<Expr>>,
}
}
}
+/// Fields and Ids of enum variants and structs
+///
+/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all
+/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants).
+/// One shared Id can be successfully used for these two purposes.
+/// Id of the whole enum lives in `Item`.
+///
+/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually
+/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of
+/// the variant itself" from enum variants.
+/// Id of the whole struct lives in `Item`.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct StructDef {
- /// Fields, not including ctor
- pub fields: Vec<StructField>,
- /// ID of the constructor. This is only used for tuple- or enum-like
- /// structs.
- pub ctor_id: Option<NodeId>,
+pub enum VariantData {
+ Struct(Vec<StructField>, NodeId),
+ Tuple(Vec<StructField>, NodeId),
+ Unit(NodeId),
+}
+
+pub type FieldIter<'a> = iter::FlatMap<option::IntoIter<&'a Vec<StructField>>,
+ slice::Iter<'a, StructField>,
+ fn(&Vec<StructField>) -> slice::Iter<StructField>>;
+
+impl VariantData {
+ pub fn fields(&self) -> FieldIter {
+ fn vec_iter<T>(v: &Vec<T>) -> slice::Iter<T> { v.iter() }
+ match *self {
+ VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => Some(fields),
+ _ => None,
+ }.into_iter().flat_map(vec_iter)
+ }
+ pub fn id(&self) -> NodeId {
+ match *self {
+ VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id
+ }
+ }
+ pub fn is_struct(&self) -> bool {
+ if let VariantData::Struct(..) = *self { true } else { false }
+ }
+ pub fn is_tuple(&self) -> bool {
+ if let VariantData::Tuple(..) = *self { true } else { false }
+ }
+ pub fn is_unit(&self) -> bool {
+ if let VariantData::Unit(..) = *self { true } else { false }
+ }
}
/*
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
ItemEnum(EnumDef, Generics),
/// A struct definition, e.g. `struct Foo<A> {x: A}`
- ItemStruct(P<StructDef>, Generics),
+ ItemStruct(P<VariantData>, Generics),
/// Represents a Trait Declaration
ItemTrait(Unsafety,
Generics,
}
}
}
- ItemEnum(ref enum_definition, _) => {
- for variant in &enum_definition.variants {
- self.operation.visit_id(variant.node.id)
- }
- }
_ => {}
}
visit::walk_struct_field(self, struct_field)
}
- fn visit_struct_def(&mut self,
- struct_def: &StructDef,
+ fn visit_variant_data(&mut self,
+ struct_def: &VariantData,
_: ast::Ident,
_: &ast::Generics,
- id: NodeId) {
- self.operation.visit_id(id);
- struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id));
+ _: NodeId,
+ _: Span) {
+ self.operation.visit_id(struct_def.id());
visit::walk_struct_def(self, struct_def);
}
id_visitor.operation.result
}
-/// Returns true if the given struct def is tuple-like; i.e. that its fields
-/// are unnamed.
-pub fn struct_def_is_tuple_like(struct_def: &ast::StructDef) -> bool {
- struct_def.ctor_id.is_some()
-}
-
/// Returns true if the given pattern consists solely of an identifier
/// and false otherwise.
pub fn pat_is_ident(pat: P<ast::Pat>) -> bool {
if !(cx.in_cfg)(&v.node.attrs) {
None
} else {
- Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind,
+ Some(v.map(|Spanned {node: ast::Variant_ {name, attrs, data,
disr_expr}, span}| {
Spanned {
node: ast::Variant_ {
- id: id,
name: name,
attrs: attrs,
- kind: match kind {
- ast::TupleVariantKind(..) => kind,
- ast::StructVariantKind(def) => {
- ast::StructVariantKind(fold_struct(cx, def))
- }
- },
+ data: fold_struct(cx, data),
disr_expr: disr_expr,
},
span: span
fold::noop_fold_item_underscore(item, cx)
}
-fn fold_struct<F>(cx: &mut Context<F>, def: P<ast::StructDef>) -> P<ast::StructDef> where
+fn fold_struct<F>(cx: &mut Context<F>, def: P<ast::VariantData>) -> P<ast::VariantData> where
F: FnMut(&[ast::Attribute]) -> bool
{
- def.map(|ast::StructDef { fields, ctor_id }| {
- ast::StructDef {
- fields: fields.into_iter().filter(|m| {
- (cx.in_cfg)(&m.node.attrs)
- }).collect(),
- ctor_id: ctor_id,
+ def.map(|vdata| {
+ match vdata {
+ ast::VariantData::Struct(fields, id) => {
+ ast::VariantData::Struct(fields.into_iter().filter(|m| {
+ (cx.in_cfg)(&m.node.attrs)
+ }).collect(), id)
+ }
+ ast::VariantData::Tuple(fields, id) => {
+ ast::VariantData::Tuple(fields.into_iter().filter(|m| {
+ (cx.in_cfg)(&m.node.attrs)
+ }).collect(), id)
+ }
+ ast::VariantData::Unit(id) => ast::VariantData::Unit(id)
}
})
}
syntax_expanders.insert(intern("cfg"),
builtin_normal_expander(
ext::cfg::expand_cfg));
- syntax_expanders.insert(intern("push_unsafe"),
- builtin_normal_expander(
- ext::pushpop_safe::expand_push_unsafe));
- syntax_expanders.insert(intern("pop_unsafe"),
- builtin_normal_expander(
- ext::pushpop_safe::expand_pop_unsafe));
syntax_expanders.insert(intern("trace_macros"),
builtin_normal_expander(
ext::trace_macros::expand_trace_macros));
fn item_struct_poly(&self,
span: Span,
name: Ident,
- struct_def: ast::StructDef,
+ struct_def: ast::VariantData,
generics: Generics) -> P<ast::Item>;
- fn item_struct(&self, span: Span, name: Ident, struct_def: ast::StructDef) -> P<ast::Item>;
+ fn item_struct(&self, span: Span, name: Ident, struct_def: ast::VariantData) -> P<ast::Item>;
fn item_mod(&self, span: Span, inner_span: Span,
name: Ident, attrs: Vec<ast::Attribute>,
}
fn variant(&self, span: Span, name: Ident, tys: Vec<P<ast::Ty>> ) -> ast::Variant {
- let args = tys.into_iter().map(|ty| {
- ast::VariantArg { ty: ty, id: ast::DUMMY_NODE_ID }
+ let fields: Vec<_> = tys.into_iter().map(|ty| {
+ Spanned { span: ty.span, node: ast::StructField_ {
+ ty: ty,
+ kind: ast::UnnamedField(ast::Inherited),
+ attrs: Vec::new(),
+ id: ast::DUMMY_NODE_ID,
+ }}
}).collect();
+ let vdata = if fields.is_empty() {
+ ast::VariantData::Unit(ast::DUMMY_NODE_ID)
+ } else {
+ ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID)
+ };
+
respan(span,
ast::Variant_ {
name: name,
attrs: Vec::new(),
- kind: ast::TupleVariantKind(args),
- id: ast::DUMMY_NODE_ID,
+ data: P(vdata),
disr_expr: None,
})
}
}
fn item_struct(&self, span: Span, name: Ident,
- struct_def: ast::StructDef) -> P<ast::Item> {
+ struct_def: ast::VariantData) -> P<ast::Item> {
self.item_struct_poly(
span,
name,
}
fn item_struct_poly(&self, span: Span, name: Ident,
- struct_def: ast::StructDef, generics: Generics) -> P<ast::Item> {
+ struct_def: ast::VariantData, generics: Generics) -> P<ast::Item> {
self.item(span, name, Vec::new(), ast::ItemStruct(P(struct_def), generics))
}
//! A static method on the types above would result in,
//!
//! ```{.text}
-//! StaticStruct(<ast::StructDef of A>, Named(vec![(<ident of x>, <span of x>)]))
+//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
//!
-//! StaticStruct(<ast::StructDef of B>, Unnamed(vec![<span of x>]))
+//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
//!
//! StaticEnum(<ast::EnumDef of C>,
//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
use abi::Abi;
use abi;
use ast;
-use ast::{EnumDef, Expr, Ident, Generics, StructDef};
+use ast::{EnumDef, Expr, Ident, Generics, VariantData};
use ast_util;
use attr;
use attr::AttrMetaMethods;
EnumNonMatchingCollapsed(Vec<Ident>, &'a [P<ast::Variant>], &'a [Ident]),
/// A static method where `Self` is a struct.
- StaticStruct(&'a ast::StructDef, StaticFields),
+ StaticStruct(&'a ast::VariantData, StaticFields),
/// A static method where `Self` is an enum.
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
}
fn expand_struct_def(&self,
cx: &mut ExtCtxt,
- struct_def: &'a StructDef,
+ struct_def: &'a VariantData,
type_ident: Ident,
generics: &Generics) -> P<ast::Item> {
- let field_tys: Vec<P<ast::Ty>> = struct_def.fields.iter()
+ let field_tys: Vec<P<ast::Ty>> = struct_def.fields()
.map(|field| field.node.ty.clone())
.collect();
let mut field_tys = Vec::new();
for variant in &enum_def.variants {
- match variant.node.kind {
- ast::VariantKind::TupleVariantKind(ref args) => {
- field_tys.extend(args.iter()
- .map(|arg| arg.ty.clone()));
- }
- ast::VariantKind::StructVariantKind(ref args) => {
- field_tys.extend(args.fields.iter()
- .map(|field| field.node.ty.clone()));
- }
- }
+ field_tys.extend(variant.node.data.fields()
+ .map(|field| field.node.ty.clone()));
}
let methods = self.methods.iter().map(|method_def| {
fn expand_struct_method_body<'b>(&self,
cx: &mut ExtCtxt,
trait_: &TraitDef<'b>,
- struct_def: &'b StructDef,
+ struct_def: &'b VariantData,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>])
fn expand_static_struct_method_body(&self,
cx: &mut ExtCtxt,
trait_: &TraitDef,
- struct_def: &StructDef,
+ struct_def: &VariantData,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>])
-> P<Expr> {
let summary = enum_def.variants.iter().map(|v| {
let ident = v.node.name;
- let summary = match v.node.kind {
- ast::TupleVariantKind(ref args) => {
- Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
- }
- ast::StructVariantKind(ref struct_def) => {
- trait_.summarise_struct(cx, &**struct_def)
- }
- };
+ let summary = trait_.summarise_struct(cx, &v.node.data);
(ident, v.span, summary)
}).collect();
self.call_substructure_method(cx, trait_, type_ident,
fn summarise_struct(&self,
cx: &mut ExtCtxt,
- struct_def: &StructDef) -> StaticFields {
+ struct_def: &VariantData) -> StaticFields {
let mut named_idents = Vec::new();
let mut just_spans = Vec::new();
- for field in struct_def.fields.iter(){
+ for field in struct_def.fields(){
let sp = self.set_expn_info(cx, field.span);
match field.node.kind {
ast::NamedField(ident, _) => named_idents.push((ident, sp)),
fn create_struct_pattern(&self,
cx: &mut ExtCtxt,
struct_path: ast::Path,
- struct_def: &'a StructDef,
+ struct_def: &'a VariantData,
prefix: &str,
mutbl: ast::Mutability)
-> (P<ast::Pat>, Vec<(Span, Option<Ident>,
P<Expr>,
&'a [ast::Attribute])>) {
- if struct_def.fields.is_empty() {
+ if struct_def.fields().count() == 0 {
return (cx.pat_enum(self.span, struct_path, vec![]), vec![]);
}
let mut ident_expr = Vec::new();
let mut struct_type = Unknown;
- for (i, struct_field) in struct_def.fields.iter().enumerate() {
+ for (i, struct_field) in struct_def.fields().enumerate() {
let sp = self.set_expn_info(cx, struct_field.span);
let opt_id = match struct_field.node.kind {
ast::NamedField(ident, _) if (struct_type == Unknown ||
-> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
let variant_ident = variant.node.name;
let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]);
- match variant.node.kind {
- ast::TupleVariantKind(ref variant_args) => {
- if variant_args.is_empty() {
- return (cx.pat_enum(variant.span, variant_path, vec![]), vec![]);
- }
-
- let mut paths = Vec::new();
- let mut ident_expr: Vec<(_, _, _, &'a [ast::Attribute])> = Vec::new();
- for (i, va) in variant_args.iter().enumerate() {
- let sp = self.set_expn_info(cx, va.ty.span);
- let ident = cx.ident_of(&format!("{}_{}", prefix, i));
- let path1 = codemap::Spanned{span: sp, node: ident};
- paths.push(path1);
- let expr_path = cx.expr_path(cx.path_ident(sp, ident));
- let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
- ident_expr.push((sp, None, val, &[]));
- }
-
- let subpats = self.create_subpatterns(cx, paths, mutbl);
-
- (cx.pat_enum(variant.span, variant_path, subpats),
- ident_expr)
- }
- ast::StructVariantKind(ref struct_def) => {
- self.create_struct_pattern(cx, variant_path, &**struct_def,
- prefix, mutbl)
- }
- }
+ self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl)
}
}
let mut arms = Vec::new();
for variant in &enum_def.variants {
- match variant.node.kind {
- ast::TupleVariantKind(ref args) => {
- if !args.is_empty() {
- cx.span_err(trait_span,
- "`FromPrimitive` cannot be derived for \
- enum variants with arguments");
- return cx.expr_fail(trait_span,
- InternedString::new(""));
- }
- let span = variant.span;
+ let def = &variant.node.data;
+ if !def.is_unit() {
+ cx.span_err(trait_span, "`FromPrimitive` cannot be derived \
+ for enums with non-unit variants");
+ return cx.expr_fail(trait_span,
+ InternedString::new(""));
+ }
- // expr for `$n == $variant as $name`
- let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
- let variant = cx.expr_path(path);
- let ty = cx.ty_ident(span, cx.ident_of(name));
- let cast = cx.expr_cast(span, variant.clone(), ty);
- let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
+ let span = variant.span;
- // expr for `Some($variant)`
- let body = cx.expr_some(span, variant);
+ // expr for `$n == $variant as $name`
+ let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
+ let variant = cx.expr_path(path);
+ let ty = cx.ty_ident(span, cx.ident_of(name));
+ let cast = cx.expr_cast(span, variant.clone(), ty);
+ let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
- // arm for `_ if $guard => $body`
- let arm = ast::Arm {
- attrs: vec!(),
- pats: vec!(cx.pat_wild(span)),
- guard: Some(guard),
- body: body,
- };
+ // expr for `Some($variant)`
+ let body = cx.expr_some(span, variant);
- arms.push(arm);
- }
- ast::StructVariantKind(_) => {
- cx.span_err(trait_span,
- "`FromPrimitive` cannot be derived for enums \
- with struct variants");
- return cx.expr_fail(trait_span,
- InternedString::new(""));
- }
- }
+ // arm for `_ if $guard => $body`
+ let arm = ast::Arm {
+ attrs: vec!(),
+ pats: vec!(cx.pat_wild(span)),
+ guard: Some(guard),
+ body: body,
+ };
+
+ arms.push(arm);
}
// arm for `_ => None`
+++ /dev/null
-// 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 compiler code necessary to support the `push_unsafe!` and
- * `pop_unsafe!` macros.
- *
- * This is a hack to allow a kind of "safety hygiene", where a macro
- * can generate code with an interior expression that inherits the
- * safety of some outer context.
- *
- * For example, in:
- *
- * ```rust
- * fn foo() { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) }
- * ```
- *
- * the `EXPR_1` is considered to be in an `unsafe` context,
- * but `EXPR_2` is considered to be in a "safe" (i.e. checked) context.
- *
- * For comparison, in:
- *
- * ```rust
- * fn foo() { unsafe { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } }
- * ```
- *
- * both `EXPR_1` and `EXPR_2` are considered to be in `unsafe`
- * contexts.
- *
- */
-
-use ast;
-use codemap::Span;
-use ext::base::*;
-use ext::base;
-use ext::build::AstBuilder;
-use feature_gate;
-use ptr::P;
-
-enum PushPop { Push, Pop }
-
-pub fn expand_push_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
- -> Box<base::MacResult+'cx> {
- expand_pushpop_unsafe(cx, sp, tts, PushPop::Push)
-}
-
-pub fn expand_pop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
- -> Box<base::MacResult+'cx> {
- expand_pushpop_unsafe(cx, sp, tts, PushPop::Pop)
-}
-
-fn expand_pushpop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree],
- pp: PushPop) -> Box<base::MacResult+'cx> {
- feature_gate::check_for_pushpop_syntax(
- cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp);
-
- let mut exprs = match get_exprs_from_tts(cx, sp, tts) {
- Some(exprs) => exprs.into_iter(),
- None => return DummyResult::expr(sp),
- };
-
- let expr = match (exprs.next(), exprs.next()) {
- (Some(expr), None) => expr,
- _ => {
- let msg = match pp {
- PushPop::Push => "push_unsafe! takes 1 arguments",
- PushPop::Pop => "pop_unsafe! takes 1 arguments",
- };
- cx.span_err(sp, msg);
- return DummyResult::expr(sp);
- }
- };
-
- let source = ast::UnsafeSource::CompilerGenerated;
- let check_mode = match pp {
- PushPop::Push => ast::BlockCheckMode::PushUnsafeBlock(source),
- PushPop::Pop => ast::BlockCheckMode::PopUnsafeBlock(source),
- };
-
- MacEager::expr(cx.expr_block(P(ast::Block {
- stmts: vec![],
- expr: Some(expr),
- id: ast::DUMMY_NODE_ID,
- rules: check_mode,
- span: sp
- })))
-}
// allow `#[unwind]`
("unwind_attributes", "1.4.0", None, Active),
- // allow empty structs/enum variants with braces
+ // allow empty structs and enum variants with braces
("braced_empty_structs", "1.5.0", None, Active),
// allow overloading augmented assignment operations like `a += b`
pub cfg_target_feature: bool,
pub cfg_target_vendor: bool,
pub augmented_assignments: bool,
+ pub braced_empty_structs: bool,
}
impl Features {
cfg_target_feature: false,
cfg_target_vendor: false,
augmented_assignments: false,
+ braced_empty_structs: false,
}
}
}
}
}
- ast::ItemStruct(ref def, _) => {
+ ast::ItemStruct(..) => {
if attr::contains_name(&i.attrs[..], "simd") {
self.gate_feature("simd", i.span,
"SIMD types are experimental and possibly buggy");
}
}
}
- if def.fields.is_empty() && def.ctor_id.is_none() {
- self.gate_feature("braced_empty_structs", i.span,
- "empty structs with braces are unstable");
- }
}
ast::ItemDefaultImpl(..) => {
visit::walk_item(self, i);
}
+ fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident,
+ _: &'v ast::Generics, _: ast::NodeId, span: Span) {
+ if s.fields().count() == 0 {
+ if s.is_struct() {
+ self.gate_feature("braced_empty_structs", span,
+ "empty structs and enum variants with braces are unstable");
+ } else if s.is_tuple() {
+ self.context.span_handler.span_err(span, "empty tuple structs and enum variants \
+ are not allowed, use unit structs and \
+ enum variants instead");
+ }
+ }
+ visit::walk_struct_def(self, s)
+ }
+
fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
"link_name") {
"box expression syntax is experimental; \
you can call `Box::new` instead.");
}
- ast::ExprStruct(_, ref fields, ref expr) => {
- if fields.is_empty() && expr.is_none() {
- self.gate_feature("braced_empty_structs", e.span,
- "empty structs with braces are unstable");
- }
- }
_ => {}
}
visit::walk_expr(self, e);
pattern.span,
"box pattern syntax is experimental");
}
- ast::PatStruct(_, ref fields, dotdot) => {
- if fields.is_empty() && !dotdot {
- self.gate_feature("braced_empty_structs", pattern.span,
- "empty structs with braces are unstable");
- }
- }
_ => {}
}
visit::walk_pat(self, pattern)
cfg_target_feature: cx.has_feature("cfg_target_feature"),
cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
augmented_assignments: cx.has_feature("augmented_assignments"),
+ braced_empty_structs: cx.has_feature("braced_empty_structs"),
}
}
noop_fold_poly_trait_ref(p, self)
}
- fn fold_struct_def(&mut self, struct_def: P<StructDef>) -> P<StructDef> {
+ fn fold_variant_data(&mut self, struct_def: P<VariantData>) -> P<VariantData> {
noop_fold_struct_def(struct_def, self)
}
noop_fold_opt_lifetime(o_lt, self)
}
- fn fold_variant_arg(&mut self, va: VariantArg) -> VariantArg {
- noop_fold_variant_arg(va, self)
- }
-
fn fold_opt_bounds(&mut self, b: Option<OwnedSlice<TyParamBound>>)
-> Option<OwnedSlice<TyParamBound>> {
noop_fold_opt_bounds(b, self)
}
pub fn noop_fold_variant<T: Folder>(v: P<Variant>, fld: &mut T) -> P<Variant> {
- v.map(|Spanned {node: Variant_ {id, name, attrs, kind, disr_expr}, span}| Spanned {
+ v.map(|Spanned {node: Variant_ {name, attrs, data, disr_expr}, span}| Spanned {
node: Variant_ {
- id: fld.new_id(id),
name: name,
attrs: fold_attrs(attrs, fld),
- kind: match kind {
- TupleVariantKind(variant_args) => {
- TupleVariantKind(variant_args.move_map(|x|
- fld.fold_variant_arg(x)))
- }
- StructVariantKind(struct_def) => {
- StructVariantKind(fld.fold_struct_def(struct_def))
- }
- },
+ data: fld.fold_variant_data(data),
disr_expr: disr_expr.map(|e| fld.fold_expr(e)),
},
span: fld.new_span(span),
}
}
-pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> {
- struct_def.map(|StructDef { fields, ctor_id }| StructDef {
- fields: fields.move_map(|f| fld.fold_struct_field(f)),
- ctor_id: ctor_id.map(|cid| fld.new_id(cid)),
+pub fn noop_fold_struct_def<T: Folder>(struct_def: P<VariantData>, fld: &mut T) -> P<VariantData> {
+ struct_def.map(|vdata| {
+ match vdata {
+ ast::VariantData::Struct(fields, id) => {
+ ast::VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)),
+ fld.new_id(id))
+ }
+ ast::VariantData::Tuple(fields, id) => {
+ ast::VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)),
+ fld.new_id(id))
+ }
+ ast::VariantData::Unit(id) => ast::VariantData::Unit(fld.new_id(id))
+ }
})
}
bounds.move_map(|bound| folder.fold_ty_param_bound(bound))
}
-fn noop_fold_variant_arg<T: Folder>(VariantArg {id, ty}: VariantArg, folder: &mut T)
- -> VariantArg {
- VariantArg {
- id: folder.new_id(id),
- ty: folder.fold_ty(ty)
- }
-}
-
pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
b.map(|Block {id, stmts, expr, rules, span}| Block {
id: folder.new_id(id),
folder.fold_generics(generics))
}
ItemStruct(struct_def, generics) => {
- let struct_def = folder.fold_struct_def(struct_def);
+ let struct_def = folder.fold_variant_data(struct_def);
ItemStruct(struct_def, folder.fold_generics(generics))
}
ItemDefaultImpl(unsafety, ref trait_ref) => {
pub mod log_syntax;
pub mod mtwt;
pub mod quote;
- pub mod pushpop_safe;
pub mod source_util;
pub mod trace_macros;
use ast::PatWildSingle;
use ast::{PolyTraitRef, QSelf};
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
-use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
-use ast::{StructVariantKind, BiSub, StrStyle};
+use ast::{StmtExpr, StmtSemi, StmtMac, VariantData, StructField};
+use ast::{BiSub, StrStyle};
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::{Ty, Ty_, TypeBinding};
use ast::{TyMac};
use ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer};
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr};
/// - `extern fn`
/// - etc
pub fn parse_fn_front_matter(&mut self) -> PResult<(ast::Constness, ast::Unsafety, abi::Abi)> {
+ let unsafety = try!(self.parse_unsafety());
let is_const_fn = try!(self.eat_keyword(keywords::Const));
let (constness, unsafety, abi) = if is_const_fn {
- (Constness::Const, Unsafety::Normal, abi::Rust)
+ (Constness::Const, unsafety, abi::Rust)
} else {
- let unsafety = try!(self.parse_unsafety());
let abi = if try!(self.eat_keyword(keywords::Extern)) {
try!(self.parse_opt_abi()).unwrap_or(abi::C)
} else {
// Otherwise if we look ahead and see a paren we parse a tuple-style
// struct.
- let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) {
+ let vdata = if self.token.is_keyword(keywords::Where) {
generics.where_clause = try!(self.parse_where_clause());
if try!(self.eat(&token::Semi)) {
// If we see a: `struct Foo<T> where T: Copy;` style decl.
- (Vec::new(), Some(ast::DUMMY_NODE_ID))
+ VariantData::Unit(ast::DUMMY_NODE_ID)
} else {
// If we see: `struct Foo<T> where T: Copy { ... }`
- (try!(self.parse_record_struct_body()), None)
+ VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID)
}
// No `where` so: `struct Foo<T>;`
} else if try!(self.eat(&token::Semi) ){
- (Vec::new(), Some(ast::DUMMY_NODE_ID))
+ VariantData::Unit(ast::DUMMY_NODE_ID)
// Record-style struct definition
} else if self.token == token::OpenDelim(token::Brace) {
- let fields = try!(self.parse_record_struct_body());
- (fields, None)
+ VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID)
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(token::Paren) {
- let fields = try!(self.parse_tuple_struct_body(class_name, &mut generics));
- (fields, Some(ast::DUMMY_NODE_ID))
+ VariantData::Tuple(try!(self.parse_tuple_struct_body(&mut generics)),
+ ast::DUMMY_NODE_ID)
} else {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \
};
Ok((class_name,
- ItemStruct(P(ast::StructDef {
- fields: fields,
- ctor_id: ctor_id,
- }), generics),
- None))
+ ItemStruct(P(vdata), generics),
+ None))
}
pub fn parse_record_struct_body(&mut self) -> PResult<Vec<StructField>> {
}
pub fn parse_tuple_struct_body(&mut self,
- class_name: ast::Ident,
generics: &mut ast::Generics)
-> PResult<Vec<StructField>> {
// This is the case where we find `struct Foo<T>(T) where T: Copy;`
Ok(spanned(lo, p.span.hi, struct_field_))
}));
- if fields.is_empty() {
- return Err(self.fatal(&format!("unit-like struct definition should be \
- written as `struct {};`",
- class_name)));
- }
-
generics.where_clause = try!(self.parse_where_clause());
try!(self.expect(&token::Semi));
Ok(fields)
/// Parse a structure-like enum variant definition
/// this should probably be renamed or refactored...
- fn parse_struct_def(&mut self) -> PResult<P<StructDef>> {
+ fn parse_struct_def(&mut self) -> PResult<P<VariantData>> {
let mut fields: Vec<StructField> = Vec::new();
while self.token != token::CloseDelim(token::Brace) {
fields.push(try!(self.parse_struct_decl_field(false)));
}
try!(self.bump());
- Ok(P(StructDef {
- fields: fields,
- ctor_id: None,
- }))
+ Ok(P(VariantData::Struct(fields, ast::DUMMY_NODE_ID)))
}
/// Parse the part of an "enum" decl following the '{'
let variant_attrs = self.parse_outer_attributes();
let vlo = self.span.lo;
- let kind;
- let mut args = Vec::new();
+ let struct_def;
let mut disr_expr = None;
let ident = try!(self.parse_ident());
if try!(self.eat(&token::OpenDelim(token::Brace)) ){
// Parse a struct variant.
all_nullary = false;
- let start_span = self.span;
- let struct_def = try!(self.parse_struct_def());
- if struct_def.fields.is_empty() {
- self.span_err(start_span,
- &format!("unit-like struct variant should be written \
- without braces, as `{},`",
- ident));
- }
- kind = StructVariantKind(struct_def);
+ struct_def = try!(self.parse_struct_def());
} else if self.check(&token::OpenDelim(token::Paren)) {
all_nullary = false;
let arg_tys = try!(self.parse_enum_variant_seq(
seq_sep_trailing_allowed(token::Comma),
|p| p.parse_ty_sum()
));
+ let mut fields = Vec::new();
for ty in arg_tys {
- args.push(ast::VariantArg {
+ fields.push(Spanned { span: ty.span, node: ast::StructField_ {
ty: ty,
+ kind: ast::UnnamedField(ast::Inherited),
+ attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
- });
+ }});
}
- kind = TupleVariantKind(args);
+ struct_def = P(ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID));
} else if try!(self.eat(&token::Eq) ){
disr_expr = Some(try!(self.parse_expr_nopanic()));
any_disr = disr_expr.as_ref().map(|expr| expr.span);
- kind = TupleVariantKind(args);
+ struct_def = P(ast::VariantData::Unit(ast::DUMMY_NODE_ID));
} else {
- kind = TupleVariantKind(Vec::new());
+ struct_def = P(ast::VariantData::Unit(ast::DUMMY_NODE_ID));
}
let vr = ast::Variant_ {
name: ident,
attrs: variant_attrs,
- kind: kind,
- id: ast::DUMMY_NODE_ID,
+ data: struct_def,
disr_expr: disr_expr,
};
variants.push(P(spanned(vlo, self.last_span.hi, vr)));
} else {
abi::Rust
};
+ let constness = if abi == abi::Rust && try!(self.eat_keyword(keywords::Const) ){
+ Constness::Const
+ } else {
+ Constness::NotConst
+ };
try!(self.expect_keyword(keywords::Fn));
let (ident, item_, extra_attrs) =
- try!(self.parse_item_fn(Unsafety::Unsafe, Constness::NotConst, abi));
+ try!(self.parse_item_fn(Unsafety::Unsafe, constness, abi));
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
self.end()
}
+ fn commasep_iter<'it, T: 'it, F, I>(&mut self, b: Breaks, elts: I, mut op: F) -> io::Result<()>
+ where F: FnMut(&mut Self, &T) -> io::Result<()>,
+ I: Iterator<Item=&'it T>,
+ {
+ try!(self.rbox(0, b));
+ let mut first = true;
+ for elt in elts {
+ if first { first = false; } else { try!(self.word_space(",")); }
+ try!(op(self, elt));
+ }
+ self.end()
+ }
fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
let mut cur_lit = self.cur_cmnt_and_lit().cur_lit;
}
ast::ItemStruct(ref struct_def, ref generics) => {
try!(self.head(&visibility_qualified(item.vis,"struct")));
- try!(self.print_struct(&**struct_def, generics, item.ident, item.span));
+ try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
}
ast::ItemDefaultImpl(unsafety, ref trait_ref) => {
}
pub fn print_struct(&mut self,
- struct_def: &ast::StructDef,
+ struct_def: &ast::VariantData,
generics: &ast::Generics,
ident: ast::Ident,
- span: codemap::Span) -> io::Result<()> {
+ span: codemap::Span,
+ print_finalizer: bool) -> io::Result<()> {
try!(self.print_ident(ident));
try!(self.print_generics(generics));
- if ast_util::struct_def_is_tuple_like(struct_def) {
- if !struct_def.fields.is_empty() {
+ if !struct_def.is_struct() {
+ if struct_def.is_tuple() {
try!(self.popen());
- try!(self.commasep(
- Inconsistent, &struct_def.fields,
+ try!(self.commasep_iter(
+ Inconsistent, struct_def.fields(),
|s, field| {
match field.node.kind {
ast::NamedField(..) => panic!("unexpected named field"),
try!(self.pclose());
}
try!(self.print_where_clause(&generics.where_clause));
- try!(word(&mut self.s, ";"));
+ if print_finalizer {
+ try!(word(&mut self.s, ";"));
+ }
try!(self.end());
self.end() // close the outer-box
} else {
try!(self.bopen());
try!(self.hardbreak_if_not_bol());
- for field in &struct_def.fields {
+ for field in struct_def.fields() {
match field.node.kind {
ast::UnnamedField(..) => panic!("unexpected unnamed field"),
ast::NamedField(ident, visibility) => {
}
pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> {
- match v.node.kind {
- ast::TupleVariantKind(ref args) => {
- try!(self.print_ident(v.node.name));
- if !args.is_empty() {
- try!(self.popen());
- try!(self.commasep(Consistent,
- &args[..],
- |s, arg| s.print_type(&*arg.ty)));
- try!(self.pclose());
- }
- }
- ast::StructVariantKind(ref struct_def) => {
- try!(self.head(""));
- let generics = ast_util::empty_generics();
- try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span));
- }
- }
+ try!(self.head(""));
+ let generics = ast_util::empty_generics();
+ try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false));
match v.node.disr_expr {
Some(ref d) => {
try!(space(&mut self.s));
attrs: &[ast::Attribute],
close_box: bool) -> io::Result<()> {
match blk.rules {
- ast::UnsafeBlock(..) | ast::PushUnsafeBlock(..) => try!(self.word_space("unsafe")),
- ast::DefaultBlock | ast::PopUnsafeBlock(..) => ()
+ ast::UnsafeBlock(..) => try!(self.word_space("unsafe")),
+ ast::DefaultBlock => ()
}
try!(self.maybe_print_comment(blk.span.lo));
try!(self.ann.pre(self, NodeBlock(blk)));
use ast_util;
use codemap;
use parse::token;
+ use ptr::P;
#[test]
fn test_fun_to_string() {
name: ident,
attrs: Vec::new(),
// making this up as I go.... ?
- kind: ast::TupleVariantKind(Vec::new()),
- id: 0,
+ data: P(ast::VariantData::Unit(ast::DUMMY_NODE_ID)),
disr_expr: None,
});
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
walk_poly_trait_ref(self, t, m)
}
- fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) {
+ fn visit_variant_data(&mut self, s: &'v VariantData, _: Ident,
+ _: &'v Generics, _: NodeId, _: Span) {
walk_struct_def(self, s)
}
fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) }
fn visit_enum_def(&mut self, enum_definition: &'v EnumDef,
- generics: &'v Generics) {
- walk_enum_def(self, enum_definition, generics)
+ generics: &'v Generics, item_id: NodeId) {
+ walk_enum_def(self, enum_definition, generics, item_id)
+ }
+ fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) {
+ walk_variant(self, v, g, item_id)
}
-
- fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) }
-
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
walk_lifetime(self, lifetime)
}
}
ItemEnum(ref enum_definition, ref type_parameters) => {
visitor.visit_generics(type_parameters);
- visitor.visit_enum_def(enum_definition, type_parameters)
+ visitor.visit_enum_def(enum_definition, type_parameters, item.id)
}
ItemDefaultImpl(_, ref trait_ref) => {
visitor.visit_trait_ref(trait_ref)
}
ItemStruct(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
- visitor.visit_struct_def(struct_definition,
- item.ident,
- generics,
- item.id)
+ visitor.visit_variant_data(struct_definition, item.ident,
+ generics, item.id, item.span);
}
ItemTrait(_, ref generics, ref bounds, ref methods) => {
visitor.visit_generics(generics);
pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
enum_definition: &'v EnumDef,
- generics: &'v Generics) {
+ generics: &'v Generics,
+ item_id: NodeId) {
for variant in &enum_definition.variants {
- visitor.visit_variant(variant, generics);
+ visitor.visit_variant(variant, generics, item_id);
}
}
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
variant: &'v Variant,
- generics: &'v Generics) {
+ generics: &'v Generics,
+ item_id: NodeId) {
visitor.visit_ident(variant.span, variant.node.name);
-
- match variant.node.kind {
- TupleVariantKind(ref variant_arguments) => {
- for variant_argument in variant_arguments {
- visitor.visit_ty(&variant_argument.ty)
- }
- }
- StructVariantKind(ref struct_definition) => {
- visitor.visit_struct_def(struct_definition,
- variant.node.name,
- generics,
- variant.node.id)
- }
- }
+ visitor.visit_variant_data(&variant.node.data, variant.node.name,
+ generics, item_id, variant.span);
walk_list!(visitor, visit_expr, &variant.node.disr_expr);
walk_list!(visitor, visit_attribute, &variant.node.attrs);
}
}
pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V,
- struct_definition: &'v StructDef) {
- walk_list!(visitor, visit_struct_field, &struct_definition.fields);
+ struct_definition: &'v VariantData) {
+ walk_list!(visitor, visit_struct_field, struct_definition.fields());
}
pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V,
uint64_t get_z(struct S s) {
return s.z;
}
+
+uint64_t get_c_many_params(void *a, void *b, void *c, void *d, struct quad f) {
+ return f.c;
+}
LLVMTargetMachineRef TMR) {
TargetMachine *Target = unwrap(TMR);
#if LLVM_VERSION_MINOR >= 7
- if (const DataLayout *DL = Target->getDataLayout())
- unwrap(Module)->setDataLayout(*DL);
+ unwrap(Module)->setDataLayout(Target->createDataLayout());
#elif LLVM_VERSION_MINOR >= 6
if (const DataLayout *DL = Target->getSubtargetImpl()->getDataLayout())
unwrap(Module)->setDataLayout(DL);
offset_momentum(&mut bodies);
println!("{:.9}", energy(&bodies));
- for _ in (0..n) {
+ for _ in 0..n {
advance(&mut bodies, 0.01, &mut diff, &mut mag);
}
let mut x = Int(0);
x += 1;
//~^ error: overloaded augmented assignments are not stable
- // | help: add #![feature(augmented_assignments)] to the crate features to enable
+ // | help: add #![feature(augmented_assignments)] to the crate root to enable
}
let mut x = Int(0);
x += 1;
//~^ error: overloaded augmented assignments are not stable
- // | help: add #![feature(augmented_assignments)] to the crate features to enable
+ // | help: add #![feature(augmented_assignments)] to the crate root to enable
}
#[derive(FromPrimitive)]
enum C { Foo(isize), Bar(usize) }
-//~^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments
-//~^^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments
+//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
+//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
#[derive(FromPrimitive)]
enum D { Baz { x: isize } }
-//~^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants
-//~^^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants
+//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
+//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
pub fn main() {}
--- /dev/null
+// 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.
+
+// Can't use empty braced struct as constant or constructor function
+
+#![feature(braced_empty_structs)]
+
+struct Empty1 {}
+
+enum E {
+ Empty2 {}
+}
+
+fn main() {
+ let e1 = Empty1; //~ ERROR `Empty1` is the name of a struct or struct variant
+ let e1 = Empty1(); //~ ERROR `Empty1` is the name of a struct or struct variant
+ let e2 = E::Empty2; //~ ERROR `E::Empty2` is the name of a struct or struct variant
+ let e2 = E::Empty2(); //~ ERROR `E::Empty2` is the name of a struct or struct variant
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Feature gate test for empty struct with braces
+// Can't define an empty braced struct
+
+struct Empty1 {} //~ ERROR empty structs and enum variants with braces are unstable
+struct Empty2;
+
+enum E {
+ Empty4 {}, //~ ERROR empty structs and enum variants with braces are unstable
+ Empty5,
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Feature gate test for empty struct with braces
+// Can't use braced expressions and patterns with structs defined without braces
+
+struct Empty2;
+
+enum E {
+ Empty5,
+}
+
+fn main() {
+ let e2: Empty2 = Empty2 {}; //~ ERROR empty structs and enum variants with braces are unstable
+ let e2: Empty2 = Empty2;
+ // Issue #28692
+ // let e5: E = E::Empty5 {}; // ERROR empty structs and enum variants with braces are unstable
+ let e5: E = E::Empty5;
+
+ match e2 {
+ Empty2 {} => {} //~ ERROR empty structs and enum variants with braces are unstable
+ }
+ match e2 {
+ Empty2 => {}
+ }
+ match e2 {
+ Empty2 { .. } => {} //~ ERROR empty structs and enum variants with braces are unstable
+ }
+ // Issue #28692
+ // match e5 {
+ // E::Empty5 {} => {} // ERROR empty structs and enum variants with braces are unstable
+ // }
+ match e5 {
+ E::Empty5 => {}
+ }
+ // Issue #28692
+ // match e5 {
+ // E::Empty5 { .. } => {} // ERROR empty structs and enum variants with braces are unstable
+ // }
+
+ let e22 = Empty2 { ..e2 }; //~ ERROR empty structs and enum variants with braces are unstable
+}
--- /dev/null
+// 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.
+
+// Can't use empty braced struct as constant pattern
+
+#![deny(warnings)]
+#![feature(braced_empty_structs)]
+
+struct Empty1 {}
+
+enum E {
+ Empty2 {}
+}
+
+fn main() {
+ let e1 = Empty1 {};
+ let e2 = E::Empty2 {};
+
+ // Issue #28692
+ // match e1 {
+ // Empty1 => () // ERROR incorrect error
+ // }
+ match e2 {
+ E::Empty2 => () //~ ERROR `E::Empty2` does not name a non-struct variant or a tuple struct
+ }
+}
--- /dev/null
+// 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.
+
+// Can't use empty braced struct as enum pattern
+
+#![feature(braced_empty_structs)]
+
+struct Empty1 {}
+
+enum E {
+ Empty2 {}
+}
+
+fn main() {
+ let e1 = Empty1 {};
+ let e2 = E::Empty2 {};
+
+ // Rejected by parser as yet
+ // match e1 {
+ // Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1`
+ // }
+ match e1 {
+ Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1`
+ }
+ // Issue #28692
+ // match e2 {
+ // E::Empty2() => () // ERROR unresolved enum variant, struct or const `Empty2`
+ // }
+ // match e2 {
+ // E::Empty2(..) => () // ERROR unresolved enum variant, struct or const `Empty2`
+ // }
+}
--- /dev/null
+// 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.
+
+// Can't use unit struct as constructor function
+
+#![feature(braced_empty_structs)]
+
+struct Empty1;
+
+enum E {
+ Empty2
+}
+
+fn main() {
+ let e1 = Empty1(); //~ ERROR expected function, found `Empty1`
+ let e2 = E::Empty2(); //~ ERROR expected function, found `E`
+}
--- /dev/null
+// 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.
+
+// Can't use unit struct as enum pattern
+
+#![feature(braced_empty_structs)]
+
+FIXME //~ ERROR expected item, found `FIXME`
+
+struct Empty1;
+
+enum E {
+ Empty2
+}
+
+fn main() {
+ let e1 = Empty1;
+ let e2 = E::Empty2;
+
+ // Issue #28692
+ // match e1 {
+ // Empty1() => () // ERROR variable `Empty1` should have a snake case name
+ // }
+ // match e1 {
+ // Empty1(..) => () // ERROR variable `Empty1` should have a snake case name
+ // }
+ // match e2 {
+ // E::Empty2() => () // ERROR variable `Empty2` should have a snake case name
+ // }
+ // match e2 {
+ // E::Empty2(..) => () // ERROR variable `Empty2` should have a snake case name
+ // }
+}
+++ /dev/null
-// 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.
-
-// Empty struct defined with braces shouldn't add names into value namespace
-
-#![feature(braced_empty_structs)]
-
-struct Empty {}
-
-fn main() {
- let e = Empty; //~ ERROR `Empty` is the name of a struct or struct variant
-}
+++ /dev/null
-// 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.
-
-// Empty struct defined with braces shouldn't add names into value namespace
-
-#![feature(braced_empty_structs)]
-#![deny(warnings)]
-
-struct Empty {}
-
-fn main() {
- let e = Empty {};
-
- match e {
- Empty => () //~ ERROR unused variable: `Empty`
- //~^ ERROR variable `Empty` should have a snake case name such as `empty`
- }
-}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Feature gate test for empty struct with braces
-
-struct Empty {} //~ ERROR empty structs with braces are unstable
-
-fn main() {
- let e = Empty {}; //~ ERROR empty structs with braces are unstable
-
- match e {
- Empty {} => {} //~ ERROR empty structs with braces are unstable
- }
-}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- let c = push_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental
- let c = pop_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental
-}
--- /dev/null
+// 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.
+
+struct TS ( //~ ERROR empty tuple structs and enum variants are not allowed
+ #[cfg(untrue)]
+ int,
+);
+
+fn main() {
+ let s = S;
+}
let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
let x = Bar;
- Bar { ..x };
- let Bar { .. } = x;
+ Bar { ..x }; //~ ERROR empty structs and enum variants with braces are unstable
+ let Bar { .. } = x; //~ ERROR empty structs and enum variants with braces are unstable
match Enum::Bar {
Enum::Bar { .. } //~ ERROR `Enum::Bar` does not name a struct
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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.
-
-// Basic sanity check for `push_unsafe!(EXPR)` and
-// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a
-// positive number of pushes in the stack, or if we are within a
-// normal `unsafe` block, but otherwise cannot.
-
-#![feature(pushpop_unsafe)]
-
-static mut X: i32 = 0;
-
-unsafe fn f() { X += 1; return; }
-fn g() { unsafe { X += 1_000; } return; }
-
-fn main() {
- push_unsafe!( {
- f(); pop_unsafe!({
- f() //~ ERROR: call to unsafe function
- })
- } );
-
- push_unsafe!({
- f();
- pop_unsafe!({
- g();
- f(); //~ ERROR: call to unsafe function
- })
- } );
-
- push_unsafe!({
- g(); pop_unsafe!({
- unsafe {
- f();
- }
- f(); //~ ERROR: call to unsafe function
- })
- });
-
-
- // Note: For implementation simplicity the compiler just
- // ICE's if you underflow the push_unsafe stack.
- //
- // Thus all of the following cases cause an ICE.
- //
- // (The "ERROR" notes are from an earlier version
- // that used saturated arithmetic rather than checked
- // arithmetic.)
-
- // pop_unsafe!{ g() };
- //
- // push_unsafe!({
- // pop_unsafe!(pop_unsafe!{ g() })
- // });
- //
- // push_unsafe!({
- // g();
- // pop_unsafe!(pop_unsafe!({
- // f() // ERROR: call to unsafe function
- // }))
- // });
- //
- // pop_unsafe!({
- // f(); // ERROR: call to unsafe function
- // })
-
-}
--- /dev/null
+// 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.
+
+struct Foo(); //~ ERROR empty tuple structs and enum variants are not allowed
+
+fn main() {}
--- /dev/null
+// 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.
+
+// A quick test of 'unsafe const fn' functionality
+
+#![feature(const_fn)]
+
+unsafe const fn dummy(v: u32) -> u32 {
+ !v
+}
+
+const VAL: u32 = dummy(0xFFFF); //~ ERROR E0133
+
+fn main() {
+ assert_eq!(VAL, 0xFFFF0000);
+}
+
+++ /dev/null
-// 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.
-
-// compile-flags: -Z parse-only
-
-struct Foo(); //~ ERROR unit-like struct definition should be written as `struct Foo;`
-
-fn main() {}
+++ /dev/null
-// 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.
-
-// compile-flags: -Z parse-only
-
-enum Foo {
- Bar {} //~ ERROR unit-like struct variant should be written without braces, as `Bar,`
-}
--- /dev/null
+-include ../tools.mk
+
+all: $(call NATIVE_STATICLIB,test)
+ $(RUSTC) test.rs
+ $(call RUN,test) || exit 1
--- /dev/null
+// 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.
+
+#include <assert.h>
+#include <stdint.h>
+
+struct Rect {
+ int32_t a;
+ int32_t b;
+ int32_t c;
+ int32_t d;
+};
+
+struct BiggerRect {
+ struct Rect s;
+ int32_t a;
+ int32_t b;
+};
+
+struct FloatRect {
+ int32_t a;
+ int32_t b;
+ double c;
+};
+
+struct Huge {
+ int32_t a;
+ int32_t b;
+ int32_t c;
+ int32_t d;
+ int32_t e;
+};
+
+// System V x86_64 ABI:
+// a, b, c, d, e should be in registers
+// s should be byval pointer
+//
+// Win64 ABI:
+// a, b, c, d should be in registers
+// e should be on the stack
+// s should be byval pointer
+void byval_rect(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3);
+ assert(d == 4);
+ assert(e == 5);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 ABI:
+// a, b, c, d, e, f, g should be in sse registers
+// s should be split across 2 registers
+// t should be byval pointer
+//
+// Win64 ABI:
+// a, b, c, d should be in sse registers
+// e, f, g should be on the stack
+// s should be on the stack (treated as 2 i64's)
+// t should be on the stack (treated as an i64 and a double)
+void byval_rect_floats(float a, float b, double c, float d, float e,
+ float f, double g, struct Rect s, struct FloatRect t) {
+ assert(a == 1.);
+ assert(b == 2.);
+ assert(c == 3.);
+ assert(d == 4.);
+ assert(e == 5.);
+ assert(f == 6.);
+ assert(g == 7.);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+ assert(t.a == 3489);
+ assert(t.b == 3490);
+ assert(t.c == 8.);
+}
+
+// System V x86_64 ABI:
+// a, b, d, e, f should be in registers
+// c passed via sse registers
+// s should be byval pointer
+//
+// Win64 ABI:
+// a, b, d should be in registers
+// c passed via sse registers
+// e, f should be on the stack
+// s should be byval pointer
+void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d,
+ int32_t e, int32_t f, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3.);
+ assert(d == 4);
+ assert(e == 5);
+ assert(f == 6);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b should be in registers
+// s should be split across 2 integer registers
+void split_rect(int32_t a, int32_t b, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b should be in sse registers
+// s should be split across integer & sse registers
+void split_rect_floats(float a, float b, struct FloatRect s) {
+ assert(a == 1.);
+ assert(b == 2.);
+ assert(s.a == 3489);
+ assert(s.b == 3490);
+ assert(s.c == 8.);
+}
+
+// System V x86_64 ABI:
+// a, b, d, f should be in registers
+// c, e passed via sse registers
+// s should be split across 2 registers
+//
+// Win64 ABI:
+// a, b, d should be in registers
+// c passed via sse registers
+// e, f should be on the stack
+// s should be on the stack (treated as 2 i64's)
+void split_rect_with_floats(int32_t a, int32_t b, float c,
+ int32_t d, float e, int32_t f, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3.);
+ assert(d == 4);
+ assert(e == 5.);
+ assert(f == 6);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b, c should be in registers
+// s should be split across 2 registers
+// t should be a byval pointer
+void split_and_byval_rect(int32_t a, int32_t b, int32_t c, struct Rect s, struct Rect t) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+ assert(t.a == 553);
+ assert(t.b == 554);
+ assert(t.c == 555);
+ assert(t.d == 556);
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b should in registers
+// s and return should be split across 2 registers
+struct Rect split_ret_byval_struct(int32_t a, int32_t b, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+ return s;
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b, c, d should be in registers
+// return should be in a hidden sret pointer
+// s should be a byval pointer
+struct BiggerRect sret_byval_struct(int32_t a, int32_t b, int32_t c, int32_t d, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3);
+ assert(d == 4);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+
+ struct BiggerRect t;
+ t.s = s; t.a = 27834; t.b = 7657;
+ return t;
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b should be in registers
+// return should be in a hidden sret pointer
+// s should be split across 2 registers
+struct BiggerRect sret_split_struct(int32_t a, int32_t b, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+
+ struct BiggerRect t;
+ t.s = s; t.a = 27834; t.b = 7657;
+ return t;
+}
+
+// System V x86_64 & Win64 ABI:
+// s should be byval pointer (since sizeof(s) > 16)
+// return should in a hidden sret pointer
+struct Huge huge_struct(struct Huge s) {
+ assert(s.a == 5647);
+ assert(s.b == 5648);
+ assert(s.c == 5649);
+ assert(s.d == 5650);
+ assert(s.e == 5651);
+
+ return s;
+}
--- /dev/null
+// 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.
+
+// Passing structs via FFI should work regardless of whether
+// they get passed in multiple registers, byval pointers or the stack
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct Rect {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct BiggerRect {
+ s: Rect,
+ a: i32,
+ b: i32
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct FloatRect {
+ a: i32,
+ b: i32,
+ c: f64
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct Huge {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32
+}
+
+#[link(name = "test", kind = "static")]
+extern {
+ fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);
+
+ fn byval_rect_floats(a: f32, b: f32, c: f64, d: f32, e: f32,
+ f: f32, g: f64, s: Rect, t: FloatRect);
+
+ fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect);
+
+ fn split_rect(a: i32, b: i32, s: Rect);
+
+ fn split_rect_floats(a: f32, b: f32, s: FloatRect);
+
+ fn split_rect_with_floats(a: i32, b: i32, c: f32, d: i32, e: f32, f: i32, s: Rect);
+
+ fn split_and_byval_rect(a: i32, b: i32, c: i32, s: Rect, t: Rect);
+
+ fn split_ret_byval_struct(a: i32, b: i32, s: Rect) -> Rect;
+
+ fn sret_byval_struct(a: i32, b: i32, c: i32, d: i32, s: Rect) -> BiggerRect;
+
+ fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect;
+
+ fn huge_struct(s: Huge) -> Huge;
+}
+
+fn main() {
+ let s = Rect { a: 553, b: 554, c: 555, d: 556 };
+ let t = BiggerRect { s: s, a: 27834, b: 7657 };
+ let u = FloatRect { a: 3489, b: 3490, c: 8. };
+ let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
+
+ unsafe {
+ byval_rect(1, 2, 3, 4, 5, s);
+ byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u);
+ byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s);
+ split_rect(1, 2, s);
+ split_rect_floats(1., 2., u);
+ split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s);
+ split_and_byval_rect(1, 2, 3, s, s);
+ split_rect(1, 2, s);
+ assert_eq!(huge_struct(v), v);
+ assert_eq!(split_ret_byval_struct(1, 2, s), s);
+ assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
+ assert_eq!(sret_split_struct(1, 2, s), t);
+ }
+}
--- /dev/null
+// 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.
+
+// Empty struct defined with braces add names into type namespace
+// Empty struct defined without braces add names into both type and value namespaces
+
+#![feature(braced_empty_structs)]
+
+struct Empty1 {}
+struct Empty2;
+struct Empty3 {}
+const Empty3: Empty3 = Empty3 {};
+
+enum E {
+ Empty4 {},
+ Empty5,
+}
+
+fn main() {
+ let e1: Empty1 = Empty1 {};
+ let e2: Empty2 = Empty2 {};
+ let e2: Empty2 = Empty2;
+ let e3: Empty3 = Empty3 {};
+ let e3: Empty3 = Empty3;
+ let e4: E = E::Empty4 {};
+ // let e5: E = E::Empty5 {}; // Issue #28692
+ let e5: E = E::Empty5;
+
+ match e1 {
+ Empty1 {} => {}
+ }
+ match e2 {
+ Empty2 {} => {}
+ }
+ match e3 {
+ Empty3 {} => {}
+ }
+ match e4 {
+ E::Empty4 {} => {}
+ _ => {}
+ }
+ // Issue #28692
+ // match e5 {
+ // E::Empty5 {} => {}
+ // _ => {}
+ // }
+
+ match e1 {
+ Empty1 { .. } => {}
+ }
+ match e2 {
+ Empty2 { .. } => {}
+ }
+ match e3 {
+ Empty3 { .. } => {}
+ }
+ match e4 {
+ E::Empty4 { .. } => {}
+ _ => {}
+ }
+ // Issue #28692
+ // match e5 {
+ // E::Empty5 { .. } => {}
+ // _ => {}
+ // }
+
+ match e2 {
+ Empty2 => {}
+ }
+ match e3 {
+ Empty3 => {}
+ }
+ match e5 {
+ E::Empty5 => {}
+ _ => {}
+ }
+
+ let e11: Empty1 = Empty1 { ..e1 };
+ let e22: Empty2 = Empty2 { ..e2 };
+ let e33: Empty3 = Empty3 { ..e3 };
+}
+++ /dev/null
-// 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.
-
-// Empty struct defined with braces add names into type namespace
-// Empty struct defined without braces add names into both type and value namespaces
-
-#![feature(braced_empty_structs)]
-
-struct Empty1 {}
-struct Empty2;
-struct Empty3 {}
-const Empty3: Empty3 = Empty3 {};
-
-fn main() {
- let e1: Empty1 = Empty1 {};
- let e2: Empty2 = Empty2 {};
- let e2: Empty2 = Empty2;
- let e3: Empty3 = Empty3 {};
- let e3: Empty3 = Empty3;
-
- match e1 {
- Empty1 {} => ()
- }
- match e2 {
- Empty2 {} => ()
- }
- match e2 {
- Empty2 => ()
- }
- match e3 {
- Empty3 {} => ()
- }
- match e3 {
- Empty3 => ()
- }
- match e1 {
- Empty1 { .. } => ()
- }
- match e2 {
- Empty2 { .. } => ()
- }
- match e3 {
- Empty3 { .. } => ()
- }
-
- let e11 = Empty1 { ..e1 };
- let e22 = Empty2 { ..e2 };
- let e33 = Empty3 { ..e3 };
-}
--- /dev/null
+// 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.
+
+#[allow(dead_code)]
+fn check(a: &str) {
+ let x = a as *const str;
+ x == x;
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Test {}
+
+macro_rules! test {
+( $($name:ident)+) => (
+ impl<$($name: Test),*> Test for ($($name,)*) {
+ }
+)
+}
+
+test!(A B C);
+
+fn main() {}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+//
+
+#[derive(Copy, Clone)]
+pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
+
+mod rustrt {
+ use super::Quad;
+
+ #[link(name = "rust_test_helpers")]
+ extern {
+ pub fn get_c_many_params(_: *const (), _: *const (),
+ _: *const (), _: *const (), f: Quad) -> u64;
+ }
+}
+
+fn test() {
+ unsafe {
+ let null = std::ptr::null();
+ let q = Quad {
+ a: 1,
+ b: 2,
+ c: 3,
+ d: 4
+ };
+ assert_eq!(rustrt::get_c_many_params(null, null, null, null, q), q.c);
+ }
+}
+
+pub fn main() {
+ test();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Test { type T; }
+
+impl Test for u32 {
+ type T = i32;
+}
+
+pub mod export {
+ #[no_mangle]
+ pub extern "C" fn issue_28983(t: <u32 as ::Test>::T) -> i32 { t*3 }
+}
+
+// to test both exporting and importing functions, import
+// a function from ourselves.
+extern "C" {
+ fn issue_28983(t: <u32 as Test>::T) -> i32;
+}
+
+fn main() {
+ assert_eq!(export::issue_28983(2), 6);
+ assert_eq!(unsafe { issue_28983(3) }, 9);
+}
--- /dev/null
+// 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.
+
+pub struct Xyz<'a, V> {
+ pub v: (V, &'a u32),
+}
+
+pub fn eq<'a, 's, 't, V>(this: &'s Xyz<'a, V>, other: &'t Xyz<'a, V>) -> bool
+ where V: PartialEq {
+ this.v == other.v
+}
+
+fn main() {}
+++ /dev/null
-// 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.
-
-// Basic sanity check for `push_unsafe!(EXPR)` and
-// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a
-// positive number of pushes in the stack, or if we are within a
-// normal `unsafe` block, but otherwise cannot.
-
-// ignore-pretty because the `push_unsafe!` and `pop_unsafe!` macros
-// are not integrated with the pretty-printer.
-
-#![feature(pushpop_unsafe)]
-
-static mut X: i32 = 0;
-
-unsafe fn f() { X += 1; return; }
-fn g() { unsafe { X += 1_000; } return; }
-
-fn check_reset_x(x: i32) -> bool {
- #![allow(unused_parens)] // dont you judge my style choices!
- unsafe {
- let ret = (x == X);
- X = 0;
- ret
- }
-}
-
-fn main() {
- // double-check test infrastructure
- assert!(check_reset_x(0));
- unsafe { f(); }
- assert!(check_reset_x(1));
- assert!(check_reset_x(0));
- { g(); }
- assert!(check_reset_x(1000));
- assert!(check_reset_x(0));
- unsafe { f(); g(); g(); }
- assert!(check_reset_x(2001));
-
- push_unsafe!( { f(); pop_unsafe!( g() ) } );
- assert!(check_reset_x(1_001));
- push_unsafe!( { g(); pop_unsafe!( unsafe { f(); f(); } ) } );
- assert!(check_reset_x(1_002));
-
- unsafe { push_unsafe!( { f(); pop_unsafe!( { f(); f(); } ) } ); }
- assert!(check_reset_x(3));
- push_unsafe!( { f(); push_unsafe!( { pop_unsafe!( { f(); f(); f(); } ) } ); } );
- assert!(check_reset_x(4));
-}
--- /dev/null
+// 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.
+
+// A quick test of 'unsafe const fn' functionality
+
+#![feature(const_fn)]
+
+unsafe const fn dummy(v: u32) -> u32 {
+ !v
+}
+
+struct Type;
+impl Type {
+ unsafe const fn new() -> Type {
+ Type
+ }
+}
+
+const VAL: u32 = unsafe { dummy(0xFFFF) };
+const TYPE_INST: Type = unsafe { Type::new() };
+
+fn main() {
+ assert_eq!(VAL, 0xFFFF0000);
+}