Merge branch 'master' into mulit-decor

This commit is contained in:
Nick Cameron 2015-04-30 22:30:50 +12:00
commit b2ddd937b2
488 changed files with 12552 additions and 7327 deletions

View file

@ -170,6 +170,9 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
format!("ignore-{}",
config.stage_id.split('-').next().unwrap())
}
fn ignore_env(config: &Config) -> String {
format!("ignore-{}", util::get_env(&config.target).unwrap_or("<unknown>"))
}
fn ignore_gdb(config: &Config, line: &str) -> bool {
if config.mode != common::DebugInfoGdb {
return false;
@ -231,6 +234,7 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
!parse_name_directive(ln, &ignore_target(config)) &&
!parse_name_directive(ln, &ignore_architecture(config)) &&
!parse_name_directive(ln, &ignore_stage(config)) &&
!parse_name_directive(ln, &ignore_env(config)) &&
!(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
!(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
!ignore_gdb(config, ln) &&

View file

@ -1233,7 +1233,20 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
let mut crate_type = if aux_props.no_prefer_dynamic {
Vec::new()
} else {
vec!("--crate-type=dylib".to_string())
// We primarily compile all auxiliary libraries as dynamic libraries
// to avoid code size bloat and large binaries as much as possible
// for the test suite (otherwise including libstd statically in all
// executables takes up quite a bit of space).
//
// For targets like MUSL, however, there is no support for dynamic
// libraries so we just go back to building a normal library. Note,
// however, that if the library is built with `force_host` then it's
// ok to be a dylib as the host should always support dylibs.
if config.target.contains("musl") && !aux_props.force_host {
vec!("--crate-type=lib".to_string())
} else {
vec!("--crate-type=dylib".to_string())
}
};
crate_type.extend(extra_link_args.clone().into_iter());
let aux_args =

View file

@ -60,6 +60,10 @@ pub fn get_arch(triple: &str) -> &'static str {
panic!("Cannot determine Architecture from triple");
}
pub fn get_env(triple: &str) -> Option<&str> {
triple.split('-').nth(3)
}
pub fn make_new_path(path: &str) -> String {
assert!(cfg!(windows));
// Windows just uses PATH as the library search path, so we have to

View file

@ -96,12 +96,16 @@ explicit codepoint lists. [^inputformat]
## Special Unicode Productions
The following productions in the Rust grammar are defined in terms of Unicode
properties: `ident`, `non_null`, `non_star`, `non_eol`, `non_slash_or_star`,
`non_single_quote` and `non_double_quote`.
properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and
`non_double_quote`.
### Identifiers
The `ident` production is any nonempty Unicode string of the following form:
The `ident` production is any nonempty Unicode[^non_ascii_idents] string of
the following form:
[^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature
gated. This is expected to improve soon.
- The first character has property `XID_start`
- The remaining characters have property `XID_continue`
@ -118,8 +122,6 @@ Some productions are defined by exclusion of particular Unicode characters:
- `non_null` is any single Unicode character aside from `U+0000` (null)
- `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`)
- `non_star` is `non_null` restricted to exclude `U+002A` (`*`)
- `non_slash_or_star` is `non_null` restricted to exclude `U+002F` (`/`) and `U+002A` (`*`)
- `non_single_quote` is `non_null` restricted to exclude `U+0027` (`'`)
- `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`)
@ -152,19 +154,19 @@ token : simple_token | ident | literal | symbol | whitespace token ;
<p id="keyword-table-marker"></p>
| | | | | |
|----------|----------|----------|----------|--------|
| abstract | alignof | as | become | box |
| break | const | continue | crate | do |
| else | enum | extern | false | final |
| fn | for | if | impl | in |
| let | loop | match | mod | move |
| mut | offsetof | once | override | priv |
| proc | pub | pure | ref | return |
| sizeof | static | self | struct | super |
| true | trait | type | typeof | unsafe |
| unsized | use | virtual | where | while |
| yield | | | | |
| | | | | |
|----------|----------|----------|----------|---------|
| abstract | alignof | as | become | box |
| break | const | continue | crate | do |
| else | enum | extern | false | final |
| fn | for | if | impl | in |
| let | loop | macro | match | mod |
| move | mut | offsetof | override | priv |
| proc | pub | pure | ref | return |
| Self | self | sizeof | static | struct |
| super | trait | true | type | typeof |
| unsafe | unsized | use | virtual | where |
| while | yield | | | |
Each of these keywords has special meaning in its grammar, and all of them are
@ -524,6 +526,15 @@ array_elems : [expr [',' expr]*] | [expr ',' ".." expr] ;
idx_expr : expr '[' expr ']' ;
```
### Range expressions
```antlr
range_expr : expr ".." expr |
expr ".." |
".." expr |
".." ;
```
### Unary operator expressions
**FIXME:** grammar?
@ -610,7 +621,7 @@ lambda_expr : '|' ident_list '|' expr ;
### While loops
```antlr
while_expr : "while" no_struct_literal_expr '{' block '}' ;
while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
```
### Infinite loops
@ -634,7 +645,7 @@ continue_expr : "continue" [ lifetime ];
### For expressions
```antlr
for_expr : "for" pat "in" no_struct_literal_expr '{' block '}' ;
for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
```
### If expressions

View file

@ -57,8 +57,12 @@ function populate_rust_search() {
// #18540, use a single token
var a = document.createElement("a");
a.href = "http://doc.rust-lang.org/core/?search=" + encodeURIComponent(lt);
a.textContent = lt;
var search = document.getElementById('core-search');
search.innerHTML = "<a href=\"http://doc.rust-lang.org/core/?search=" + lt + "\">" + lt + "</a>";
search.innerHTML = "";
search.appendChild(a);
}
populate_site_search();
populate_rust_search();

View file

@ -29,41 +29,6 @@ You may also be interested in the [grammar].
# Notation
Rust's grammar is defined over Unicode code points, each conventionally denoted
`U+XXXX`, for 4 or more hexadecimal digits `X`. _Most_ of Rust's grammar is
confined to the ASCII range of Unicode, and is described in this document by a
dialect of Extended Backus-Naur Form (EBNF), specifically a dialect of EBNF
supported by common automated LL(k) parsing tools such as `llgen`, rather than
the dialect given in ISO 14977. The dialect can be defined self-referentially
as follows:
```{.ebnf .notation}
grammar : rule + ;
rule : nonterminal ':' productionrule ';' ;
productionrule : production [ '|' production ] * ;
production : term * ;
term : element repeats ;
element : LITERAL | IDENTIFIER | '[' productionrule ']' ;
repeats : [ '*' | '+' ] NUMBER ? | NUMBER ? | '?' ;
```
Where:
- Whitespace in the grammar is ignored.
- Square brackets are used to group rules.
- `LITERAL` is a single printable ASCII character, or an escaped hexadecimal
ASCII code of the form `\xQQ`, in single quotes, denoting the corresponding
Unicode code point `U+00QQ`.
- `IDENTIFIER` is a nonempty string of ASCII letters and underscores.
- The `repeat` forms apply to the adjacent `element`, and are as follows:
- `?` means zero or one repetition
- `*` means zero or more repetitions
- `+` means one or more repetitions
- NUMBER trailing a repeat symbol gives a maximum repetition count
- NUMBER on its own gives an exact repetition count
This EBNF dialect should hopefully be familiar to many readers.
## Unicode productions
A few productions in Rust's grammar permit Unicode code points outside the ASCII
@ -100,15 +65,12 @@ explicit code point lists. [^inputformat]
provided to the grammar verifier, restricted to ASCII range, when verifying the
grammar in this document.
## Special Unicode Productions
## Identifiers
The following productions in the Rust grammar are defined in terms of Unicode
properties: `ident`, `non_null`, `non_star`, `non_eol`, `non_slash_or_star`,
`non_single_quote` and `non_double_quote`.
An identifier is any nonempty Unicode[^non_ascii_idents] string of the following form:
### Identifiers
The `ident` production is any nonempty Unicode string of the following form:
[^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature
gated. This is expected to improve soon.
- The first character has property `XID_start`
- The remaining characters have property `XID_continue`
@ -119,54 +81,34 @@ that does _not_ occur in the set of [keywords](#keywords).
> character ranges used to form the more familiar C and Java language-family
> identifiers.
### Delimiter-restricted productions
Some productions are defined by exclusion of particular Unicode characters:
- `non_null` is any single Unicode character aside from `U+0000` (null)
- `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`)
- `non_star` is `non_null` restricted to exclude `U+002A` (`*`)
- `non_slash_or_star` is `non_null` restricted to exclude `U+002F` (`/`) and `U+002A` (`*`)
- `non_single_quote` is `non_null` restricted to exclude `U+0027` (`'`)
- `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`)
## Comments
```{.ebnf .gram}
comment : block_comment | line_comment ;
block_comment : "/*" block_comment_body * "*/" ;
block_comment_body : [block_comment | character] * ;
line_comment : "//" non_eol * ;
```
Comments in Rust code follow the general C++ style of line and block-comment
forms. Nested block comments are supported.
Comments in Rust code follow the general C++ style of line (`//`) and
block (`/* ... */`) comment forms. Nested block comments are supported.
Line comments beginning with exactly _three_ slashes (`///`), and block
comments beginning with exactly one repeated asterisk in the block-open
sequence (`/**`), are interpreted as a special syntax for `doc`
[attributes](#attributes). That is, they are equivalent to writing
`#[doc="..."]` around the body of the comment (this includes the comment
characters themselves, i.e. `/// Foo` turns into `#[doc="/// Foo"]`).
`#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into
`#[doc="Foo"]`.
Line comments beginning with `//!` and block comments beginning with `/*!` are
doc comments that apply to the parent of the comment, rather than the item
that follows. That is, they are equivalent to writing `#![doc="..."]` around
the body of the comment. `//!` comments are usually used to display
information on the crate index page.
the body of the comment. `//!` comments are usually used to document
modules that occupy a source file.
Non-doc comments are interpreted as a form of whitespace.
## Whitespace
```{.ebnf .gram}
whitespace_char : '\x20' | '\x09' | '\x0a' | '\x0d' ;
whitespace : [ whitespace_char | comment ] + ;
```
Whitespace is any non-empty string containing only the following characters:
The `whitespace_char` production is any nonempty Unicode string consisting of
any of the following Unicode characters: `U+0020` (space, `' '`), `U+0009`
(tab, `'\t'`), `U+000A` (LF, `'\n'`), `U+000D` (CR, `'\r'`).
- `U+0020` (space, `' '`)
- `U+0009` (tab, `'\t'`)
- `U+000A` (LF, `'\n'`)
- `U+000D` (CR, `'\r'`)
Rust is a "free-form" language, meaning that all forms of whitespace serve only
to separate _tokens_ in the grammar, and have no semantic significance.
@ -176,41 +118,11 @@ with any other legal whitespace element, such as a single space character.
## Tokens
```{.ebnf .gram}
simple_token : keyword | unop | binop ;
token : simple_token | ident | literal | symbol | whitespace token ;
```
Tokens are primitive productions in the grammar defined by regular
(non-recursive) languages. "Simple" tokens are given in [string table
production](#string-table-productions) form, and occur in the rest of the
grammar as double-quoted strings. Other tokens have exact rules given.
### Keywords
<p id="keyword-table-marker"></p>
| | | | | |
|----------|----------|----------|----------|---------|
| abstract | alignof | as | become | box |
| break | const | continue | crate | do |
| else | enum | extern | false | final |
| fn | for | if | impl | in |
| let | loop | macro | match | mod |
| move | mut | offsetof | override | priv |
| proc | pub | pure | ref | return |
| Self | self | sizeof | static | struct |
| super | trait | true | type | typeof |
| unsafe | unsized | use | virtual | where |
| while | yield | | | |
Each of these keywords has special meaning in its grammar, and all of them are
excluded from the `ident` rule.
Note that some of these keywords are reserved, and do not currently do
anything.
### Literals
A literal is an expression consisting of a single token, rather than a sequence
@ -218,11 +130,6 @@ of tokens, that immediately and directly denotes the value it evaluates to,
rather than referring to it by name or some other evaluation rule. A literal is
a form of constant expression, so is evaluated (primarily) at compile time.
```{.ebnf .gram}
lit_suffix : ident;
literal : [ string_lit | char_lit | byte_string_lit | byte_lit | num_lit ] lit_suffix ?;
```
The optional suffix is only used for certain numeric literals, but is
reserved for future extension, that is, the above gives the lexical
grammar, but a Rust parser will reject everything but the 12 special
@ -275,32 +182,6 @@ cases mentioned in [Number literals](#number-literals) below.
#### Character and string literals
```{.ebnf .gram}
char_lit : '\x27' char_body '\x27' ;
string_lit : '"' string_body * '"' | 'r' raw_string ;
char_body : non_single_quote
| '\x5c' [ '\x27' | common_escape | unicode_escape ] ;
string_body : non_double_quote
| '\x5c' [ '\x22' | common_escape | unicode_escape ] ;
raw_string : '"' raw_string_body '"' | '#' raw_string '#' ;
common_escape : '\x5c'
| 'n' | 'r' | 't' | '0'
| 'x' hex_digit 2
unicode_escape : 'u' '{' hex_digit+ 6 '}';
hex_digit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
| 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
| dec_digit ;
oct_digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' ;
dec_digit : '0' | nonzero_dec ;
nonzero_dec: '1' | '2' | '3' | '4'
| '5' | '6' | '7' | '8' | '9' ;
```
##### Character literals
A _character literal_ is a single Unicode character enclosed within two
@ -311,13 +192,13 @@ which must be _escaped_ by a preceding `U+005C` character (`\`).
A _string literal_ is a sequence of any Unicode characters enclosed within two
`U+0022` (double-quote) characters, with the exception of `U+0022` itself,
which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw
string literal_.
which must be _escaped_ by a preceding `U+005C` character (`\`).
A multi-line string literal may be defined by terminating each line with a
`U+005C` character (`\`) immediately before the newline. This causes the
`U+005C` character, the newline, and all whitespace at the beginning of the
next line to be ignored.
Line-break characters are allowed in string literals. Normally they represent
themselves (i.e. no translation), but as a special exception, when a `U+005C`
character (`\`) occurs immediately before the newline, the `U+005C` character,
the newline, and all whitespace at the beginning of the next line are ignored.
Thus `a` and `b` are equal:
```rust
let a = "foobar";
@ -349,11 +230,10 @@ following forms:
Raw string literals do not process any escapes. They start with the character
`U+0072` (`r`), followed by zero or more of the character `U+0023` (`#`) and a
`U+0022` (double-quote) character. The _raw string body_ is not defined in the
EBNF grammar above: it can contain any sequence of Unicode characters and is
terminated only by another `U+0022` (double-quote) character, followed by the
same number of `U+0023` (`#`) characters that preceded the opening `U+0022`
(double-quote) character.
`U+0022` (double-quote) character. The _raw string body_ can contain any sequence
of Unicode characters and is terminated only by another `U+0022` (double-quote)
character, followed by the same number of `U+0023` (`#`) characters that preceded
the opening `U+0022` (double-quote) character.
All Unicode characters contained in the raw string body represent themselves,
the characters `U+0022` (double-quote) (except when followed by at least as
@ -375,26 +255,14 @@ r##"foo #"# bar"##; // foo #"# bar
#### Byte and byte string literals
```{.ebnf .gram}
byte_lit : "b\x27" byte_body '\x27' ;
byte_string_lit : "b\x22" string_body * '\x22' | "br" raw_byte_string ;
byte_body : ascii_non_single_quote
| '\x5c' [ '\x27' | common_escape ] ;
byte_string_body : ascii_non_double_quote
| '\x5c' [ '\x22' | common_escape ] ;
raw_byte_string : '"' raw_byte_string_body '"' | '#' raw_byte_string '#' ;
```
##### Byte literals
A _byte literal_ is a single ASCII character (in the `U+0000` to `U+007F`
range) enclosed within two `U+0027` (single-quote) characters, with the
exception of `U+0027` itself, which must be _escaped_ by a preceding U+005C
character (`\`), or a single _escape_. It is equivalent to a `u8` unsigned
8-bit integer _number literal_.
range) or a single _escape_ preceded by the characters `U+0062` (`b`) and
`U+0027` (single-quote), and followed by the character `U+0027`. If the character
`U+0027` is present within the literal, it must be _escaped_ by a preceding
`U+005C` (`\`) character. It is equivalent to a `u8` unsigned 8-bit integer
_number literal_.
##### Byte string literals
@ -403,7 +271,7 @@ preceded by the characters `U+0062` (`b`) and `U+0022` (double-quote), and
followed by the character `U+0022`. If the character `U+0022` is present within
the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character.
Alternatively, a byte string literal can be a _raw byte string literal_, defined
below. A byte string literal is equivalent to a `&'static [u8]` borrowed array
below. A byte string literal of length `n` is equivalent to a `&'static [u8; n]` borrowed fixed-sized array
of unsigned 8-bit integers.
Some additional _escapes_ are available in either byte or non-raw byte string
@ -424,11 +292,10 @@ following forms:
Raw byte string literals do not process any escapes. They start with the
character `U+0062` (`b`), followed by `U+0072` (`r`), followed by zero or more
of the character `U+0023` (`#`), and a `U+0022` (double-quote) character. The
_raw string body_ is not defined in the EBNF grammar above: it can contain any
sequence of ASCII characters and is terminated only by another `U+0022`
(double-quote) character, followed by the same number of `U+0023` (`#`)
characters that preceded the opening `U+0022` (double-quote) character. A raw
byte string literal can not contain any non-ASCII byte.
_raw string body_ can contain any sequence of ASCII characters and is terminated
only by another `U+0022` (double-quote) character, followed by the same number of
`U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote)
character. A raw byte string literal can not contain any non-ASCII byte.
All characters contained in the raw string body represent their ASCII encoding,
the characters `U+0022` (double-quote) (except when followed by at least as
@ -450,19 +317,6 @@ b"\\x52"; br"\x52"; // \x52
#### Number literals
```{.ebnf .gram}
num_lit : nonzero_dec [ dec_digit | '_' ] * float_suffix ?
| '0' [ [ dec_digit | '_' ] * float_suffix ?
| 'b' [ '1' | '0' | '_' ] +
| 'o' [ oct_digit | '_' ] +
| 'x' [ hex_digit | '_' ] + ] ;
float_suffix : [ exponent | '.' dec_lit exponent ? ] ? ;
exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ;
dec_lit : [ dec_digit | '_' ] + ;
```
A _number literal_ is either an _integer literal_ or a _floating-point
literal_. The grammar for recognizing the two kinds of literals is mixed.
@ -512,11 +366,19 @@ A _floating-point literal_ has one of two forms:
optionally followed by another decimal literal, with an optional _exponent_.
* A single _decimal literal_ followed by an _exponent_.
By default, a floating-point literal has a generic type, and, like integer
literals, the type must be uniquely determined from the context. There are two valid
Like integer literals, a floating-point literal may be followed by a
suffix, so long as the pre-suffix part does not end with `U+002E` (`.`).
The suffix forcibly sets the type of the literal. There are two valid
_floating-point suffixes_, `f32` and `f64` (the 32-bit and 64-bit floating point
types), which explicitly determine the type of the literal.
The type of an _unsuffixed_ floating-point literal is determined by type
inference. If a floating-point type can be _uniquely_ determined from the
surrounding program context, the unsuffixed floating-point literal has that type.
If the program context underconstrains the type, it defaults to double-precision `f64`;
if the program context overconstrains the type, it is considered a static type
error.
Examples of floating-point literals of various forms:
```
@ -540,12 +402,6 @@ The two values of the boolean type are written `true` and `false`.
### Symbols
```{.ebnf .gram}
symbol : "::" | "->"
| '#' | '[' | ']' | '(' | ')' | '{' | '}'
| ',' | ';' ;
```
Symbols are a general class of printable [token](#tokens) that play structural
roles in a variety of grammar productions. They are catalogued here for
completeness as the set of remaining miscellaneous printable tokens that do not
@ -555,16 +411,6 @@ operators](#binary-operator-expressions), or [keywords](#keywords).
## Paths
```{.ebnf .gram}
expr_path : [ "::" ] ident [ "::" expr_path_tail ] + ;
expr_path_tail : '<' type_expr [ ',' type_expr ] + '>'
| expr_path ;
type_path : ident [ type_path_tail ] + ;
type_path_tail : '<' type_expr [ ',' type_expr ] + '>'
| "::" type_path ;
```
A _path_ is a sequence of one or more path components _logically_ separated by
a namespace qualifier (`::`). If a path consists of only one component, it may
refer to either an [item](#items) or a [variable](#variables) in a local control
@ -660,19 +506,6 @@ Users of `rustc` can define new syntax extensions in two ways:
## Macros
```{.ebnf .gram}
expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ;
macro_rule : '(' matcher * ')' "=>" '(' transcriber * ')' ';' ;
matcher : '(' matcher * ')' | '[' matcher * ']'
| '{' matcher * '}' | '$' ident ':' ident
| '$' '(' matcher * ')' sep_token? [ '*' | '+' ]
| non_special_token ;
transcriber : '(' transcriber * ')' | '[' transcriber * ']'
| '{' transcriber * '}' | '$' ident
| '$' '(' transcriber * ')' sep_token? [ '*' | '+' ]
| non_special_token ;
```
`macro_rules` allows users to define syntax extension in a declarative way. We
call such extensions "macros by example" or simply "macros" — to be distinguished
from the "procedural macros" defined in [compiler plugins][plugin].
@ -811,12 +644,6 @@ Crates contain [items](#items), each of which may have some number of
## Items
```{.ebnf .gram}
item : extern_crate_decl | use_decl | mod_item | fn_item | type_item
| struct_item | enum_item | static_item | trait_item | impl_item
| extern_block ;
```
An _item_ is a component of a crate. Items are organized within a crate by a
nested set of [modules](#modules). Every crate has a single "outermost"
anonymous module; all further items within the crate have [paths](#paths)
@ -863,11 +690,6 @@ no notion of type abstraction: there are no first-class "forall" types.
### Modules
```{.ebnf .gram}
mod_item : "mod" ident ( ';' | '{' mod '}' );
mod : item * ;
```
A module is a container for zero or more [items](#items).
A _module item_ is a module, surrounded in braces, named, and prefixed with the
@ -928,11 +750,6 @@ mod thread {
##### Extern crate declarations
```{.ebnf .gram}
extern_crate_decl : "extern" "crate" crate_name
crate_name: ident | ( string_lit "as" ident )
```
An _`extern crate` declaration_ specifies a dependency on an external crate.
The external crate is then bound into the declaring scope as the `ident`
provided in the `extern_crate_decl`.
@ -958,17 +775,6 @@ extern crate std as ruststd; // linking to 'std' under another name
##### Use declarations
```{.ebnf .gram}
use_decl : "pub" ? "use" [ path "as" ident
| path_glob ] ;
path_glob : ident [ "::" [ path_glob
| '*' ] ] ?
| '{' path_item [ ',' path_item ] * '}' ;
path_item : ident | "self" ;
```
A _use declaration_ creates one or more local name bindings synonymous with
some other [path](#paths). Usually a `use` declaration is used to shorten the
path required to refer to a module item. These declarations may appear at the
@ -1413,10 +1219,6 @@ it were `Bar(i32)`, this is disallowed.
### Constant items
```{.ebnf .gram}
const_item : "const" ident ':' type '=' expr ';' ;
```
A *constant item* is a named _constant value_ which is not associated with a
specific memory location in the program. Constants are essentially inlined
wherever they are used, meaning that they are copied directly into the relevant
@ -1453,10 +1255,6 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings {
### Static items
```{.ebnf .gram}
static_item : "static" ident ':' type '=' expr ';' ;
```
A *static item* is similar to a *constant*, except that it represents a precise
memory location in the program. A static is never "inlined" at the usage site,
and all references to it refer to the same memory location. Static items have
@ -1711,11 +1509,6 @@ impl Seq<bool> for u32 {
### External blocks
```{.ebnf .gram}
extern_block_item : "extern" '{' extern_block '}' ;
extern_block : [ foreign_fn ] * ;
```
External blocks form the basis for Rust's foreign function interface.
Declarations in an external block describe symbols in external, non-Rust
libraries.
@ -1915,13 +1708,6 @@ the namespace hierarchy as it normally would.
## Attributes
```{.ebnf .gram}
attribute : '#' '!' ? '[' meta_item ']' ;
meta_item : ident [ '=' literal
| '(' meta_seq ')' ] ? ;
meta_seq : meta_item [ ',' meta_seq ] ? ;
```
Any item declaration may have an _attribute_ applied to it. Attributes in Rust
are modeled on Attributes in ECMA-335, with the syntax coming from ECMA-334
(C#). An attribute is a general, free-form metadatum that is interpreted
@ -2111,8 +1897,8 @@ release builds.
There are two kinds of configuration options, one that is either defined or not
(`#[cfg(foo)]`), and the other that contains a string that can be checked
against (`#[cfg(bar = "baz")]` (currently only compiler-defined configuration
options can have the latter form).
against (`#[cfg(bar = "baz")]`). Currently, only compiler-defined configuration
options can have the latter form.
```
// The function is only included in the build when compiling for OSX
@ -2188,7 +1974,7 @@ For any lint check `C`:
The lint checks supported by the compiler can be found via `rustc -W help`,
along with their default settings. [Compiler
plugins](book/plugins.html#lint-plugins) can provide additional lint checks.
plugins](book/compiler-plugins.html#lint-plugins) can provide additional lint checks.
```{.ignore}
mod m1 {
@ -2349,7 +2135,10 @@ The currently implemented features of the reference compiler are:
semantics are likely to change, so this macro usage must be opted
into.
* `associated_types` - Allows type aliases in traits. Experimental.
* `associated_consts` - Allows constants to be defined in `impl` and `trait`
blocks, so that they can be associated with a type or
trait in a similar manner to methods and associated
types.
* `box_patterns` - Allows `box` patterns, the exact semantics of which
is subject to change.
@ -2503,7 +2292,7 @@ The currently implemented features of the reference compiler are:
terms of encapsulation).
If a feature is promoted to a language feature, then all existing programs will
start to receive compilation warnings about #[feature] directives which enabled
start to receive compilation warnings about `#![feature]` directives which enabled
the new feature (because the directive is no longer necessary). However, if a
feature is decided to be removed from the language, errors will be issued (if
there isn't a parser error first). The directive in this case is no longer
@ -2554,11 +2343,6 @@ in meaning to declaring the item outside the statement block.
#### Variable declarations
```{.ebnf .gram}
let_decl : "let" pat [':' type ] ? [ init ] ? ';' ;
init : [ '=' ] expr ;
```
A _variable declaration_ introduces a new set of variable, given by a pattern. The
pattern may be followed by a type annotation, and/or an initializer expression.
When no type annotation is given, the compiler will infer the type, or signal
@ -2649,7 +2433,7 @@ parentheses. They are used to create [tuple-typed](#tuple-types) values.
```{.tuple}
(0,);
(0.0, 4.5);
("a", 4us, true);
("a", 4usize, true);
```
### Unit expressions
@ -2659,15 +2443,6 @@ the same name.
### Structure expressions
```{.ebnf .gram}
struct_expr : expr_path '{' ident ':' expr
[ ',' ident ':' expr ] *
[ ".." expr ] '}' |
expr_path '(' expr
[ ',' expr ] * ')' |
expr_path ;
```
There are several forms of structure expressions. A _structure expression_
consists of the [path](#paths) of a [structure item](#structures), followed by
a brace-enclosed list of one or more comma-separated name-value pairs,
@ -2718,11 +2493,6 @@ Point3d {y: 0, z: 10, .. base};
### Block expressions
```{.ebnf .gram}
block_expr : '{' [ stmt ';' | item ] *
[ expr ] '}' ;
```
A _block expression_ is similar to a module in terms of the declarations that
are possible. Each block conceptually introduces a new namespace scope. Use
items can bring new names into scopes and declared items are in scope for only
@ -2745,10 +2515,6 @@ assert_eq!(5, x);
### Method-call expressions
```{.ebnf .gram}
method_call_expr : expr '.' ident paren_expr_list ;
```
A _method call_ consists of an expression followed by a single dot, an
identifier, and a parenthesized expression-list. Method calls are resolved to
methods on specific traits, either statically dispatching to a method if the
@ -2757,10 +2523,6 @@ the left-hand-side expression is an indirect [trait object](#trait-objects).
### Field expressions
```{.ebnf .gram}
field_expr : expr '.' ident ;
```
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
@ -2781,12 +2543,6 @@ automatically dereferenced to make the field access possible.
### Array expressions
```{.ebnf .gram}
array_expr : '[' "mut" ? array_elems? ']' ;
array_elems : [expr [',' expr]*] | [expr ';' expr] ;
```
An [array](#array,-and-slice-types) _expression_ is written by enclosing zero
or more comma-separated expressions of uniform type in square brackets.
@ -2803,10 +2559,6 @@ constant expression that can be evaluated at compile time, such as a
### Index expressions
```{.ebnf .gram}
idx_expr : expr '[' expr ']' ;
```
[Array](#array,-and-slice-types)-typed expressions can be indexed by
writing a square-bracket-enclosed expression (the index) after them. When the
array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can
@ -2823,13 +2575,6 @@ _panicked state_.
### Range expressions
```{.ebnf .gram}
range_expr : expr ".." expr |
expr ".." |
".." expr |
".." ;
```
The `..` operator will construct an object of one of the `std::ops::Range` variants.
```
@ -2872,10 +2617,6 @@ before the expression they apply to.
### Binary operator expressions
```{.ebnf .gram}
binop_expr : expr binop expr ;
```
Binary operators expressions are given in terms of [operator
precedence](#operator-precedence).
@ -3036,10 +2777,6 @@ An expression enclosed in parentheses evaluates to the result of the enclosed
expression. Parentheses can be used to explicitly specify evaluation order
within an expression.
```{.ebnf .gram}
paren_expr : '(' expr ')' ;
```
An example of a parenthesized expression:
```
@ -3049,12 +2786,6 @@ let x: i32 = (2 + 3) * 4;
### Call expressions
```{.ebnf .gram}
expr_list : [ expr [ ',' expr ]* ] ? ;
paren_expr_list : '(' expr_list ')' ;
call_expr : expr paren_expr_list ;
```
A _call expression_ invokes a function, providing zero or more input variables
and an optional location to move the function's output into. If the function
eventually returns, then the expression completes.
@ -3070,11 +2801,6 @@ let pi: Result<f32, _> = "3.14".parse();
### Lambda expressions
```{.ebnf .gram}
ident_list : [ ident [ ',' ident ]* ] ? ;
lambda_expr : '|' ident_list '|' expr ;
```
A _lambda expression_ (sometimes called an "anonymous function expression")
defines a function and denotes it as a value, in a single expression. A lambda
expression is a pipe-symbol-delimited (`|`) list of identifiers followed by an
@ -3118,10 +2844,6 @@ ten_times(|j| println!("hello, {}", j));
A `loop` expression denotes an infinite loop.
```{.ebnf .gram}
loop_expr : [ lifetime ':' ] "loop" '{' block '}';
```
A `loop` expression may optionally have a _label_. The label is written as
a lifetime preceding the loop expression, as in `'foo: loop{ }`. If a
label is present, then labeled `break` and `continue` expressions nested
@ -3131,10 +2853,6 @@ expressions](#continue-expressions).
### Break expressions
```{.ebnf .gram}
break_expr : "break" [ lifetime ];
```
A `break` expression has an optional _label_. If the label is absent, then
executing a `break` expression immediately terminates the innermost loop
enclosing it. It is only permitted in the body of a loop. If the label is
@ -3143,10 +2861,6 @@ be the innermost label enclosing the `break` expression, but must enclose it.
### Continue expressions
```{.ebnf .gram}
continue_expr : "continue" [ lifetime ];
```
A `continue` expression has an optional _label_. If the label is absent, then
executing a `continue` expression immediately terminates the current iteration
of the innermost loop enclosing it, returning control to the loop *head*. In
@ -3160,10 +2874,6 @@ A `continue` expression is only permitted in the body of a loop.
### While loops
```{.ebnf .gram}
while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
```
A `while` loop begins by evaluating the boolean loop conditional expression.
If the loop conditional expression evaluates to `true`, the loop body block
executes and control returns to the loop conditional expression. If the loop
@ -3187,26 +2897,22 @@ loops](#infinite-loops), [break expressions](#break-expressions), and
### For expressions
```{.ebnf .gram}
for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
```
A `for` expression is a syntactic construct for looping over elements provided
by an implementation of `std::iter::Iterator`.
by an implementation of `std::iter::IntoIterator`.
An example of a for loop over the contents of an array:
```
# type Foo = i32;
# fn bar(f: Foo) { }
# fn bar(f: &Foo) { }
# let a = 0;
# let b = 0;
# let c = 0;
let v: &[Foo] = &[a, b, c];
for e in v.iter() {
bar(*e);
for e in v {
bar(e);
}
```
@ -3226,14 +2932,6 @@ loops](#infinite-loops), [break expressions](#break-expressions), and
### If expressions
```{.ebnf .gram}
if_expr : "if" no_struct_literal_expr '{' block '}'
else_tail ? ;
else_tail : "else" [ if_expr | if_let_expr
| '{' block '}' ] ;
```
An `if` expression is a conditional branch in program control. The form of an
`if` expression is a condition expression, followed by a consequent block, any
number of `else if` conditions and blocks, and an optional trailing `else`
@ -3246,14 +2944,6 @@ if` condition is evaluated. If all `if` and `else if` conditions evaluate to
### Match expressions
```{.ebnf .gram}
match_expr : "match" no_struct_literal_expr '{' match_arm * '}' ;
match_arm : attribute * match_pat "=>" [ expr "," | '{' block '}' ] ;
match_pat : pat [ '|' pat ] * [ "if" expr ] ? ;
```
A `match` expression branches on a *pattern*. The exact form of matching that
occurs depends on the pattern. Patterns consist of some combination of
literals, destructured arrays or enum constructors, structures and tuples,
@ -3370,12 +3060,6 @@ let message = match maybe_digit {
### If let expressions
```{.ebnf .gram}
if_let_expr : "if" "let" pat '=' expr '{' block '}'
else_tail ? ;
else_tail : "else" [ if_expr | if_let_expr | '{' block '}' ] ;
```
An `if let` expression is semantically identical to an `if` expression but in place
of a condition expression it expects a refutable let statement. If the value of the
expression on the right hand side of the let statement matches the pattern, the corresponding
@ -3383,10 +3067,6 @@ block will execute, otherwise flow proceeds to the first `else` block that follo
### While let loops
```{.ebnf .gram}
while_let_expr : "while" "let" pat '=' expr '{' block '}' ;
```
A `while let` loop is semantically identical to a `while` loop but in place of a
condition expression it expects a refutable let statement. If the value of the
expression on the right hand side of the let statement matches the pattern, the
@ -3395,10 +3075,6 @@ Otherwise, the while expression completes.
### Return expressions
```{.ebnf .gram}
return_expr : "return" expr ? ;
```
Return expressions are denoted with the keyword `return`. Evaluating a `return`
expression moves its argument into the designated output location for the
current function call, destroys the current function activation frame, and
@ -3971,4 +3647,4 @@ that have since been removed):
pattern syntax
[ffi]: book/ffi.html
[plugin]: book/plugins.html
[plugin]: book/compiler-plugins.html

View file

@ -1,10 +1,10 @@
% Unit testing
Unit tests should live in a `test` submodule at the bottom of the module they
test. Mark the `test` submodule with `#[cfg(test)]` so it is only compiled when
Unit tests should live in a `tests` submodule at the bottom of the module they
test. Mark the `tests` submodule with `#[cfg(test)]` so it is only compiled when
testing.
The `test` module should contain:
The `tests` module should contain:
* Imports needed only for testing.
* Functions marked with `#[test]` striving for full coverage of the parent module's
@ -17,7 +17,7 @@ For example:
// Excerpt from std::str
#[cfg(test)]
mod test {
mod tests {
#[test]
fn test_eq() {
assert!((eq(&"".to_owned(), &"".to_owned())));

View file

@ -8,7 +8,7 @@ good at: embedding in other languages, programs with specific space and time
requirements, and writing low-level code, like device drivers and operating
systems. It improves on current languages targeting this space by having a
number of compile-time safety checks that produce no runtime overhead, while
eliminating all data races. Rust also aims to achieve zero-cost abstrations
eliminating all data races. Rust also aims to achieve zero-cost abstractions
even though some of these abstractions feel like those of a high-level
language. Even then, Rust still allows precise control like a low-level
language would.
@ -127,7 +127,7 @@ vector. When we try to compile this program, we get an error:
```text
error: cannot borrow `x` as mutable because it is also borrowed as immutable
x.push(4);
x.push("foo");
^
note: previous borrow of `x` occurs here; the immutable borrow prevents
subsequent moves or mutable borrows of `x` until the borrow ends

View file

@ -36,7 +36,6 @@
* [Strings](strings.md)
* [Generics](generics.md)
* [Traits](traits.md)
* [Operators and Overloading](operators-and-overloading.md)
* [Drop](drop.md)
* [if let](if-let.md)
* [Trait Objects](trait-objects.md)
@ -50,6 +49,7 @@
* [Casting between types](casting-between-types.md)
* [Associated Types](associated-types.md)
* [Unsized Types](unsized-types.md)
* [Operators and Overloading](operators-and-overloading.md)
* [Deref coercions](deref-coercions.md)
* [Macros](macros.md)
* [Raw Pointers](raw-pointers.md)

View file

@ -13,7 +13,7 @@ pub fn add_two(a: i32) -> i32 {
}
#[cfg(test)]
mod test {
mod tests {
use super::*;
use test::Bencher;

View file

@ -294,7 +294,7 @@ is `Fn(i32) -> i32`.
Theres one other key point here: because were bounding a generic with a
trait, this will get monomorphized, and therefore, well be doing static
dispatch into the closure. Thats pretty neat. In many langauges, closures are
dispatch into the closure. Thats pretty neat. In many languages, closures are
inherently heap allocated, and will always involve dynamic dispatch. In Rust,
we can stack allocate our closure environment, and statically dispatch the
call. This happens quite often with iterators and their adapters, which often

View file

@ -66,6 +66,8 @@ unsafe {
}
```
[unsafe]: unsafe.html
Furthermore, any type stored in a `static` must be `Sync`.
# Initializing

View file

@ -1,3 +1,119 @@
% `Deref` coercions
Coming soon!
The standard library provides a special trait, [`Deref`][deref]. Its normally
used to overload `*`, the dereference operator:
```rust
use std::ops::Deref;
struct DerefExample<T> {
value: T,
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x);
}
```
[deref]: ../std/ops/trait.Deref.html
This is useful for writing custom pointer types. However, theres a language
feature related to `Deref`: deref coercions. Heres the rule: If you have a
type `U`, and it implements `Deref<Target=T>`, values of `&U` will
automatically coerce to a `&T`. Heres an example:
```rust
fn foo(s: &str) {
// borrow a string for a second
}
// String implements Deref<Target=str>
let owned = "Hello".to_string();
// therefore, this works:
foo(&owned);
```
Using an ampersand in front of a value takes a reference to it. So `owned` is a
`String`, `&owned` is an `&String`, and since `impl Deref<Target=str> for
String`, `&String` will deref to `&str`, which `foo()` takes.
Thats it. This rule is one of the only places in which Rust does an automatic
conversion for you, but it adds a lot of flexibility. For example, the `Rc<T>`
type implements `Deref<Target=T>`, so this works:
```rust
use std::rc::Rc;
fn foo(s: &str) {
// borrow a string for a second
}
// String implements Deref<Target=str>
let owned = "Hello".to_string();
let counted = Rc::new(owned);
// therefore, this works:
foo(&counted);
```
All weve done is wrap our `String` in an `Rc<T>`. But we can now pass the
`Rc<String>` around anywhere wed have a `String`. The signature of `foo`
didnt change, but works just as well with either type. This example has two
conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do
this as many times as possible until the types match.
Another very common implementation provided by the standard library is:
```rust
fn foo(s: &[i32]) {
// borrow a slice for a second
}
// Vec<T> implements Deref<Target=[T]>
let owned = vec![1, 2, 3];
foo(&owned);
```
Vectors can `Deref` to a slice.
## Deref and method calls
`Deref` will also kick in when calling a method. In other words, these are
the same two things in Rust:
```rust
struct Foo;
impl Foo {
fn foo(&self) { println!("Foo"); }
}
let f = Foo;
f.foo();
```
Even though `f` isnt a reference, and `foo` takes `&self`, this works.
Thats because these things are the same:
```rust,ignore
f.foo();
(&f).foo();
(&&f).foo();
(&&&&&&&&f).foo();
```
A value of type `&&&&&&&&&&&&&&&&Foo` can still have methods defined on `Foo`
called, because the compiler will insert as many * operations as necessary to
get it right. And since its inserting `*`s, that uses `Deref`.

View file

@ -556,7 +556,7 @@ This sets a few different options, with a logo, favicon, and a root URL.
## Generation options
`rustdoc` also contains a few other options on the command line, for further customiziation:
`rustdoc` also contains a few other options on the command line, for further customization:
- `--html-in-header FILE`: includes the contents of FILE at the end of the
`<head>...</head>` section.

View file

@ -1,5 +1,5 @@
% Getting Started
This first section of the book will get you going with Rust and its tooling.
First, well install Rust. Then: the classic Hello World program. Finally,
First, well install Rust. Then, the classic Hello World program. Finally,
well talk about Cargo, Rusts build system and package manager.

View file

@ -19,7 +19,7 @@ In the example above `x` and `y` have arity 2. `z` has arity 3.
When a compiler is compiling your program, it does a number of different
things. One of the things that it does is turn the text of your program into an
'abstract syntax tree,' or 'AST.' This tree is a representation of the
abstract syntax tree, orAST. This tree is a representation of the
structure of your program. For example, `2 + 3` can be turned into a tree:
```text

View file

@ -32,6 +32,13 @@ $ mkdir src
$ mv main.rs src/main.rs
```
Note that since we're creating an executable, we used `main.rs`. If we
want to make a library instead, we should use `lib.rs`.
Custom file locations for the entry point can be specified
with a [`[[lib]]` or `[[bin]]`][crates-custom] key in the TOML file described below.
[crates-custom]: http://doc.crates.io/manifest.html#configuring-a-target
Cargo expects your source files to live inside a `src` directory. That leaves
the top level for other things, like READMEs, license information, and anything
not related to your code. Cargo helps us keep our projects nice and tidy. A

View file

@ -765,7 +765,7 @@ as `unimplemented!` until youre ready to write them.
# Procedural macros
If Rusts macro system cant do what you need, you may want to write a
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
[compiler plugin](compiler-plugins.html) instead. Compared to `macro_rules!`
macros, this is significantly more work, the interfaces are much less stable,
and bugs can be much harder to track down. In exchange you get the
flexibility of running arbitrary Rust code within the compiler. Syntax

View file

@ -18,7 +18,7 @@ foo.bar().baz();
Luckily, as you may have guessed with the leading question, you can! Rust provides
the ability to use this method call syntax via the `impl` keyword.
## Method calls
# Method calls
Heres how it works:
@ -83,7 +83,7 @@ impl Circle {
}
```
## Chaining method calls
# Chaining method calls
So, now we know how to call a method, such as `foo.bar()`. But what about our
original example, `foo.bar().baz()`? This is called method chaining, and we
@ -127,7 +127,7 @@ fn grow(&self) -> Circle {
We just say were returning a `Circle`. With this method, we can grow a new
circle to any arbitrary size.
## Static methods
# Static methods
You can also define methods that do not take a `self` parameter. Heres a
pattern thats very common in Rust code:
@ -158,7 +158,7 @@ This static method builds a new `Circle` for us. Note that static methods
are called with the `Struct::method()` syntax, rather than the `ref.method()`
syntax.
## Builder Pattern
# Builder Pattern
Lets say that we want our users to be able to create Circles, but we will
allow them to only set the properties they care about. Otherwise, the `x`

View file

@ -1,3 +1,179 @@
% Mutability
Coming Soon
Mutability, the ability to change something, works a bit differently in Rust
than in other languages. The first aspect of mutability is its non-default
status:
```rust,ignore
let x = 5;
x = 6; // error!
```
We can introduce mutability with the `mut` keyword:
```rust
let mut x = 5;
x = 6; // no problem!
```
This is a mutable [variable binding][vb]. When a binding is mutable, it means
youre allowed to change what the binding points to. So in the above example,
its not so much that the value at `x` is changing, but that the binding
changed from one `i32` to another.
[vb]: variable-bindings.html
If you want to change what the binding points to, youll need a [mutable reference][mr]:
```rust
let mut x = 5;
let y = &mut x;
```
[mr]: references-and-borrowing.html
`y` is an immutable binding to a mutable reference, which means that you cant
bind `y` to something else (`y = &mut z`), but you can mutate the thing thats
bound to `y`. (`*y = 5`) A subtle distinction.
Of course, if you need both:
```rust
let mut x = 5;
let mut y = &mut x;
```
Now `y` can be bound to another value, and the value its referencing can be
changed.
Its important to note that `mut` is part of a [pattern][pattern], so you
can do things like this:
```rust
let (mut x, y) = (5, 6);
fn foo(mut x: i32) {
# }
```
[pattern]: patterns.html
# Interior vs. Exterior Mutability
However, when we say something is immutable in Rust, that doesnt mean that
its not able to be changed: We mean something has exterior mutability. Consider,
for example, [`Arc<T>`][arc]:
```rust
use std::sync::Arc;
let x = Arc::new(5);
let y = x.clone();
```
[arc]: ../std/sync/struct.Arc.html
When we call `clone()`, the `Arc<T>` needs to update the reference count. Yet
weve not used any `mut`s here, `x` is an immutable binding, and we didnt take
`&mut 5` or anything. So what gives?
To this, we have to go back to the core of Rusts guiding philosophy, memory
safety, and the mechanism by which Rust guarantees it, the
[ownership][ownership] system, and more specifically, [borrowing][borrowing]:
> You may have one or the other of these two kinds of borrows, but not both at
> the same time:
>
> * 0 to N references (`&T`) to a resource.
> * exactly one mutable reference (`&mut T`)
[ownership]: ownership.html
[borrowing]: borrowing.html#The-Rules
So, thats the real definition of immutability: is this safe to have two
pointers to? In `Arc<T>`s case, yes: the mutation is entirely contained inside
the structure itself. Its not user facing. For this reason, it hands out `&T`
with `clone()`. If it handed out `&mut T`s, though, that would be a problem.
Other types, like the ones in the [`std::cell`][stdcell] module, have the
opposite: interior mutability. For example:
```rust
use std::cell::RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();
```
[stdcell]: ../std/cell/index.html
RefCell hands out `&mut` references to whats inside of it with the
`borrow_mut()` method. Isnt that dangerous? What if we do:
```rust,ignore
use std::cell::RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();
let z = x.borrow_mut();
# (y, z);
```
This will in fact panic, at runtime. This is what `RefCell` does: it enforces
Rusts borrowing rules at runtime, and `panic!`s if theyre violated. This
allows us to get around another aspect of Rusts mutability rules. Lets talk
about it first.
## Field-level mutability
Mutability is a property of either a borrow (`&mut`) or a binding (`let mut`).
This means that, for example, you cannot have a [`struct`][struct] with
some fields mutable and some immutable:
```rust,ignore
struct Point {
x: i32,
mut y: i32, // nope
}
```
The mutability of a struct is in its binding:
```rust,ignore
struct Point {
x: i32,
y: i32,
}
let mut a = Point { x: 5, y: 6 };
a.x = 10;
let b = Point { x: 5, y: 6};
b.x = 10; // error: cannot assign to immutable field `b.x`
```
[struct]: structs.html
However, by using `Cell<T>`, you can emulate field-level mutability:
```
use std::cell::Cell;
struct Point {
x: i32,
y: Cell<i32>,
}
let mut point = Point { x: 5, y: Cell::new(6) };
point.y.set(7);
println!("y: {:?}", point.y);
```
This will print `y: Cell { value: 7 }`. Weve successfully updated `y`.

View file

@ -1,3 +1,83 @@
% Operators and Overloading
Coming soon!
Rust allows for a limited form of operator overloading. There are certain
operators that are able to be overloaded. To support a particular operator
between types, theres a specific trait that you can implement, which then
overloads the operator.
For example, the `+` operator can be overloaded with the `Add` trait:
```rust
use std::ops::Add;
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point { x: self.x + other.x, y: self.y + other.y }
}
}
fn main() {
let p1 = Point { x: 1, y: 0 };
let p2 = Point { x: 2, y: 3 };
let p3 = p1 + p2;
println!("{:?}", p3);
}
```
In `main`, we can use `+` on our two `Point`s, since weve implemented
`Add<Output=Point>` for `Point`.
There are a number of operators that can be overloaded this way, and all of
their associated traits live in the [`std::ops`][stdops] module. Check out its
documentation for the full list.
[stdops]: ../std/ops/index.html
Implementing these traits follows a pattern. Lets look at [`Add`][add] in more
detail:
```rust
# mod foo {
pub trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
# }
```
[add]: ../std/ops/trait.Add.html
Theres three types in total involved here: the type you `impl Add` for, `RHS`,
which defaults to `Self`, and `Output`. For an expression `let z = x + y`, `x`
is the `Self` type, `y` is the RHS, and `z` is the `Self::Output` type.
```rust
# struct Point;
# use std::ops::Add;
impl Add<i32> for Point {
type Output = f64;
fn add(self, rhs: i32) -> f64 {
// add an i32 to a Point and get an f64
# 1.0
}
}
```
will let you do this:
```rust,ignore
let p: Point = // ...
let x: f64 = p + 2i32;
```

View file

@ -62,14 +62,14 @@ let y = 1.0; // y has type f64
Heres a list of the different numeric types, with links to their documentation
in the standard library:
* [i8](../std/primitive.i8.html)
* [i16](../std/primitive.i16.html)
* [i32](../std/primitive.i32.html)
* [i64](../std/primitive.i64.html)
* [i8](../std/primitive.i8.html)
* [u8](../std/primitive.u8.html)
* [u16](../std/primitive.u16.html)
* [u32](../std/primitive.u32.html)
* [u64](../std/primitive.u64.html)
* [u8](../std/primitive.u8.html)
* [isize](../std/primitive.isize.html)
* [usize](../std/primitive.usize.html)
* [f32](../std/primitive.f32.html)
@ -82,12 +82,12 @@ Lets go over them by category:
Integer types come in two varieties: signed and unsigned. To understand the
difference, lets consider a number with four bits of size. A signed, four-bit
number would let you store numbers from `-8` to `+7`. Signed numbers use
twos compliment representation. An unsigned four bit number, since it does
“twos compliment representation”. An unsigned four bit number, since it does
not need to store negatives, can store values from `0` to `+15`.
Unsigned types use a `u` for their category, and signed types use `i`. The `i`
is for integer. So `u8` is an eight-bit unsigned number, and `i8` is an
eight-bit signed number.
eight-bit signed number.
## Fixed size types
@ -103,7 +103,7 @@ and unsigned varieties. This makes for two types: `isize` and `usize`.
## Floating-point types
Rust also two floating point types: `f32` and `f64`. These correspond to
Rust also has two floating point types: `f32` and `f64`. These correspond to
IEEE-754 single and double precision numbers.
# Arrays
@ -241,8 +241,8 @@ println!("x is {}", x);
Remember [before][let] when I said the left-hand side of a `let` statement was more
powerful than just assigning a binding? Here we are. We can put a pattern on
the left-hand side of the `let`, and if it matches up to the right-hand side,
we can assign multiple bindings at once. In this case, `let` "destructures,"
or "breaks up," the tuple, and assigns the bits to three bindings.
we can assign multiple bindings at once. In this case, `let` “destructures”
or “breaks up” the tuple, and assigns the bits to three bindings.
[let]: variable-bindings.html

View file

@ -219,10 +219,10 @@ fn it_works() {
This is a very common use of `assert_eq!`: call some function with
some known arguments and compare it to the expected output.
# The `test` module
# The `tests` module
There is one way in which our existing example is not idiomatic: it's
missing the test module. The idiomatic way of writing our example
missing the `tests` module. The idiomatic way of writing our example
looks like this:
```{rust,ignore}
@ -231,7 +231,7 @@ pub fn add_two(a: i32) -> i32 {
}
#[cfg(test)]
mod test {
mod tests {
use super::add_two;
#[test]
@ -241,7 +241,7 @@ mod test {
}
```
There's a few changes here. The first is the introduction of a `mod test` with
There's a few changes here. The first is the introduction of a `mod tests` with
a `cfg` attribute. The module allows us to group all of our tests together, and
to also define helper functions if needed, that don't become a part of the rest
of our crate. The `cfg` attribute only compiles our test code if we're
@ -260,7 +260,7 @@ pub fn add_two(a: i32) -> i32 {
}
#[cfg(test)]
mod test {
mod tests {
use super::*;
#[test]
@ -279,7 +279,7 @@ $ cargo test
Running target/adder-91b3e234d4ed382a
running 1 test
test test::it_works ... ok
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
@ -292,7 +292,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
It works!
The current convention is to use the `test` module to hold your "unit-style"
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
@ -325,7 +325,7 @@ $ cargo test
Running target/adder-91b3e234d4ed382a
running 1 test
test test::it_works ... ok
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
@ -346,7 +346,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
Now we have three sections: our previous test is also run, as well as our new
one.
That's all there is to the `tests` directory. The `test` module isn't needed
That's all there is to the `tests` directory. The `tests` module isn't needed
here, since the whole thing is focused on tests.
Let's finally check out that third section: documentation tests.
@ -382,7 +382,7 @@ pub fn add_two(a: i32) -> i32 {
}
#[cfg(test)]
mod test {
mod tests {
use super::*;
#[test]
@ -405,7 +405,7 @@ $ cargo test
Running target/adder-91b3e234d4ed382a
running 1 test
test test::it_works ... ok
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

View file

@ -155,7 +155,7 @@ A function that takes a trait object is not specialized to each of the types
that implements `Foo`: only one copy is generated, often (but not always)
resulting in less code bloat. However, this comes at the cost of requiring
slower virtual function calls, and effectively inhibiting any chance of
inlining and related optimisations from occurring.
inlining and related optimizations from occurring.
### Why pointers?

View file

@ -184,7 +184,7 @@ wont have its methods:
```rust,ignore
let mut f = std::fs::File::open("foo.txt").ok().expect("Couldnt open foo.txt");
let result = f.write("whatever".as_bytes());
# result.unwrap(); // ignore the erorr
# result.unwrap(); // ignore the error
```
Heres the error:
@ -203,7 +203,7 @@ use std::io::Write;
let mut f = std::fs::File::open("foo.txt").ok().expect("Couldnt open foo.txt");
let result = f.write("whatever".as_bytes());
# result.unwrap(); // ignore the erorr
# result.unwrap(); // ignore the error
```
This will compile without error.

View file

@ -89,7 +89,7 @@ not, and so we need to pass an explicit `&b`.
The form of UFCS we just talked about:
```rust,ignore
Type::method(args);
Trait::method(args);
```
Is a short-hand. Theres an expanded form of this thats needed in some

View file

@ -1,6 +1,6 @@
% Variable Bindings
Vitually every non-Hello World Rust program uses *variable bindings*. They
Virtually every non-'Hello World Rust program uses *variable bindings*. They
look like this:
```rust

View file

@ -1,8 +1,9 @@
% Vectors
A vector is a dynamic or growable array, implemented as the standard
library type [`Vec<T>`][vec]. That `<T>` is a [generic][generic], meaning we
can have vectors of any type. Vectors always allocate their data on the heap.
library type [`Vec<T>`][vec]. The `T` means that we can have vectors
of any type (see the chapter on [generics][generic] for more).
Vectors always allocate their data on the heap.
You can create them with the `vec!` macro:
```rust
@ -56,3 +57,4 @@ Vectors have many more useful methods, which you can read about in [their
API documentation][vec].
[vec]: ../std/vec/index.html
[generic]: generics.html

View file

@ -505,10 +505,20 @@ trait_items
;
trait_item
: trait_type
: trait_const
| trait_type
| trait_method
;
trait_const
: maybe_outer_attrs CONST ident maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 3, $1, $3, $4); }
;
maybe_const_default
: '=' expr { $$ = mk_node("ConstDefault", 1, $2); }
| %empty { $$ = mk_none(); }
;
trait_type
: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); }
;
@ -611,7 +621,16 @@ impl_items
impl_item
: impl_method
| item_macro
| trait_type
| impl_const
| impl_type
;
impl_const
: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); }
;
impl_type
: attrs_and_vis TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); }
;
item_fn

View file

@ -355,7 +355,6 @@ impl<T: Clone> Arc<T> {
}
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Arc<T> {
/// Drops the `Arc<T>`.
@ -489,7 +488,6 @@ impl<T> Clone for Weak<T> {
}
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Weak<T> {
/// Drops the `Weak<T>`.

View file

@ -211,7 +211,9 @@ mod imp {
}
// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
#[cfg(all(not(windows), not(target_os = "android")))]
#[cfg(all(not(windows),
not(target_os = "android"),
not(target_env = "musl")))]
#[link(name = "pthread")]
extern {}
@ -384,7 +386,7 @@ mod imp {
}
#[cfg(test)]
mod test {
mod tests {
extern crate test;
use self::test::Bencher;
use boxed::Box;

View file

@ -73,7 +73,7 @@
#![feature(allocator)]
#![feature(custom_attribute)]
#![feature(fundamental)]
#![feature(lang_items, unsafe_destructor)]
#![feature(lang_items)]
#![feature(box_syntax)]
#![feature(optin_builtin_traits)]
#![feature(unboxed_closures)]

View file

@ -375,7 +375,6 @@ impl<T> Deref for Rc<T> {
}
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Rc<T> {
/// Drops the `Rc<T>`.
@ -693,7 +692,6 @@ impl<T> Weak<T> {
}
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Weak<T> {
/// Drops the `Weak<T>`.

View file

@ -35,7 +35,6 @@
#![feature(core)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(unsafe_destructor)]
#![cfg_attr(test, feature(test))]
extern crate alloc;
@ -124,7 +123,6 @@ fn chunk(size: usize, is_copy: bool) -> Chunk {
}
}
#[unsafe_destructor]
impl<'longer_than_self> Drop for Arena<'longer_than_self> {
fn drop(&mut self) {
unsafe {
@ -510,7 +508,6 @@ impl<T> TypedArena<T> {
}
}
#[unsafe_destructor]
impl<T> Drop for TypedArena<T> {
fn drop(&mut self) {
unsafe {

View file

@ -546,7 +546,7 @@ impl<T: Ord> BinaryHeap<T> {
#[unstable(feature = "collections",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn drain(&mut self) -> Drain<T> {
Drain { iter: self.data.drain() }
Drain { iter: self.data.drain(..) }
}
/// Drops all items from the binary heap.

View file

@ -270,14 +270,12 @@ impl<T> DoubleEndedIterator for RawItems<T> {
}
}
#[unsafe_destructor]
impl<T> Drop for RawItems<T> {
fn drop(&mut self) {
for _ in self.by_ref() {}
}
}
#[unsafe_destructor]
impl<K, V> Drop for Node<K, V> {
fn drop(&mut self) {
if self.keys.is_null() ||
@ -1394,7 +1392,6 @@ impl<K, V> TraversalImpl for MoveTraversalImpl<K, V> {
}
}
#[unsafe_destructor]
impl<K, V> Drop for MoveTraversalImpl<K, V> {
fn drop(&mut self) {
// We need to cleanup the stored values manually, as the RawItems destructor would run

View file

@ -394,14 +394,71 @@
//!
//! ## Precision
//!
//! For non-numeric types, this can be considered a "maximum width". If the
//! resulting string is longer than this width, then it is truncated down to
//! this many characters and only those are emitted.
//! For non-numeric types, this can be considered a "maximum width". If the resulting string is
//! longer than this width, then it is truncated down to this many characters and only those are
//! emitted.
//!
//! For integral types, this has no meaning currently.
//!
//! For floating-point types, this indicates how many digits after the decimal
//! point should be printed.
//! For floating-point types, this indicates how many digits after the decimal point should be
//! printed.
//!
//! There are three possible ways to specify the desired `precision`:
//!
//! There are three possible ways to specify the desired `precision`:
//! 1. An integer `.N`,
//! 2. an integer followed by dollar sign `.N$`, or
//! 3. an asterisk `.*`.
//!
//! The first specification, `.N`, means the integer `N` itself is the precision.
//!
//! The second, `.N$`, means use format *argument* `N` (which must be a `usize`) as the precision.
//!
//! Finally, `.*` means that this `{...}` is associated with *two* format inputs rather than one:
//! the first input holds the `usize` precision, and the second holds the value to print. Note
//! that in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part
//! refers to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
//!
//! For example, these:
//!
//! ```
//! // Hello {arg 0 (x)} is {arg 1 (0.01} with precision specified inline (5)}
//! println!("Hello {0} is {1:.5}", "x", 0.01);
//!
//! // Hello {arg 1 (x)} is {arg 2 (0.01} with precision specified in arg 0 (5)}
//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
//!
//! // Hello {arg 0 (x)} is {arg 2 (0.01} with precision specified in arg 1 (5)}
//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
//!
//! // Hello {next arg (x)} is {second of next two args (0.01} with precision
//! // specified in first of next two args (5)}
//! println!("Hello {} is {:.*}", "x", 5, 0.01);
//!
//! // Hello {next arg (x)} is {arg 2 (0.01} with precision
//! // specified in its predecessor (5)}
//! println!("Hello {} is {2:.*}", "x", 5, 0.01);
//! ```
//!
//! All print the same thing:
//!
//! ```text
//! Hello x is 0.01000
//! ```
//!
//! While these:
//!
//! ```
//! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
//! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
//! ```
//!
//! print two significantly different things:
//!
//! ```text
//! Hello, `1234.560` has 3 fractional digits
//! Hello, `123` has 3 characters
//! ```
//!
//! # Escaping
//!

View file

@ -33,7 +33,6 @@
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unsafe_destructor)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(step_by)]
@ -42,7 +41,8 @@
#![feature(slice_patterns)]
#![feature(debug_builders)]
#![feature(utf8_error)]
#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))]
#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections,
collections_drain, collections_range))]
#![cfg_attr(test, allow(deprecated))] // rand
#![feature(no_std)]
@ -82,6 +82,7 @@ pub mod borrow;
pub mod enum_set;
pub mod fmt;
pub mod linked_list;
pub mod range;
pub mod slice;
pub mod str;
pub mod string;

View file

@ -624,7 +624,6 @@ impl<T> LinkedList<T> {
}
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for LinkedList<T> {
fn drop(&mut self) {
@ -933,7 +932,7 @@ impl<A: Hash> Hash for LinkedList<A> {
}
#[cfg(test)]
mod test {
mod tests {
use std::clone::Clone;
use std::iter::{Iterator, IntoIterator};
use std::option::Option::{Some, None, self};

View file

@ -0,0 +1,45 @@
// 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.
#![unstable(feature = "collections_range", reason = "was just added")]
//! Range syntax.
use core::option::Option::{self, None, Some};
use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
/// **RangeArgument** is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
pub trait RangeArgument<T> {
/// Start index (inclusive)
///
/// Return start value if present, else `None`.
fn start(&self) -> Option<&T> { None }
/// End index (exclusive)
///
/// Return end value if present, else `None`.
fn end(&self) -> Option<&T> { None }
}
impl<T> RangeArgument<T> for RangeFull {}
impl<T> RangeArgument<T> for RangeFrom<T> {
fn start(&self) -> Option<&T> { Some(&self.start) }
}
impl<T> RangeArgument<T> for RangeTo<T> {
fn end(&self) -> Option<&T> { Some(&self.end) }
}
impl<T> RangeArgument<T> for Range<T> {
fn start(&self) -> Option<&T> { Some(&self.start) }
fn end(&self) -> Option<&T> { Some(&self.end) }
}

View file

@ -951,12 +951,13 @@ impl<'a> Deref for DerefString<'a> {
/// # #![feature(collections)]
/// use std::string::as_string;
///
/// fn string_consumer(s: String) {
/// assert_eq!(s, "foo".to_string());
/// // Let's pretend we have a function that requires `&String`
/// fn string_consumer(s: &String) {
/// assert_eq!(s, "foo");
/// }
///
/// let string = as_string("foo").clone();
/// string_consumer(string);
/// // Provide a `&String` from a `&str` without allocating
/// string_consumer(&as_string("foo"));
/// ```
#[unstable(feature = "collections")]
pub fn as_string<'a>(x: &'a str) -> DerefString<'a> {

View file

@ -69,6 +69,8 @@ use core::usize;
use borrow::{Cow, IntoCow};
use super::range::RangeArgument;
// FIXME- fix places which assume the max vector allowed has memory usize::MAX.
static MAX_MEMORY_SIZE: usize = isize::MAX as usize;
@ -116,11 +118,7 @@ static MAX_MEMORY_SIZE: usize = isize::MAX as usize;
/// stack.push(2);
/// stack.push(3);
///
/// loop {
/// let top = match stack.pop() {
/// None => break, // empty
/// Some(x) => x,
/// };
/// while let Some(top) = stack.pop() {
/// // Prints 3, 2, 1
/// println!("{}", top);
/// }
@ -540,7 +538,7 @@ impl<T> Vec<T> {
///
/// # Panics
///
/// Panics if `i` is out of bounds.
/// Panics if `index` is out of bounds.
///
/// # Examples
///
@ -718,36 +716,61 @@ impl<T> Vec<T> {
unsafe { other.set_len(0); }
}
/// Creates a draining iterator that clears the `Vec` and iterates over
/// the removed items from start to end.
/// Create a draining iterator that removes the specified range in the vector
/// and yields the removed items from start to end. The element range is
/// removed even if the iterator is not consumed until the end.
///
/// Note: It is unspecified how many elements are removed from the vector,
/// if the `Drain` value is leaked.
///
/// # Panics
///
/// Panics if the starting point is greater than the end point or if
/// the end point is greater than the length of the vector.
///
/// # Examples
///
/// ```
/// # #![feature(collections)]
/// let mut v = vec!["a".to_string(), "b".to_string()];
/// for s in v.drain() {
/// // s has type String, not &String
/// println!("{}", s);
/// }
/// assert!(v.is_empty());
/// # #![feature(collections_drain, collections_range)]
///
/// // Draining using `..` clears the whole vector.
/// let mut v = vec![1, 2, 3];
/// let u: Vec<_> = v.drain(..).collect();
/// assert_eq!(v, &[]);
/// assert_eq!(u, &[1, 2, 3]);
/// ```
#[inline]
#[unstable(feature = "collections",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn drain(&mut self) -> Drain<T> {
#[unstable(feature = "collections_drain",
reason = "recently added, matches RFC")]
pub fn drain<R>(&mut self, range: R) -> Drain<T> where R: RangeArgument<usize> {
// Memory safety
//
// When the Drain is first created, it shortens the length of
// the source vector to make sure no uninitalized or moved-from elements
// are accessible at all if the Drain's destructor never gets to run.
//
// Drain will ptr::read out the values to remove.
// When finished, remaining tail of the vec is copied back to cover
// the hole, and the vector length is restored to the new length.
//
let len = self.len();
let start = *range.start().unwrap_or(&0);
let end = *range.end().unwrap_or(&len);
assert!(start <= end);
assert!(end <= len);
unsafe {
let begin = *self.ptr as *const T;
let end = if mem::size_of::<T>() == 0 {
(*self.ptr as usize + self.len()) as *const T
} else {
(*self.ptr).offset(self.len() as isize) as *const T
};
self.set_len(0);
// set self.vec length's to start, to be safe in case Drain is leaked
self.set_len(start);
// Use the borrow in the IterMut to indicate borrowing behavior of the
// whole Drain iterator (like &mut T).
let range_slice = slice::from_raw_parts_mut(
self.as_mut_ptr().offset(start as isize),
end - start);
Drain {
ptr: begin,
end: end,
marker: PhantomData,
tail_start: end,
tail_len: len - end,
iter: range_slice.iter_mut(),
vec: self as *mut _,
}
}
}
@ -1603,7 +1626,6 @@ impl<'a, T: Clone> Add<&'a [T]> for Vec<T> {
}
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Vec<T> {
fn drop(&mut self) {
@ -1785,7 +1807,6 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for IntoIter<T> {
fn drop(&mut self) {
@ -1799,14 +1820,16 @@ impl<T> Drop for IntoIter<T> {
}
}
/// An iterator that drains a vector.
#[unsafe_no_drop_flag]
#[unstable(feature = "collections",
reason = "recently added as part of collections reform 2")]
pub struct Drain<'a, T:'a> {
ptr: *const T,
end: *const T,
marker: PhantomData<&'a T>,
/// A draining iterator for `Vec<T>`.
#[unstable(feature = "collections_drain", reason = "recently added")]
pub struct Drain<'a, T: 'a> {
/// Index of tail to preserve
tail_start: usize,
/// Length of tail
tail_len: usize,
/// Current remaining range to remove
iter: slice::IterMut<'a, T>,
vec: *mut Vec<T>,
}
unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
@ -1818,34 +1841,15 @@ impl<'a, T> Iterator for Drain<'a, T> {
#[inline]
fn next(&mut self) -> Option<T> {
unsafe {
if self.ptr == self.end {
None
} else {
if mem::size_of::<T>() == 0 {
// purposefully don't use 'ptr.offset' because for
// vectors with 0-size elements this would return the
// same pointer.
self.ptr = mem::transmute(self.ptr as usize + 1);
// Use a non-null pointer value
Some(ptr::read(EMPTY as *mut T))
} else {
let old = self.ptr;
self.ptr = self.ptr.offset(1);
Some(ptr::read(old))
}
self.iter.next().map(|elt|
unsafe {
ptr::read(elt as *const _)
}
}
)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let diff = (self.end as usize) - (self.ptr as usize);
let size = mem::size_of::<T>();
let exact = diff / (if size == 0 {1} else {size});
(exact, Some(exact))
self.iter.size_hint()
}
}
@ -1853,41 +1857,39 @@ impl<'a, T> Iterator for Drain<'a, T> {
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
unsafe {
if self.end == self.ptr {
None
} else {
if mem::size_of::<T>() == 0 {
// See above for why 'ptr.offset' isn't used
self.end = mem::transmute(self.end as usize - 1);
self.iter.next_back().map(|elt|
unsafe {
ptr::read(elt as *const _)
}
)
}
}
// Use a non-null pointer value
Some(ptr::read(EMPTY as *mut T))
} else {
self.end = self.end.offset(-1);
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
// exhaust self first
while let Some(_) = self.next() { }
Some(ptr::read(self.end))
}
if self.tail_len > 0 {
unsafe {
let source_vec = &mut *self.vec;
// memmove back untouched tail, update to new length
let start = source_vec.len();
let tail = self.tail_start;
let src = source_vec.as_ptr().offset(tail as isize);
let dst = source_vec.as_mut_ptr().offset(start as isize);
ptr::copy(src, dst, self.tail_len);
source_vec.set_len(start + self.tail_len);
}
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
// self.ptr == self.end == mem::POST_DROP_USIZE if drop has already been called,
// so we can use #[unsafe_no_drop_flag].
// destroy the remaining elements
for _x in self.by_ref() {}
}
}
////////////////////////////////////////////////////////////////////////////////
// Conversion from &[T] to &Vec<T>
////////////////////////////////////////////////////////////////////////////////
@ -1909,7 +1911,6 @@ impl<'a, T> Deref for DerefVec<'a, T> {
}
// Prevent the inner `Vec<T>` from attempting to deallocate memory.
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for DerefVec<'a, T> {
fn drop(&mut self) {
@ -1919,6 +1920,22 @@ impl<'a, T> Drop for DerefVec<'a, T> {
}
/// Converts a slice to a wrapper type providing a `&Vec<T>` reference.
///
/// # Examples
///
/// ```
/// # #![feature(collections)]
/// use std::vec::as_vec;
///
/// // Let's pretend we have a function that requires `&Vec<i32>`
/// fn vec_consumer(s: &Vec<i32>) {
/// assert_eq!(s, &[1, 2, 3]);
/// }
///
/// // Provide a `&Vec<i32>` from a `&[i32]` without allocating
/// let values = [1, 2, 3];
/// vec_consumer(&as_vec(&values));
/// ```
#[unstable(feature = "collections")]
pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> {
unsafe {
@ -1962,7 +1979,6 @@ struct PartialVecZeroSized<T,U> {
marker: PhantomData<::core::cell::Cell<(T,U)>>,
}
#[unsafe_destructor]
impl<T,U> Drop for PartialVecNonZeroSized<T,U> {
fn drop(&mut self) {
unsafe {
@ -1988,7 +2004,6 @@ impl<T,U> Drop for PartialVecNonZeroSized<T,U> {
}
}
#[unsafe_destructor]
impl<T,U> Drop for PartialVecZeroSized<T,U> {
fn drop(&mut self) {
unsafe {

View file

@ -59,7 +59,6 @@ impl<T: Clone> Clone for VecDeque<T> {
}
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for VecDeque<T> {
fn drop(&mut self) {
@ -1612,7 +1611,6 @@ pub struct Drain<'a, T: 'a> {
inner: &'a mut VecDeque<T>,
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: 'a> Drop for Drain<'a, T> {
fn drop(&mut self) {
@ -1772,7 +1770,7 @@ impl<T: fmt::Debug> fmt::Debug for VecDeque<T> {
}
#[cfg(test)]
mod test {
mod tests {
use core::iter::{Iterator, self};
use core::option::Option::Some;

View file

@ -418,7 +418,7 @@ impl<V> VecMap<V> {
}
let filter: fn((usize, Option<V>)) -> Option<(usize, V)> = filter; // coerce to fn ptr
Drain { iter: self.v.drain().enumerate().filter_map(filter) }
Drain { iter: self.v.drain(..).enumerate().filter_map(filter) }
}
/// Returns the number of elements in the map.

View file

@ -10,6 +10,7 @@
#![feature(box_syntax)]
#![feature(collections)]
#![feature(collections_drain)]
#![feature(core)]
#![feature(hash)]
#![feature(rand)]
@ -17,7 +18,6 @@
#![feature(test)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unsafe_destructor)]
#![feature(into_cow)]
#![feature(step_by)]
#![cfg_attr(test, feature(str_char))]

View file

@ -18,7 +18,6 @@ struct DropCounter<'a> {
count: &'a mut u32
}
#[unsafe_destructor]
impl<'a> Drop for DropCounter<'a> {
fn drop(&mut self) {
*self.count += 1;
@ -460,7 +459,7 @@ fn test_move_items_zero_sized() {
fn test_drain_items() {
let mut vec = vec![1, 2, 3];
let mut vec2 = vec![];
for i in vec.drain() {
for i in vec.drain(..) {
vec2.push(i);
}
assert_eq!(vec, []);
@ -471,7 +470,7 @@ fn test_drain_items() {
fn test_drain_items_reverse() {
let mut vec = vec![1, 2, 3];
let mut vec2 = vec![];
for i in vec.drain().rev() {
for i in vec.drain(..).rev() {
vec2.push(i);
}
assert_eq!(vec, []);
@ -482,13 +481,43 @@ fn test_drain_items_reverse() {
fn test_drain_items_zero_sized() {
let mut vec = vec![(), (), ()];
let mut vec2 = vec![];
for i in vec.drain() {
for i in vec.drain(..) {
vec2.push(i);
}
assert_eq!(vec, []);
assert_eq!(vec2, [(), (), ()]);
}
#[test]
#[should_panic]
fn test_drain_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
v.drain(5..6);
}
#[test]
fn test_drain_range() {
let mut v = vec![1, 2, 3, 4, 5];
for _ in v.drain(4..) {
}
assert_eq!(v, &[1, 2, 3, 4]);
let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
for _ in v.drain(1..4) {
}
assert_eq!(v, &[1.to_string(), 5.to_string()]);
let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
for _ in v.drain(1..4).rev() {
}
assert_eq!(v, &[1.to_string(), 5.to_string()]);
let mut v: Vec<_> = vec![(); 5];
for _ in v.drain(1..4).rev() {
}
assert_eq!(v, &[(), ()]);
}
#[test]
fn test_into_boxed_slice() {
let xs = vec![1, 2, 3];

View file

@ -129,6 +129,12 @@ pub struct AtomicPtr<T> {
_marker: PhantomData<*mut T>,
}
impl<T> Default for AtomicPtr<T> {
fn default() -> AtomicPtr<T> {
AtomicPtr::new(::ptr::null_mut())
}
}
unsafe impl<T> Sync for AtomicPtr<T> {}
/// Atomic memory orderings

View file

@ -417,7 +417,7 @@ impl<T> RefCell<T> {
///
/// let result = thread::spawn(move || {
/// let c = RefCell::new(5);
/// let m = c.borrow_mut();
/// let m = c.borrow();
///
/// let b = c.borrow_mut(); // this causes a panic
/// }).join();
@ -493,7 +493,6 @@ impl<'b> BorrowRef<'b> {
}
}
#[unsafe_destructor]
impl<'b> Drop for BorrowRef<'b> {
#[inline]
fn drop(&mut self) {
@ -557,7 +556,6 @@ struct BorrowRefMut<'b> {
_borrow: &'b Cell<BorrowFlag>,
}
#[unsafe_destructor]
impl<'b> Drop for BorrowRefMut<'b> {
#[inline]
fn drop(&mut self) {

View file

@ -11,7 +11,7 @@
//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about conversions from one type to
//! another. They follow the standard Rust conventions of `as`/`to`/`into`/`from`.
//! another. They follow the standard Rust conventions of `as`/`into`/`from`.
//!
//! Like many traits, these are often used as bounds for generic functions, to support arguments of
//! multiple types.
@ -83,10 +83,8 @@ pub trait Into<T>: Sized {
/// `String` implements `From<&str>`:
///
/// ```
/// let s = "hello";
/// let string = "hello".to_string();
///
/// let other_string: String = From::from(s);
/// let other_string = String::from("hello");
///
/// assert_eq!(string, other_string);
/// ```

View file

@ -34,8 +34,7 @@ mod num;
mod float;
mod builders;
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
#[unstable(feature = "core", reason = "internal to format_args!")]
#[doc(hidden)]
pub mod rt {
pub mod v1;
@ -148,8 +147,7 @@ enum Void {}
/// compile time it is ensured that the function and the value have the correct
/// types, and then this struct is used to canonicalize arguments to one type.
#[derive(Copy)]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
#[unstable(feature = "core", reason = "internal to format_args!")]
#[doc(hidden)]
pub struct ArgumentV1<'a> {
value: &'a Void,
@ -169,8 +167,7 @@ impl<'a> ArgumentV1<'a> {
}
#[doc(hidden)]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
#[unstable(feature = "core", reason = "internal to format_args!")]
pub fn new<'b, T>(x: &'b T,
f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> {
unsafe {
@ -182,8 +179,7 @@ impl<'a> ArgumentV1<'a> {
}
#[doc(hidden)]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
#[unstable(feature = "core", reason = "internal to format_args!")]
pub fn from_usize(x: &usize) -> ArgumentV1 {
ArgumentV1::new(x, ArgumentV1::show_usize)
}
@ -206,8 +202,7 @@ impl<'a> Arguments<'a> {
/// When using the format_args!() macro, this function is used to generate the
/// Arguments structure.
#[doc(hidden)] #[inline]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
#[unstable(feature = "core", reason = "internal to format_args!")]
pub fn new_v1(pieces: &'a [&'a str],
args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
Arguments {
@ -224,8 +219,7 @@ impl<'a> Arguments<'a> {
/// created with `argumentusize`. However, failing to do so doesn't cause
/// unsafety, but will ignore invalid .
#[doc(hidden)] #[inline]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
#[unstable(feature = "core", reason = "internal to format_args!")]
pub fn new_v1_formatted(pieces: &'a [&'a str],
args: &'a [ArgumentV1<'a>],
fmt: &'a [rt::v1::Argument]) -> Arguments<'a> {

View file

@ -14,69 +14,46 @@
//! These definitions are similar to their `ct` equivalents, but differ in that
//! these can be statically allocated and are slightly optimized for the runtime
#![cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
#![unstable(feature = "core", reason = "internal to format_args!")]
#[derive(Copy, Clone)]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub struct Argument {
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub position: Position,
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub format: FormatSpec,
}
#[derive(Copy, Clone)]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub struct FormatSpec {
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub fill: char,
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub align: Alignment,
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub flags: u32,
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub precision: Count,
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub width: Count,
}
/// Possible alignments that can be requested as part of a formatting directive.
#[derive(Copy, Clone, PartialEq)]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub enum Alignment {
/// Indication that contents should be left-aligned.
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Left,
/// Indication that contents should be right-aligned.
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Right,
/// Indication that contents should be center-aligned.
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Center,
/// No alignment was requested.
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Unknown,
}
#[derive(Copy, Clone)]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub enum Count {
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Is(usize),
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Param(usize),
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
NextParam,
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Implied,
}
#[derive(Copy, Clone)]
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub enum Position {
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Next,
#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
At(usize)
}

View file

@ -139,6 +139,21 @@ extern "rust-intrinsic" {
pub fn atomic_fence_rel();
pub fn atomic_fence_acqrel();
/// A compiler-only memory barrier.
///
/// Memory accesses will never be reordered across this barrier by the compiler,
/// but no instructions will be emitted for it. This is appropriate for operations
/// on the same thread that may be preempted, such as when interacting with signal
/// handlers.
#[cfg(not(stage0))] // SNAP 857ef6e
pub fn atomic_singlethreadfence();
#[cfg(not(stage0))] // SNAP 857ef6e
pub fn atomic_singlethreadfence_acq();
#[cfg(not(stage0))] // SNAP 857ef6e
pub fn atomic_singlethreadfence_rel();
#[cfg(not(stage0))] // SNAP 857ef6e
pub fn atomic_singlethreadfence_acqrel();
/// Aborts the execution of the process.
pub fn abort() -> !;
@ -255,12 +270,17 @@ extern "rust-intrinsic" {
/// Returns `true` if a type is managed (will be allocated on the local heap)
pub fn owns_managed<T>() -> bool;
/// Calculates the offset from a pointer. The offset *must* be in-bounds of
/// the object, or one-byte-past-the-end. An arithmetic overflow is also
/// undefined behaviour.
/// Calculates the offset from a pointer.
///
/// This is implemented as an intrinsic to avoid converting to and from an
/// integer, since the conversion would throw away aliasing information.
///
/// # Safety
///
/// Both the starting and resulting pointer must be either in bounds or one
/// byte past the end of an allocated object. If either pointer is out of
/// bounds or arithmetic overflow occurs then any further use of the
/// returned value will result in undefined behavior.
pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
@ -303,14 +323,8 @@ extern "rust-intrinsic" {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
/// dox
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
pub fn copy_nonoverlapping<T>(dst: *mut T, src: *const T, count: usize);
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
/// and destination may overlap.
///
@ -340,14 +354,8 @@ extern "rust-intrinsic" {
/// ```
///
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
/// dox
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
pub fn copy<T>(dst: *mut T, src: *const T, count: usize);
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
/// bytes of memory starting at `dst` to `c`.
#[stable(feature = "rust1", since = "1.0.0")]
@ -572,7 +580,22 @@ extern "rust-intrinsic" {
/// Returns the value of the discriminant for the variant in 'v',
/// cast to a `u64`; if `T` has no discriminant, returns 0.
// SNAP 5520801
#[cfg(not(stage0))]
pub fn discriminant_value<T>(v: &T) -> u64;
}
#[cfg(not(stage0))]
extern "rust-intrinsic" {
/// Performs an unchecked signed division, which results in undefined behavior,
/// in cases where y == 0, or x == int::MIN and y == -1
pub fn unchecked_sdiv<T>(x: T, y: T) -> T;
/// Performs an unchecked unsigned division, which results in undefined behavior,
/// in cases where y == 0
pub fn unchecked_udiv<T>(x: T, y: T) -> T;
/// Returns the remainder of an unchecked signed division, which results in
/// undefined behavior, in cases where y == 0, or x == int::MIN and y == -1
pub fn unchecked_urem<T>(x: T, y: T) -> T;
/// Returns the remainder of an unchecked signed division, which results in
/// undefined behavior, in cases where y == 0
pub fn unchecked_srem<T>(x: T, y: T) -> T;
}

View file

@ -179,8 +179,8 @@ pub trait Iterator {
/// Creates an iterator that iterates over both this and the specified
/// iterators simultaneously, yielding the two elements as pairs. When
/// either iterator returns `None`, all further invocations of next() will
/// return `None`.
/// either iterator returns `None`, all further invocations of `next()`
/// will return `None`.
///
/// # Examples
///
@ -2407,12 +2407,14 @@ pub trait Step: PartialOrd {
/// `start` should always be less than `end`, so the result should never
/// be negative.
///
/// `by` must be > 0.
///
/// Returns `None` if it is not possible to calculate steps_between
/// without overflow.
fn steps_between(start: &Self, end: &Self, by: &Self) -> Option<usize>;
}
macro_rules! step_impl {
macro_rules! step_impl_unsigned {
($($t:ty)*) => ($(
impl Step for $t {
#[inline]
@ -2423,7 +2425,33 @@ macro_rules! step_impl {
#[allow(trivial_numeric_casts)]
fn steps_between(start: &$t, end: &$t, by: &$t) -> Option<usize> {
if *start <= *end {
Some(((*end - *start) / *by) as usize)
// Note: We assume $t <= usize here
Some((*end - *start) as usize / (*by as usize))
} else {
Some(0)
}
}
}
)*)
}
macro_rules! step_impl_signed {
($($t:ty)*) => ($(
impl Step for $t {
#[inline]
fn step(&self, by: &$t) -> Option<$t> {
(*self).checked_add(*by)
}
#[inline]
#[allow(trivial_numeric_casts)]
fn steps_between(start: &$t, end: &$t, by: &$t) -> Option<usize> {
if *start <= *end {
// Note: We assume $t <= isize here
// Use .wrapping_sub and cast to usize to compute the
// difference that may not fit inside the range of isize.
Some(
((*end as isize).wrapping_sub(*start as isize) as usize
/ (*by as usize))
)
} else {
Some(0)
}
@ -2447,9 +2475,12 @@ macro_rules! step_impl_no_between {
)*)
}
step_impl!(usize u8 u16 u32 isize i8 i16 i32);
step_impl_unsigned!(usize u8 u16 u32);
step_impl_signed!(isize i8 i16 i32);
#[cfg(target_pointer_width = "64")]
step_impl!(u64 i64);
step_impl_unsigned!(u64);
#[cfg(target_pointer_width = "64")]
step_impl_signed!(i64);
#[cfg(target_pointer_width = "32")]
step_impl_no_between!(u64 i64);

View file

@ -65,7 +65,7 @@
#![feature(intrinsics, lang_items)]
#![feature(on_unimplemented)]
#![feature(simd, unsafe_destructor)]
#![feature(simd)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]

View file

@ -35,20 +35,10 @@ use hash::Hasher;
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="send"]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
#[cfg(not(stage0))]
pub unsafe trait Send {
// empty.
}
/// Types able to be transferred across thread boundaries.
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="send"]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
#[cfg(stage0)]
pub unsafe trait Send : MarkerTrait {
// empty.
}
unsafe impl Send for .. { }
impl<T> !Send for *const T { }
@ -60,21 +50,10 @@ impl !Send for Managed { }
#[lang="sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[cfg(not(stage0))]
pub trait Sized {
// Empty.
}
/// Types with a constant size known at compile-time.
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[cfg(stage0)]
pub trait Sized : MarkerTrait {
// Empty.
}
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
///
/// By default, variable bindings have 'move semantics.' In other
@ -222,7 +201,6 @@ pub trait Copy : Clone {
/// wrapper around the value(s) which can be mutated when behind a `&`
/// reference; not doing this is undefined behaviour (for example,
/// `transmute`-ing from `&T` to `&mut T` is illegal).
#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sync"]
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
@ -230,15 +208,6 @@ pub unsafe trait Sync {
// Empty
}
/// dox
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sync"]
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
pub unsafe trait Sync : MarkerTrait {
// Empty
}
unsafe impl Sync for .. { }
impl<T> !Sync for *const T { }
@ -301,20 +270,6 @@ macro_rules! impls{
)
}
/// dox
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
pub trait MarkerTrait : PhantomFn<Self,Self> { }
#[cfg(stage0)]
impl<T: ?Sized> MarkerTrait for T {}
/// dox
#[lang="phantom_fn"]
#[cfg(stage0)]
pub trait PhantomFn<A:?Sized,R:?Sized=()> {
}
/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
/// even though it does not. This allows you to inform the compiler about certain safety properties
/// of your code.
@ -461,14 +416,6 @@ mod impls {
#[rustc_reflect_like]
#[unstable(feature = "core", reason = "requires RFC and more experience")]
#[allow(deprecated)]
#[cfg(not(stage0))]
pub trait Reflect {}
/// dox
#[rustc_reflect_like]
#[unstable(feature = "core", reason = "requires RFC and more experience")]
#[cfg(stage0)]
pub trait Reflect: MarkerTrait {}
impl Reflect for .. { }

View file

@ -12,16 +12,10 @@
use marker::Sized;
use ops::Deref;
#[cfg(stage0)] use marker::MarkerTrait;
/// Unsafe trait to indicate what types are usable with the NonZero struct
#[cfg(not(stage0))]
pub unsafe trait Zeroable {}
/// Unsafe trait to indicate what types are usable with the NonZero struct
#[cfg(stage0)]
pub unsafe trait Zeroable: MarkerTrait {}
unsafe impl<T:?Sized> Zeroable for *const T {}
unsafe impl<T:?Sized> Zeroable for *mut T {}
unsafe impl Zeroable for isize {}

View file

@ -745,7 +745,20 @@ macro_rules! uint_impl {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn trailing_zeros(self) -> u32 {
unsafe { $cttz(self as $ActualT) as u32 }
// As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic
// emits two conditional moves on x86_64. By promoting the value to
// u16 and setting bit 8, we get better code without any conditional
// operations.
// FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284)
// pending, remove this workaround once LLVM generates better code
// for cttz8.
unsafe {
if $BITS == 8 {
intrinsics::cttz16(self as u16 | 0x100) as u32
} else {
$cttz(self as $ActualT) as u32
}
}
}
/// Shifts the bits to the left by a specified amount, `n`,

View file

@ -508,8 +508,6 @@ macro_rules! neg_impl_numeric {
macro_rules! neg_impl_unsigned {
($($t:ty)*) => {
neg_impl_core!{ x => {
#[cfg(stage0)]
use ::num::wrapping::WrappingOps;
!x.wrapping_add(1)
}, $($t)*} }
}
@ -1162,7 +1160,6 @@ pub trait FnOnce<Args> {
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
#[cfg(not(stage0))]
mod impls {
use marker::Sized;
use super::{Fn, FnMut, FnOnce};

View file

@ -106,28 +106,11 @@ use cmp::Ordering::{self, Less, Equal, Greater};
// FIXME #19649: intrinsic docs don't render, so these have no docs :(
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub use intrinsics::copy_nonoverlapping;
/// dox
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
intrinsics::copy_nonoverlapping(dst, src, count)
}
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub use intrinsics::copy;
/// dox
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
intrinsics::copy(dst, src, count)
}
#[stable(feature = "rust1", since = "1.0.0")]
pub use intrinsics::write_bytes;
@ -301,9 +284,10 @@ impl<T: ?Sized> *const T {
///
/// # Safety
///
/// The offset must be in-bounds of the object, or one-byte-past-the-end.
/// Otherwise `offset` invokes Undefined Behaviour, regardless of whether
/// the pointer is used.
/// Both the starting and resulting pointer must be either in bounds or one
/// byte past the end of an allocated object. If either pointer is out of
/// bounds or arithmetic overflow occurs then
/// any further use of the returned value will result in undefined behavior.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub unsafe fn offset(self, count: isize) -> *const T where T: Sized {

View file

@ -625,6 +625,36 @@ impl<'a, T> IntoIterator for &'a mut [T] {
}
}
#[inline(always)]
fn size_from_ptr<T>(_: *const T) -> usize {
mem::size_of::<T>()
}
// Use macro to be generic over const/mut
macro_rules! slice_offset {
($ptr:expr, $by:expr) => {{
let ptr = $ptr;
if size_from_ptr(ptr) == 0 {
transmute(ptr as usize + $by)
} else {
ptr.offset($by)
}
}};
}
macro_rules! slice_ref {
($ptr:expr) => {{
let ptr = $ptr;
if size_from_ptr(ptr) == 0 {
// Use a non-null pointer value
&mut *(1 as *mut _)
} else {
transmute(ptr)
}
}};
}
// The shared definition of the `Iter` and `IterMut` iterators
macro_rules! iterator {
(struct $name:ident -> $ptr:ty, $elem:ty) => {
@ -641,20 +671,9 @@ macro_rules! iterator {
if self.ptr == self.end {
None
} else {
if mem::size_of::<T>() == 0 {
// purposefully don't use 'ptr.offset' because for
// vectors with 0-size elements this would return the
// same pointer.
self.ptr = transmute(self.ptr as usize + 1);
// Use a non-null pointer value
Some(&mut *(1 as *mut _))
} else {
let old = self.ptr;
self.ptr = self.ptr.offset(1);
Some(transmute(old))
}
let old = self.ptr;
self.ptr = slice_offset!(self.ptr, 1);
Some(slice_ref!(old))
}
}
}
@ -666,6 +685,22 @@ macro_rules! iterator {
let exact = diff / (if size == 0 {1} else {size});
(exact, Some(exact))
}
#[inline]
fn count(self) -> usize {
self.size_hint().0
}
#[inline]
fn nth(&mut self, n: usize) -> Option<$elem> {
// Call helper method. Can't put the definition here because mut versus const.
self.iter_nth(n)
}
#[inline]
fn last(mut self) -> Option<$elem> {
self.next_back()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -679,17 +714,8 @@ macro_rules! iterator {
if self.end == self.ptr {
None
} else {
if mem::size_of::<T>() == 0 {
// See above for why 'ptr.offset' isn't used
self.end = transmute(self.end as usize - 1);
// Use a non-null pointer value
Some(&mut *(1 as *mut _))
} else {
self.end = self.end.offset(-1);
Some(transmute(self.end))
}
self.end = slice_offset!(self.end, -1);
Some(slice_ref!(self.end))
}
}
}
@ -785,6 +811,20 @@ impl<'a, T> Iter<'a, T> {
pub fn as_slice(&self) -> &'a [T] {
make_slice!(T => &'a [T]: self.ptr, self.end)
}
// Helper function for Iter::nth
fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
match self.as_slice().get(n) {
Some(elem_ref) => unsafe {
self.ptr = slice_offset!(elem_ref as *const _, 1);
Some(slice_ref!(elem_ref))
},
None => {
self.ptr = self.end;
None
}
}
}
}
iterator!{struct Iter -> *const T, &'a T}
@ -914,6 +954,20 @@ impl<'a, T> IterMut<'a, T> {
pub fn into_slice(self) -> &'a mut [T] {
make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
}
// Helper function for IterMut::nth
fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
Some(elem_ref) => unsafe {
self.ptr = slice_offset!(elem_ref as *mut _, 1);
Some(slice_ref!(elem_ref))
},
None => {
self.ptr = self.end;
None
}
}
}
}
iterator!{struct IterMut -> *mut T, &'a mut T}

View file

@ -11,6 +11,7 @@
use core::iter::*;
use core::iter::order::*;
use core::iter::MinMaxResult::*;
use core::isize;
use core::usize;
use core::cmp;
@ -758,6 +759,11 @@ fn test_range() {
assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1)));
assert_eq!((-10..-1).size_hint(), (9, Some(9)));
assert_eq!((-1..-10).size_hint(), (0, Some(0)));
assert_eq!((-70..58i8).size_hint(), (128, Some(128)));
assert_eq!((-128..127i8).size_hint(), (255, Some(255)));
assert_eq!((-2..isize::MAX).size_hint(),
(isize::MAX as usize + 2, Some(isize::MAX as usize + 2)));
}
#[test]

View file

@ -13,7 +13,6 @@
#![feature(box_syntax)]
#![feature(unboxed_closures)]
#![feature(unsafe_destructor)]
#![feature(core)]
#![feature(test)]
#![feature(rand)]

View file

@ -45,7 +45,7 @@ pub fn test_num<T>(ten: T, two: T) where
}
#[cfg(test)]
mod test {
mod tests {
use core::option::Option;
use core::option::Option::{Some, None};
use core::num::Float;

View file

@ -44,8 +44,7 @@ fn test_get_resource() {
i: Rc<RefCell<isize>>,
}
#[unsafe_destructor]
impl Drop for R {
impl Drop for R {
fn drop(&mut self) {
let ii = &*self.i;
let i = *ii.borrow();
@ -220,7 +219,6 @@ fn test_ord() {
assert!(big > None);
}
/* FIXME(#20575)
#[test]
fn test_collect() {
let v: Option<Vec<isize>> = (0..0).map(|_| Some(0)).collect();
@ -242,28 +240,26 @@ fn test_collect() {
assert!(v == None);
}
*/
#[test]
fn test_cloned() {
let val1 = 1u32;
let mut val2 = 2u32;
let val1_ref = &val1;
let val = 1u32;
let val_ref = &val;
let opt_none: Option<&'static u32> = None;
let opt_ref = Some(&val1);
let opt_ref_ref = Some(&val1_ref);
let opt_mut_ref = Some(&mut val2);
let opt_ref = Some(&val);
let opt_ref_ref = Some(&val_ref);
// None works
assert_eq!(opt_none.clone(), None);
assert_eq!(opt_none.cloned(), None);
// Immutable ref works
assert_eq!(opt_ref.clone(), Some(&val1));
assert_eq!(opt_ref.clone(), Some(&val));
assert_eq!(opt_ref.cloned(), Some(1u32));
// Double Immutable ref works
assert_eq!(opt_ref_ref.clone(), Some(&val1_ref));
assert_eq!(opt_ref_ref.clone().cloned(), Some(&val1));
assert_eq!(opt_ref_ref.clone(), Some(&val_ref));
assert_eq!(opt_ref_ref.clone().cloned(), Some(&val));
assert_eq!(opt_ref_ref.cloned().cloned(), Some(1u32));
}

View file

@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub fn op1() -> Result<isize, &'static str> { Ok(666) }
pub fn op2() -> Result<isize, &'static str> { Err("sadface") }
fn op1() -> Result<isize, &'static str> { Ok(666) }
fn op2() -> Result<isize, &'static str> { Err("sadface") }
#[test]
pub fn test_and() {
fn test_and() {
assert_eq!(op1().and(Ok(667)).unwrap(), 667);
assert_eq!(op1().and(Err::<i32, &'static str>("bad")).unwrap_err(),
"bad");
@ -23,7 +23,7 @@ pub fn test_and() {
}
#[test]
pub fn test_and_then() {
fn test_and_then() {
assert_eq!(op1().and_then(|i| Ok::<isize, &'static str>(i + 1)).unwrap(), 667);
assert_eq!(op1().and_then(|_| Err::<isize, &'static str>("bad")).unwrap_err(),
"bad");
@ -35,7 +35,7 @@ pub fn test_and_then() {
}
#[test]
pub fn test_or() {
fn test_or() {
assert_eq!(op1().or(Ok::<_, &'static str>(667)).unwrap(), 666);
assert_eq!(op1().or(Err("bad")).unwrap(), 666);
@ -44,7 +44,7 @@ pub fn test_or() {
}
#[test]
pub fn test_or_else() {
fn test_or_else() {
assert_eq!(op1().or_else(|_| Ok::<isize, &'static str>(667)).unwrap(), 666);
assert_eq!(op1().or_else(|e| Err::<isize, &'static str>(e)).unwrap(), 666);
@ -54,18 +54,17 @@ pub fn test_or_else() {
}
#[test]
pub fn test_impl_map() {
fn test_impl_map() {
assert!(Ok::<isize, isize>(1).map(|x| x + 1) == Ok(2));
assert!(Err::<isize, isize>(1).map(|x| x + 1) == Err(1));
}
#[test]
pub fn test_impl_map_err() {
fn test_impl_map_err() {
assert!(Ok::<isize, isize>(1).map_err(|x| x + 1) == Ok(1));
assert!(Err::<isize, isize>(1).map_err(|x| x + 1) == Err(2));
}
/* FIXME(#20575)
#[test]
fn test_collect() {
let v: Result<Vec<isize>, ()> = (0..0).map(|_| Ok::<isize, ()>(0)).collect();
@ -86,10 +85,9 @@ fn test_collect() {
let v: Result<Vec<()>, isize> = functions.iter_mut().map(|f| (*f)()).collect();
assert!(v == Err(1));
}
*/
#[test]
pub fn test_fmt_default() {
fn test_fmt_default() {
let ok: Result<isize, &'static str> = Ok(100);
let err: Result<isize, &'static str> = Err("Err");
@ -100,7 +98,7 @@ pub fn test_fmt_default() {
}
#[test]
pub fn test_unwrap_or() {
fn test_unwrap_or() {
let ok: Result<isize, &'static str> = Ok(100);
let ok_err: Result<isize, &'static str> = Err("Err");
@ -109,7 +107,7 @@ pub fn test_unwrap_or() {
}
#[test]
pub fn test_unwrap_or_else() {
fn test_unwrap_or_else() {
fn handler(msg: &'static str) -> isize {
if msg == "I got this." {
50

View file

@ -82,3 +82,34 @@ fn iterator_to_slice() {
test!([1u8,2,3]);
test!([(),(),()]);
}
#[test]
fn test_iterator_nth() {
let v: &[_] = &[0, 1, 2, 3, 4];
for i in 0..v.len() {
assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
}
assert_eq!(v.iter().nth(v.len()), None);
let mut iter = v.iter();
assert_eq!(iter.nth(2).unwrap(), &v[2]);
assert_eq!(iter.nth(1).unwrap(), &v[4]);
}
#[test]
fn test_iterator_last() {
let v: &[_] = &[0, 1, 2, 3, 4];
assert_eq!(v.iter().last().unwrap(), &4);
assert_eq!(v[..1].iter().last().unwrap(), &0);
}
#[test]
fn test_iterator_count() {
let v: &[_] = &[0, 1, 2, 3, 4];
assert_eq!(v.iter().count(), 5);
let mut iter2 = v.iter();
iter2.next();
iter2.next();
assert_eq!(iter2.count(), 3);
}

View file

@ -140,11 +140,15 @@ pub use funcs::bsd43::*;
// On NaCl, these libraries are static. Thus it would be a Bad Idea to link them
// in when creating a test crate.
#[cfg(not(any(windows, all(target_os = "nacl", test))))]
#[cfg(not(any(windows, target_env = "musl", all(target_os = "nacl", test))))]
#[link(name = "c")]
#[link(name = "m")]
extern {}
#[cfg(all(target_env = "musl", not(test)))]
#[link(name = "c", kind = "static")]
extern {}
// libnacl provides functions that require a trip through the IRT to work.
// ie: _exit, mmap, nanosleep, etc. Anything that would otherwise require a trip
// to the kernel.

View file

@ -202,7 +202,7 @@ impl Rand for ChaChaRng {
#[cfg(test)]
mod test {
mod tests {
use std::prelude::v1::*;
use core::iter::order;

View file

@ -82,7 +82,7 @@ impl IndependentSample<f64> for Exp {
}
#[cfg(test)]
mod test {
mod tests {
use std::prelude::v1::*;
use distributions::{Sample, IndependentSample};

View file

@ -276,7 +276,7 @@ impl IndependentSample<f64> for StudentT {
}
#[cfg(test)]
mod test {
mod tests {
use std::prelude::v1::*;
use distributions::{Sample, IndependentSample};

View file

@ -510,7 +510,7 @@ impl Rand for Isaac64Rng {
#[cfg(test)]
mod test {
mod tests {
use std::prelude::v1::*;
use core::iter::order;

View file

@ -120,7 +120,7 @@ impl Default for ReseedWithDefault {
}
#[cfg(test)]
mod test {
mod tests {
use std::prelude::v1::*;
use core::iter::{order, repeat};

View file

@ -71,7 +71,7 @@ The rustc crate itself consists of the following submodules
- util: ubiquitous types and helper functions
- lib: bindings to LLVM
The entry-point for the compiler is main() in the librustc_trans
The entry-point for the compiler is main() in the librustc_driver
crate.
The 3 central data structures:

View file

@ -168,6 +168,25 @@ match x {
```
"##,
E0013: r##"
Static and const variables can refer to other const variables. But a const
variable cannot refer to a static variable. For example, `Y` cannot refer to `X`
here:
```
static X: i32 = 42;
const Y: i32 = X;
```
To fix this, the value can be extracted as a const and then used:
```
const A: i32 = 42;
static X: i32 = A;
const Y: i32 = A;
```
"##,
E0015: r##"
The only function calls allowed in static or constant expressions are enum
variant constructors or struct constructors (for unit or tuple structs). This
@ -336,6 +355,22 @@ enum Method { GET, POST }
```
"##,
E0265: r##"
This error indicates that a static or constant references itself.
All statics and constants need to resolve to a value in an acyclic manner.
For example, neither of the following can be sensibly compiled:
```
const X: u32 = X;
```
```
const X: u32 = Y;
const Y: u32 = X;
```
"##,
E0267: r##"
This error indicates the use of loop keyword (break or continue) inside a
closure but outside of any loop. Break and continue can be used as normal
@ -462,7 +497,6 @@ register_diagnostics! {
E0010,
E0011,
E0012,
E0013,
E0014,
E0016,
E0017,
@ -482,7 +516,6 @@ register_diagnostics! {
E0262, // illegal lifetime parameter name
E0263, // lifetime name declared twice in same scope
E0264, // unknown external lang item
E0265, // recursive constant
E0266, // expected item
E0269, // not all control paths return a value
E0270, // computation may converge in a function marked as diverging
@ -517,5 +550,3 @@ register_diagnostics! {
E0316, // nested quantification of lifetimes
E0370 // discriminant overflow
}
__build_diagnostic_array! { DIAGNOSTICS }

View file

@ -25,22 +25,23 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(fs_canonicalize)]
#![feature(hash)]
#![feature(into_cow)]
#![feature(libc)]
#![feature(path_ext)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(unsafe_destructor)]
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(std_misc)]
#![feature(path_ext)]
#![feature(str_char)]
#![feature(into_cow)]
#![feature(slice_patterns)]
#![cfg_attr(test, feature(test))]
#![allow(trivial_casts)]
@ -139,7 +140,6 @@ pub mod plugin;
pub mod lint;
pub mod util {
pub use rustc_back::fs;
pub use rustc_back::sha2;
pub mod common;
@ -161,3 +161,9 @@ pub mod lib {
mod rustc {
pub use lint;
}
// Build the diagnostics array at the end so that the metadata includes error use sites.
#[cfg(stage0)]
__build_diagnostic_array! { DIAGNOSTICS }
#[cfg(not(stage0))]
__build_diagnostic_array! { librustc, DIAGNOSTICS }

View file

@ -21,8 +21,10 @@ use metadata::decoder;
use metadata::loader;
use metadata::loader::CratePaths;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::rc::Rc;
use std::fs;
use syntax::ast;
use syntax::abi;
use syntax::attr;
@ -32,7 +34,6 @@ use syntax::parse;
use syntax::parse::token::InternedString;
use syntax::parse::token;
use syntax::visit;
use util::fs;
use log;
pub struct CrateReader<'a> {
@ -322,7 +323,7 @@ impl<'a> CrateReader<'a> {
let source = self.sess.cstore.get_used_crate_source(cnum).unwrap();
if let Some(locs) = self.sess.opts.externs.get(name) {
let found = locs.iter().any(|l| {
let l = fs::realpath(&Path::new(&l[..])).ok();
let l = fs::canonicalize(l).ok();
source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
});
@ -664,7 +665,7 @@ fn import_codemap(local_codemap: &codemap::CodeMap,
.into_inner()
.map_in_place(|mbc|
codemap::MultiByteChar {
pos: mbc.pos + start_pos,
pos: mbc.pos - start_pos,
bytes: mbc.bytes
});

View file

@ -175,6 +175,13 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
}
pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.node, tcx)
}
pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: ast::DefId)
-> Option<ast::Name> {
let cdata = cstore.get_crate_data(def.krate);

View file

@ -305,7 +305,25 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
-> DefLike {
let fam = item_family(item);
match fam {
Constant => DlDef(def::DefConst(did)),
Constant => {
// Check whether we have an associated const item.
if item_sort(item) == Some('C') {
// Check whether the associated const is from a trait or impl.
// See the comment for methods below.
let provenance = if reader::maybe_get_doc(
item, tag_item_trait_parent_sort).is_some() {
def::FromTrait(item_reqd_and_translated_parent_item(cnum,
item))
} else {
def::FromImpl(item_reqd_and_translated_parent_item(cnum,
item))
};
DlDef(def::DefAssociatedConst(did, provenance))
} else {
// Regular const item.
DlDef(def::DefConst(did))
}
}
ImmStatic => DlDef(def::DefStatic(did, false)),
MutStatic => DlDef(def::DefStatic(did, true)),
Struct => DlDef(def::DefStruct(did)),
@ -826,6 +844,7 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
tag_item_impl_item, |doc| {
let def_id = item_def_id(doc, cdata);
match item_sort(doc) {
Some('C') => impl_items.push(ty::ConstTraitItemId(def_id)),
Some('r') | Some('p') => {
impl_items.push(ty::MethodTraitItemId(def_id))
}
@ -877,6 +896,18 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
let vis = item_visibility(method_doc);
match item_sort(method_doc) {
Some('C') => {
let ty = doc_type(method_doc, tcx, cdata);
let default = get_provided_source(method_doc, cdata);
ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
name: name,
ty: ty,
vis: vis,
def_id: def_id,
container: container,
default: default,
}))
}
Some('r') | Some('p') => {
let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
@ -914,6 +945,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
reader::tagged_docs(item, tag_item_trait_item, |mth| {
let def_id = item_def_id(mth, cdata);
match item_sort(mth) {
Some('C') => result.push(ty::ConstTraitItemId(def_id)),
Some('r') | Some('p') => {
result.push(ty::MethodTraitItemId(def_id));
}
@ -951,11 +983,8 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
cdata,
did.node,
tcx);
match trait_item {
ty::MethodTraitItem(ref method) => {
result.push((*method).clone())
}
ty::TypeTraitItem(_) => {}
if let ty::MethodTraitItem(ref method) = trait_item {
result.push((*method).clone())
}
}
true
@ -964,6 +993,36 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
return result;
}
pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId,
tcx: &ty::ctxt<'tcx>)
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
let data = cdata.data();
let item = lookup_item(id, data);
let mut result = Vec::new();
for &tag in &[tag_item_trait_item, tag_item_impl_item] {
reader::tagged_docs(item, tag, |ac_id| {
let did = item_def_id(ac_id, cdata);
let ac_doc = lookup_item(did.node, data);
if item_sort(ac_doc) == Some('C') {
let trait_item = get_impl_or_trait_item(intr.clone(),
cdata,
did.node,
tcx);
if let ty::ConstTraitItem(ref ac) = trait_item {
result.push((*ac).clone())
}
}
true
});
}
return result;
}
pub fn get_type_name_if_impl(cdata: Cmd,
node_id: ast::NodeId) -> Option<ast::Name> {
let item = lookup_item(node_id, cdata.data());

View file

@ -378,14 +378,11 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
let impl_item = ty::impl_or_trait_item(
ecx.tcx,
method_did.def_id());
match impl_item {
ty::MethodTraitItem(ref m) => {
encode_reexported_static_method(rbml_w,
exp,
m.def_id,
m.name);
}
ty::TypeTraitItem(_) => {}
if let ty::MethodTraitItem(ref m) = impl_item {
encode_reexported_static_method(rbml_w,
exp,
m.def_id,
m.name);
}
}
}
@ -802,6 +799,43 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
encode_provided_source(rbml_w, method_ty.provided_source);
}
fn encode_info_for_associated_const(ecx: &EncodeContext,
rbml_w: &mut Encoder,
associated_const: &ty::AssociatedConst,
impl_path: PathElems,
parent_id: NodeId,
impl_item_opt: Option<&ast::ImplItem>) {
debug!("encode_info_for_associated_const({:?},{:?})",
associated_const.def_id,
token::get_name(associated_const.name));
rbml_w.start_tag(tag_items_data_item);
encode_def_id(rbml_w, associated_const.def_id);
encode_name(rbml_w, associated_const.name);
encode_visibility(rbml_w, associated_const.vis);
encode_family(rbml_w, 'C');
encode_provided_source(rbml_w, associated_const.default);
encode_parent_item(rbml_w, local_def(parent_id));
encode_item_sort(rbml_w, 'C');
encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id());
let stab = stability::lookup(ecx.tcx, associated_const.def_id);
encode_stability(rbml_w, stab);
let elem = ast_map::PathName(associated_const.name);
encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ii));
}
rbml_w.end_tag();
}
fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
m: &ty::Method<'tcx>,
@ -1195,6 +1229,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
for &item_def_id in items {
rbml_w.start_tag(tag_item_impl_item);
match item_def_id {
ty::ConstTraitItemId(item_def_id) => {
encode_def_id(rbml_w, item_def_id);
encode_item_sort(rbml_w, 'C');
}
ty::MethodTraitItemId(item_def_id) => {
encode_def_id(rbml_w, item_def_id);
encode_item_sort(rbml_w, 'r');
@ -1232,6 +1270,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
});
match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) {
ty::ConstTraitItem(ref associated_const) => {
encode_info_for_associated_const(ecx,
rbml_w,
&*associated_const,
path.clone(),
item.id,
ast_item)
}
ty::MethodTraitItem(ref method_type) => {
encode_info_for_method(ecx,
rbml_w,
@ -1276,6 +1322,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
for &method_def_id in &*ty::trait_item_def_ids(tcx, def_id) {
rbml_w.start_tag(tag_item_trait_item);
match method_def_id {
ty::ConstTraitItemId(const_def_id) => {
encode_def_id(rbml_w, const_def_id);
encode_item_sort(rbml_w, 'C');
}
ty::MethodTraitItemId(method_def_id) => {
encode_def_id(rbml_w, method_def_id);
encode_item_sort(rbml_w, 'r');
@ -1321,6 +1371,25 @@ fn encode_info_for_item(ecx: &EncodeContext,
ty::impl_or_trait_item(tcx, item_def_id.def_id());
let is_nonstatic_method;
match trait_item_type {
ty::ConstTraitItem(associated_const) => {
encode_name(rbml_w, associated_const.name);
encode_def_id(rbml_w, associated_const.def_id);
encode_visibility(rbml_w, associated_const.vis);
encode_provided_source(rbml_w, associated_const.default);
let elem = ast_map::PathName(associated_const.name);
encode_path(rbml_w,
path.clone().chain(Some(elem).into_iter()));
encode_item_sort(rbml_w, 'C');
encode_family(rbml_w, 'C');
encode_bounds_and_type_for_item(rbml_w, ecx,
associated_const.def_id.local_id());
is_nonstatic_method = false;
}
ty::MethodTraitItem(method_ty) => {
let method_def_id = item_def_id.def_id();
@ -1365,6 +1434,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
let trait_item = &*ms[i];
encode_attributes(rbml_w, &trait_item.attrs);
match trait_item.node {
ast::ConstTraitItem(_, _) => {
encode_inlined_item(ecx, rbml_w,
IITraitItemRef(def_id, trait_item));
}
ast::MethodTraitItem(ref sig, ref body) => {
// If this is a static method, we've already
// encoded this.
@ -1384,9 +1457,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_method_argument_names(rbml_w, &sig.decl);
}
ast::TypeTraitItem(..) => {
encode_item_sort(rbml_w, 't');
}
ast::TypeTraitItem(..) => {}
}
rbml_w.end_tag();

View file

@ -18,7 +18,6 @@ use std::fs;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use util::fs as myfs;
use session::search_paths::{SearchPaths, PathKind};
#[derive(Copy, Clone)]
@ -191,7 +190,7 @@ pub fn get_or_default_sysroot() -> PathBuf {
// Follow symlinks. If the resolved path is relative, make it absolute.
fn canonicalize(path: Option<PathBuf>) -> Option<PathBuf> {
path.and_then(|path| {
match myfs::realpath(&path) {
match fs::canonicalize(&path) {
Ok(canon) => Some(canon),
Err(e) => panic!("failed to get realpath: {}", e),
}

View file

@ -225,12 +225,12 @@ use metadata::encoder;
use metadata::filesearch::{FileSearch, FileMatches, FileDoesntMatch};
use syntax::codemap::Span;
use syntax::diagnostic::SpanHandler;
use util::fs;
use util::common;
use rustc_back::target::Target;
use std::cmp;
use std::collections::HashMap;
use std::fs;
use std::io::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
@ -430,9 +430,9 @@ impl<'a> Context<'a> {
.or_insert_with(|| (HashMap::new(), HashMap::new()));
let (ref mut rlibs, ref mut dylibs) = *slot;
if rlib {
rlibs.insert(fs::realpath(path).unwrap(), kind);
rlibs.insert(fs::canonicalize(path).unwrap(), kind);
} else {
dylibs.insert(fs::realpath(path).unwrap(), kind);
dylibs.insert(fs::canonicalize(path).unwrap(), kind);
}
FileMatches
@ -660,10 +660,10 @@ impl<'a> Context<'a> {
// there's at most one rlib and at most one dylib.
for loc in locs {
if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
rlibs.insert(fs::realpath(&loc).unwrap(),
rlibs.insert(fs::canonicalize(&loc).unwrap(),
PathKind::ExternFlag);
} else {
dylibs.insert(fs::realpath(&loc).unwrap(),
dylibs.insert(fs::canonicalize(&loc).unwrap(),
PathKind::ExternFlag);
}
}

View file

@ -465,6 +465,9 @@ impl tr for def::Def {
def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
def::DefAssociatedConst(did, p) => {
def::DefAssociatedConst(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
}
def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
def::DefVariant(e_did, v_did, is_s) => {
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
@ -1835,29 +1838,31 @@ fn decode_item_ast(par_doc: rbml::Doc) -> ast::Item {
}
#[cfg(test)]
trait fake_ext_ctxt {
trait FakeExtCtxt {
fn call_site(&self) -> codemap::Span;
fn cfg(&self) -> ast::CrateConfig;
fn parse_sess<'a>(&'a self) -> &'a parse::ParseSess;
fn call_site(&self) -> Span;
fn ident_of(&self, st: &str) -> ast::Ident;
fn name_of(&self, st: &str) -> ast::Name;
fn parse_sess(&self) -> &parse::ParseSess;
}
#[cfg(test)]
impl fake_ext_ctxt for parse::ParseSess {
fn cfg(&self) -> ast::CrateConfig {
Vec::new()
}
fn parse_sess<'a>(&'a self) -> &'a parse::ParseSess { self }
fn call_site(&self) -> Span {
impl FakeExtCtxt for parse::ParseSess {
fn call_site(&self) -> codemap::Span {
codemap::Span {
lo: codemap::BytePos(0),
hi: codemap::BytePos(0),
expn_id: codemap::NO_EXPANSION
expn_id: codemap::NO_EXPANSION,
}
}
fn cfg(&self) -> ast::CrateConfig { Vec::new() }
fn ident_of(&self, st: &str) -> ast::Ident {
token::str_to_ident(st)
parse::token::str_to_ident(st)
}
fn name_of(&self, st: &str) -> ast::Name {
parse::token::intern(st)
}
fn parse_sess(&self) -> &parse::ParseSess { self }
}
#[cfg(test)]
@ -1883,7 +1888,7 @@ fn test_basic() {
fn foo() {}
));
}
/* NOTE: When there's a snapshot, update this (yay quasiquoter!)
#[test]
fn test_smalltalk() {
let cx = mk_ctxt();
@ -1891,7 +1896,6 @@ fn test_smalltalk() {
fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed.
));
}
*/
#[test]
fn test_more() {

View file

@ -105,6 +105,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
match pat.node {
ast::PatIdent(_, _, None) |
ast::PatEnum(_, None) |
ast::PatQPath(..) |
ast::PatLit(..) |
ast::PatRange(..) |
ast::PatWild(_) => {

View file

@ -46,33 +46,35 @@ bitflags! {
#[derive(RustcEncodable, RustcDecodable)]
flags ConstQualif: u8 {
// Const rvalue which can be placed behind a reference.
const PURE_CONST = 0b000000,
const PURE_CONST = 0,
// Inner mutability (can not be placed behind a reference) or behind
// &mut in a non-global expression. Can be copied from static memory.
const MUTABLE_MEM = 0b000001,
const MUTABLE_MEM = 1 << 0,
// Constant value with a type that implements Drop. Can be copied
// from static memory, similar to MUTABLE_MEM.
const NEEDS_DROP = 0b000010,
const NEEDS_DROP = 1 << 1,
// Even if the value can be placed in static memory, copying it from
// there is more expensive than in-place instantiation, and/or it may
// be too large. This applies to [T; N] and everything containing it.
// N.B.: references need to clear this flag to not end up on the stack.
const PREFER_IN_PLACE = 0b000100,
const PREFER_IN_PLACE = 1 << 2,
// May use more than 0 bytes of memory, doesn't impact the constness
// directly, but is not allowed to be borrowed mutably in a constant.
const NON_ZERO_SIZED = 0b001000,
const NON_ZERO_SIZED = 1 << 3,
// Actually borrowed, has to always be in static memory. Does not
// propagate, and requires the expression to behave like a 'static
// lvalue. The set of expressions with this flag is the minimum
// that have to be promoted.
const HAS_STATIC_BORROWS = 0b010000,
const HAS_STATIC_BORROWS = 1 << 4,
// Invalid const for miscellaneous reasons (e.g. not implemented).
const NOT_CONST = 0b100000,
const NOT_CONST = 1 << 5,
// Borrowing the expression won't produce &'static T if any of these
// bits are set, though the value could be copied from static memory
// if `NOT_CONST` isn't set.
const NON_STATIC_BORROWS = MUTABLE_MEM.bits | NEEDS_DROP.bits | NOT_CONST.bits
const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
ConstQualif::NEEDS_DROP.bits |
ConstQualif::NOT_CONST.bits
}
}
@ -102,7 +104,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
{
let (old_mode, old_qualif) = (self.mode, self.qualif);
self.mode = mode;
self.qualif = PURE_CONST;
self.qualif = ConstQualif::PURE_CONST;
let r = f(self);
self.mode = old_mode;
self.qualif = old_qualif;
@ -126,7 +128,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
Entry::Occupied(entry) => return *entry.get(),
Entry::Vacant(entry) => {
// Prevent infinite recursion on re-entry.
entry.insert(PURE_CONST);
entry.insert(ConstQualif::PURE_CONST);
}
}
self.with_mode(mode, |this| {
@ -223,6 +225,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
match t.node {
ast::ConstTraitItem(_, ref default) => {
if let Some(ref expr) = *default {
self.global_expr(Mode::Const, &*expr);
} else {
visit::walk_trait_item(self, t);
}
}
_ => self.with_mode(Mode::Var, |v| visit::walk_trait_item(v, t)),
}
}
fn visit_impl_item(&mut self, i: &'v ast::ImplItem) {
match i.node {
ast::ConstImplItem(_, ref expr) => {
self.global_expr(Mode::Const, &*expr);
}
_ => self.with_mode(Mode::Var, |v| visit::walk_impl_item(v, i)),
}
}
fn visit_fn(&mut self,
fk: visit::FnKind<'v>,
fd: &'v ast::FnDecl,
@ -249,7 +273,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
fn visit_expr(&mut self, ex: &ast::Expr) {
let mut outer = self.qualif;
self.qualif = PURE_CONST;
self.qualif = ConstQualif::PURE_CONST;
let node_ty = ty::node_id_to_type(self.tcx, ex.id);
check_expr(self, ex, node_ty);
@ -265,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
self.visit_expr(&**callee);
// The callee's size doesn't count in the call.
let added = self.qualif - inner;
self.qualif = inner | (added - NON_ZERO_SIZED);
self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
}
ast::ExprRepeat(ref element, _) => {
self.visit_expr(&**element);
@ -276,7 +300,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
};
// [element; 0] is always zero-sized.
if count == 0 {
self.qualif = self.qualif - (NON_ZERO_SIZED | PREFER_IN_PLACE);
self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
}
}
ast::ExprMatch(ref discr, ref arms, _) => {
@ -303,7 +327,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
let div_or_rem = op.node == ast::BiDiv || op.node == ast::BiRem;
match node_ty.sty {
ty::ty_uint(_) | ty::ty_int(_) if div_or_rem => {
if !self.qualif.intersects(NOT_CONST) {
if !self.qualif.intersects(ConstQualif::NOT_CONST) {
match const_eval::eval_const_expr_partial(self.tcx, ex, None) {
Ok(_) => {}
Err(msg) => {
@ -326,11 +350,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
// Constants cannot be borrowed if they contain interior mutability as
// it means that our "silent insertion of statics" could change
// initializer values (very bad).
// If the type doesn't have interior mutability, then `MUTABLE_MEM` has
// If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
// propagated from another error, so erroring again would be just noise.
let tc = ty::type_contents(self.tcx, node_ty);
if self.qualif.intersects(MUTABLE_MEM) && tc.interior_unsafe() {
outer = outer | NOT_CONST;
if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
outer = outer | ConstQualif::NOT_CONST;
if self.mode != Mode::Var {
self.tcx.sess.span_err(ex.span,
"cannot borrow a constant which contains \
@ -339,32 +363,32 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
}
// If the reference has to be 'static, avoid in-place initialization
// as that will end up pointing to the stack instead.
if !self.qualif.intersects(NON_STATIC_BORROWS) {
self.qualif = self.qualif - PREFER_IN_PLACE;
self.add_qualif(HAS_STATIC_BORROWS);
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
}
}
Some(ast::MutMutable) => {
// `&mut expr` means expr could be mutated, unless it's zero-sized.
if self.qualif.intersects(NON_ZERO_SIZED) {
if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
if self.mode == Mode::Var {
outer = outer | NOT_CONST;
self.add_qualif(MUTABLE_MEM);
outer = outer | ConstQualif::NOT_CONST;
self.add_qualif(ConstQualif::MUTABLE_MEM);
} else {
span_err!(self.tcx.sess, ex.span, E0017,
"references in {}s may only refer \
to immutable values", self.msg())
}
}
if !self.qualif.intersects(NON_STATIC_BORROWS) {
self.add_qualif(HAS_STATIC_BORROWS);
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
}
}
None => {}
}
self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
// Don't propagate certain flags.
self.qualif = outer | (self.qualif - HAS_STATIC_BORROWS);
self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
}
}
@ -379,7 +403,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
match node_ty.sty {
ty::ty_struct(did, _) |
ty::ty_enum(did, _) if ty::has_dtor(v.tcx, did) => {
v.add_qualif(NEEDS_DROP);
v.add_qualif(ConstQualif::NEEDS_DROP);
if v.mode != Mode::Var {
v.tcx.sess.span_err(e.span,
&format!("{}s are not allowed to have destructors",
@ -394,7 +418,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprUnary(..) |
ast::ExprBinary(..) |
ast::ExprIndex(..) if v.tcx.method_map.borrow().contains_key(&method_call) => {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0011,
"user-defined operators are not allowed in {}s", v.msg());
@ -402,7 +426,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
}
ast::ExprBox(..) |
ast::ExprUnary(ast::UnUniq, _) => {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0010,
"allocations are not allowed in {}s", v.msg());
@ -412,7 +436,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
match ty::node_id_to_type(v.tcx, ptr.id).sty {
ty::ty_ptr(_) => {
// This shouldn't be allowed in constants at all.
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
}
_ => {}
}
@ -425,7 +449,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ty::type_is_unsafe_ptr(toty) ||
(ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty));
if !is_legal_cast {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0012,
"can not cast to `{}` in {}s",
@ -433,7 +457,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
}
}
if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0018,
"can not cast a pointer to an integer in {}s", v.msg());
@ -445,17 +469,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
match def {
Some(def::DefVariant(_, _, _)) => {
// Count the discriminator or function pointer.
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Some(def::DefStruct(_)) => {
if let ty::ty_bare_fn(..) = node_ty.sty {
// Count the function pointer.
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
}
Some(def::DefFn(..)) | Some(def::DefMethod(..)) => {
// Count the function pointer.
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Some(def::DefStatic(..)) => {
match v.mode {
@ -465,20 +489,23 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
"constants cannot refer to other statics, \
insert an intermediate constant instead");
}
Mode::Var => v.add_qualif(NOT_CONST)
Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
}
}
Some(def::DefConst(did)) => {
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did) {
Some(def::DefConst(did)) |
Some(def::DefAssociatedConst(did, _)) => {
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
Some(e.id)) {
let inner = v.global_expr(Mode::Const, expr);
v.add_qualif(inner);
} else {
v.tcx.sess.span_bug(e.span, "DefConst doesn't point \
to an ItemConst");
v.tcx.sess.span_bug(e.span,
"DefConst or DefAssociatedConst \
doesn't point to a constant");
}
}
def => {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
debug!("(checking const) found bad def: {:?}", def);
span_err!(v.tcx.sess, e.span, E0014,
@ -505,10 +532,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
Some(def::DefStruct(..)) => {}
Some(def::DefVariant(..)) => {
// Count the discriminator.
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
_ => {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0015,
"function calls in {}s are limited to \
@ -520,7 +547,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprBlock(ref block) => {
// Check all statements in the block
let mut block_span_err = |span| {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, span, E0016,
"blocks in {}s are limited to items and \
@ -549,17 +576,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprStruct(..) => {
let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
if did == v.tcx.lang_items.unsafe_cell_type() {
v.add_qualif(MUTABLE_MEM);
v.add_qualif(ConstQualif::MUTABLE_MEM);
}
}
ast::ExprLit(_) |
ast::ExprAddrOf(..) => {
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
ast::ExprRepeat(..) => {
v.add_qualif(PREFER_IN_PLACE);
v.add_qualif(ConstQualif::PREFER_IN_PLACE);
}
ast::ExprClosure(..) => {
@ -568,7 +595,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
if ty::with_freevars(v.tcx, e.id, |fv| !fv.is_empty()) {
assert!(v.mode == Mode::Var,
"global closures can't capture anything");
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
}
}
@ -606,7 +633,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprAssignOp(..) |
ast::ExprInlineAsm(_) |
ast::ExprMac(_) => {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0019,
"{} contains unimplemented expression type", v.msg());
@ -619,7 +646,7 @@ pub fn check_crate(tcx: &ty::ctxt) {
visit::walk_crate(&mut CheckCrateVisitor {
tcx: tcx,
mode: Mode::Var,
qualif: NOT_CONST,
qualif: ConstQualif::NOT_CONST,
rvalue_borrows: NodeMap()
}, tcx.map.krate());

View file

@ -439,10 +439,11 @@ impl<'map> ast_util::IdVisitingOperation for RenamingRecorder<'map> {
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
return match pat.node {
ast::PatIdent(..) | ast::PatEnum(..) => {
ast::PatIdent(..) | ast::PatEnum(..) | ast::PatQPath(..) => {
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
match def {
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
Some(DefAssociatedConst(did, _)) |
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) {
Some(const_expr) => {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
@ -746,7 +747,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
match pat.node {
ast::PatIdent(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
Some(DefConst(..)) =>
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
Some(DefStruct(_)) => vec!(Single),
@ -755,15 +756,18 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
},
ast::PatEnum(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
Some(DefConst(..)) =>
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
ast::PatQPath(..) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
ast::PatStruct(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
Some(DefConst(..)) =>
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
@ -861,7 +865,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
ast::PatIdent(_, _, _) => {
let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
match opt_def {
Some(DefConst(..)) =>
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
@ -876,7 +880,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
ast::PatEnum(_, ref args) => {
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
match def {
DefConst(..) =>
DefConst(..) | DefAssociatedConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
DefVariant(_, id, _) if *constructor != Variant(id) => None,
@ -890,11 +894,16 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
}
}
ast::PatQPath(_, _) => {
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten")
}
ast::PatStruct(_, ref pattern_fields, _) => {
// Is this a struct or an enum variant?
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
let class_id = match def {
DefConst(..) =>
DefConst(..) | DefAssociatedConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {

View file

@ -12,10 +12,11 @@
// recursively.
use session::Session;
use middle::def::{DefStatic, DefConst, DefMap};
use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefMap};
use syntax::ast;
use syntax::{ast_util, ast_map};
use syntax::codemap::Span;
use syntax::visit::Visitor;
use syntax::visit;
@ -26,8 +27,43 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
}
impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> {
fn visit_item(&mut self, i: &ast::Item) {
check_item(self, i);
fn visit_item(&mut self, it: &ast::Item) {
match it.node {
ast::ItemStatic(_, _, ref expr) |
ast::ItemConst(_, ref expr) => {
let mut recursion_visitor =
CheckItemRecursionVisitor::new(self, &it.span);
recursion_visitor.visit_item(it);
visit::walk_expr(self, &*expr)
},
_ => visit::walk_item(self, it)
}
}
fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
match ti.node {
ast::ConstTraitItem(_, ref default) => {
if let Some(ref expr) = *default {
let mut recursion_visitor =
CheckItemRecursionVisitor::new(self, &ti.span);
recursion_visitor.visit_trait_item(ti);
visit::walk_expr(self, &*expr)
}
}
_ => visit::walk_trait_item(self, ti)
}
}
fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
match ii.node {
ast::ConstImplItem(_, ref expr) => {
let mut recursion_visitor =
CheckItemRecursionVisitor::new(self, &ii.span);
recursion_visitor.visit_impl_item(ii);
visit::walk_expr(self, &*expr)
}
_ => visit::walk_impl_item(self, ii)
}
}
}
@ -44,51 +80,48 @@ pub fn check_crate<'ast>(sess: &Session,
sess.abort_if_errors();
}
fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) {
match it.node {
ast::ItemStatic(_, _, ref ex) |
ast::ItemConst(_, ref ex) => {
check_item_recursion(v.sess, v.ast_map, v.def_map, it);
visit::walk_expr(v, &**ex)
},
_ => visit::walk_item(v, it)
}
}
struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
root_it: &'a ast::Item,
root_span: &'a Span,
sess: &'a Session,
ast_map: &'a ast_map::Map<'ast>,
def_map: &'a DefMap,
idstack: Vec<ast::NodeId>
}
// Make sure a const item doesn't recursively refer to itself
// FIXME: Should use the dependency graph when it's available (#1356)
pub fn check_item_recursion<'a>(sess: &'a Session,
ast_map: &'a ast_map::Map,
def_map: &'a DefMap,
it: &'a ast::Item) {
let mut visitor = CheckItemRecursionVisitor {
root_it: it,
sess: sess,
ast_map: ast_map,
def_map: def_map,
idstack: Vec::new()
};
visitor.visit_item(it);
impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
fn new(v: &CheckCrateVisitor<'a, 'ast>, span: &'a Span)
-> CheckItemRecursionVisitor<'a, 'ast> {
CheckItemRecursionVisitor {
root_span: span,
sess: v.sess,
ast_map: v.ast_map,
def_map: v.def_map,
idstack: Vec::new()
}
}
fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
where F: Fn(&mut Self) {
if self.idstack.iter().any(|x| x == &(id)) {
span_err!(self.sess, *self.root_span, E0265, "recursive constant");
return;
}
self.idstack.push(id);
f(self);
self.idstack.pop();
}
}
impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
fn visit_item(&mut self, it: &ast::Item) {
if self.idstack.iter().any(|x| x == &(it.id)) {
span_err!(self.sess, self.root_it.span, E0265, "recursive constant");
return;
}
self.idstack.push(it.id);
visit::walk_item(self, it);
self.idstack.pop();
self.with_item_id_pushed(it.id, |v| visit::walk_item(v, it));
}
fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
self.with_item_id_pushed(ti.id, |v| visit::walk_trait_item(v, ti));
}
fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
self.with_item_id_pushed(ii.id, |v| visit::walk_impl_item(v, ii));
}
fn visit_expr(&mut self, e: &ast::Expr) {
@ -96,11 +129,16 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
ast::ExprPath(..) => {
match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
Some(DefStatic(def_id, _)) |
Some(DefAssociatedConst(def_id, _)) |
Some(DefConst(def_id)) if
ast_util::is_local(def_id) => {
match self.ast_map.get(def_id.node) {
ast_map::NodeItem(item) =>
self.visit_item(item),
ast_map::NodeTraitItem(item) =>
self.visit_trait_item(item),
ast_map::NodeImplItem(item) =>
self.visit_impl_item(item),
ast_map::NodeForeignItem(_) => {},
_ => {
span_err!(self.sess, e.span, E0266,

View file

@ -16,11 +16,12 @@ pub use self::const_val::*;
use self::ErrKind::*;
use metadata::csearch;
use middle::{astencode, def};
use middle::{astencode, def, infer, subst, traits};
use middle::pat_util::def_to_path;
use middle::ty::{self, Ty};
use middle::astconv_util::ast_ty_to_prim_ty;
use util::num::ToPrimitive;
use util::ppaux::Repr;
use syntax::ast::{self, Expr};
use syntax::codemap::Span;
@ -39,8 +40,9 @@ use std::rc::Rc;
fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
match opt_def {
Some(def::DefConst(def_id)) => {
lookup_const_by_id(tcx, def_id)
Some(def::DefConst(def_id)) |
Some(def::DefAssociatedConst(def_id, _)) => {
lookup_const_by_id(tcx, def_id, Some(e.id))
}
Some(def::DefVariant(enum_def, variant_def, _)) => {
lookup_variant_by_id(tcx, enum_def, variant_def)
@ -101,14 +103,46 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt,
}
}
pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
-> Option<&'a Expr> {
pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
def_id: ast::DefId,
maybe_ref_id: Option<ast::NodeId>)
-> Option<&'tcx Expr> {
if ast_util::is_local(def_id) {
match tcx.map.find(def_id.node) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
ast::ItemConst(_, ref const_expr) => {
Some(&**const_expr)
Some(&*const_expr)
}
_ => None
},
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
ast::ConstTraitItem(_, _) => {
match maybe_ref_id {
// If we have a trait item, and we know the expression
// that's the source of the obligation to resolve it,
// `resolve_trait_associated_const` will select an impl
// or the default.
Some(ref_id) => {
let trait_id = ty::trait_of_item(tcx, def_id)
.unwrap();
resolve_trait_associated_const(tcx, ti, trait_id,
ref_id)
}
// Technically, without knowing anything about the
// expression that generates the obligation, we could
// still return the default if there is one. However,
// it's safer to return `None` than to return some value
// that may differ from what you would get from
// correctly selecting an impl.
None => None
}
}
_ => None
},
Some(ast_map::NodeImplItem(ii)) => match ii.node {
ast::ConstImplItem(_, ref expr) => {
Some(&*expr)
}
_ => None
},
@ -122,16 +156,44 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
}
None => {}
}
let mut used_ref_id = false;
let expr_id = match csearch::maybe_get_item_ast(tcx, def_id,
Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) {
csearch::FoundAst::Found(&ast::IIItem(ref item)) => match item.node {
ast::ItemConst(_, ref const_expr) => Some(const_expr.id),
_ => None
},
csearch::FoundAst::Found(&ast::IITraitItem(trait_id, ref ti)) => match ti.node {
ast::ConstTraitItem(_, _) => {
used_ref_id = true;
match maybe_ref_id {
// As mentioned in the comments above for in-crate
// constants, we only try to find the expression for
// a trait-associated const if the caller gives us
// the expression that refers to it.
Some(ref_id) => {
resolve_trait_associated_const(tcx, ti, trait_id,
ref_id).map(|e| e.id)
}
None => None
}
}
_ => None
},
csearch::FoundAst::Found(&ast::IIImplItem(_, ref ii)) => match ii.node {
ast::ConstImplItem(_, ref expr) => Some(expr.id),
_ => None
},
_ => None
};
tcx.extern_const_statics.borrow_mut().insert(def_id,
expr_id.unwrap_or(ast::DUMMY_NODE_ID));
// If we used the reference expression, particularly to choose an impl
// of a trait-associated const, don't cache that, because the next
// lookup with the same def_id may yield a different result.
if !used_ref_id {
tcx.extern_const_statics
.borrow_mut().insert(def_id,
expr_id.unwrap_or(ast::DUMMY_NODE_ID));
}
expr_id.map(|id| tcx.map.expect_expr(id))
}
}
@ -755,7 +817,35 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
_ => (None, None)
}
} else {
(lookup_const_by_id(tcx, def_id), None)
(lookup_const_by_id(tcx, def_id, Some(e.id)), None)
}
}
Some(def::DefAssociatedConst(def_id, provenance)) => {
if ast_util::is_local(def_id) {
match provenance {
def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
ast::ConstTraitItem(ref ty, _) => {
(resolve_trait_associated_const(tcx, ti,
trait_id, e.id),
Some(&**ty))
}
_ => (None, None)
},
_ => (None, None)
},
def::FromImpl(_) => match tcx.map.find(def_id.node) {
Some(ast_map::NodeImplItem(ii)) => match ii.node {
ast::ConstImplItem(ref ty, ref expr) => {
(Some(&**expr), Some(&**ty))
}
_ => (None, None)
},
_ => (None, None)
},
}
} else {
(lookup_const_by_id(tcx, def_id, Some(e.id)), None)
}
}
Some(def::DefVariant(enum_def, variant_def, _)) => {
@ -833,6 +923,71 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
Ok(result)
}
fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
ti: &'tcx ast::TraitItem,
trait_id: ast::DefId,
ref_id: ast::NodeId)
-> Option<&'tcx Expr>
{
let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs;
let subst::SeparateVecsPerParamSpace {
types: rcvr_type,
selfs: rcvr_self,
fns: _,
} = rcvr_substs.types.split();
let trait_substs =
subst::Substs::erased(subst::VecPerParamSpace::new(rcvr_type,
rcvr_self,
Vec::new()));
let trait_substs = tcx.mk_substs(trait_substs);
debug!("resolve_trait_associated_const: trait_substs={}",
trait_substs.repr(tcx));
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
substs: trait_substs }));
ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
let infcx = infer::new_infer_ctxt(tcx);
let param_env = ty::empty_parameter_environment(tcx);
let mut selcx = traits::SelectionContext::new(&infcx, &param_env);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(vtable)) => vtable,
// Still ambiguous, so give up and let the caller decide whether this
// expression is really needed yet. Some associated constant values
// can't be evaluated until monomorphization is done in trans.
Ok(None) => {
return None
}
Err(e) => {
tcx.sess.span_bug(ti.span,
&format!("Encountered error `{}` when trying \
to select an implementation for \
constant trait item reference.",
e.repr(tcx)))
}
};
match selection {
traits::VtableImpl(ref impl_data) => {
match ty::associated_consts(tcx, impl_data.impl_def_id)
.iter().find(|ic| ic.name == ti.ident.name) {
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
None => match ti.node {
ast::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
_ => None,
},
}
}
_ => {
tcx.sess.span_bug(
ti.span,
&format!("resolve_trait_associated_const: unexpected vtable type"))
}
}
}
fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult {
macro_rules! convert_val {
($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {

View file

@ -72,7 +72,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
self.tcx.def_map.borrow().get(id).map(|def| {
match def.full_def() {
def::DefConst(_) => {
def::DefConst(_) | def::DefAssociatedConst(..) => {
self.check_def_id(def.def_id())
}
_ if self.ignore_non_const_paths => (),
@ -114,14 +114,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
let trait_item = ty::trait_item(self.tcx,
trait_ref.def_id,
index);
match trait_item {
ty::MethodTraitItem(method) => {
self.check_def_id(method.def_id);
}
ty::TypeTraitItem(typedef) => {
self.check_def_id(typedef.def_id);
}
}
self.check_def_id(trait_item.def_id());
}
}
}
@ -353,6 +346,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
ast::ItemTrait(_, _, _, ref trait_items) => {
for trait_item in trait_items {
match trait_item.node {
ast::ConstTraitItem(_, Some(_)) |
ast::MethodTraitItem(_, Some(_)) => {
if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
self.worklist.push(trait_item.id);
@ -365,6 +359,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
ast::ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => {
for impl_item in impl_items {
match impl_item.node {
ast::ConstImplItem(..) |
ast::MethodImplItem(..) => {
if opt_trait.is_some() ||
has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
@ -406,7 +401,7 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
None => ()
}
// Seed implemented trait methods
// Seed implemented trait items
let mut life_seeder = LifeSeeder {
worklist: worklist
};
@ -487,7 +482,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
|ctor| self.live_symbols.contains(&ctor)) {
return true;
}
// If it's a type whose methods are live, then it's live, too.
// If it's a type whose items are live, then it's live, too.
// This is done to handle the case where, for example, the static
// method of a private type is used, but the type itself is never
// called directly.
@ -557,21 +552,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
visit::walk_foreign_item(self, fi);
}
fn visit_fn(&mut self, fk: visit::FnKind<'v>,
_: &'v ast::FnDecl, block: &'v ast::Block,
span: codemap::Span, id: ast::NodeId) {
// Have to warn method here because methods are not ast::Item
match fk {
visit::FkMethod(name, _, _) => {
if !self.symbol_is_live(id, None) {
self.warn_dead_code(id, span, name.name, "method");
}
}
_ => ()
}
visit::walk_block(self, block);
}
fn visit_struct_field(&mut self, field: &ast::StructField) {
if self.should_warn_about_field(&field.node) {
self.warn_dead_code(field.node.id, field.span,
@ -581,12 +561,37 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
visit::walk_struct_field(self, field);
}
// Overwrite so that we don't warn the trait method itself.
fn visit_trait_item(&mut self, trait_method: &ast::TraitItem) {
match trait_method.node {
fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
match impl_item.node {
ast::ConstImplItem(_, ref expr) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.ident.name, "associated const");
}
visit::walk_expr(self, expr)
}
ast::MethodImplItem(_, ref body) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.ident.name, "method");
}
visit::walk_block(self, body)
}
ast::TypeImplItem(..) |
ast::MacImplItem(..) => {}
}
}
// Overwrite so that we don't warn the trait item itself.
fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
match trait_item.node {
ast::ConstTraitItem(_, Some(ref expr)) => {
visit::walk_expr(self, expr)
}
ast::MethodTraitItem(_, Some(ref body)) => {
visit::walk_block(self, body)
}
ast::ConstTraitItem(_, None) |
ast::MethodTraitItem(_, None) |
ast::TypeTraitItem(..) => {}
}

View file

@ -28,6 +28,7 @@ pub enum Def {
DefForeignMod(ast::DefId),
DefStatic(ast::DefId, bool /* is_mutbl */),
DefConst(ast::DefId),
DefAssociatedConst(ast::DefId /* const */, MethodProvenance),
DefLocal(ast::NodeId),
DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
DefTy(ast::DefId, bool /* is_enum */),
@ -140,7 +141,8 @@ impl Def {
DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> {
DefMethod(id, _) | DefConst(id) | DefAssociatedConst(id, _) |
DefSelfTy(Some(id), None)=> {
id
}
DefLocal(id) |

View file

@ -234,7 +234,7 @@ impl OverloadedCallType {
ty::MethodTraitItem(ref method_descriptor) => {
(*method_descriptor).clone()
}
ty::TypeTraitItem(_) => {
_ => {
tcx.sess.bug("overloaded call method wasn't in method map")
}
};
@ -1147,7 +1147,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
let tcx = typer.tcx();
match pat.node {
ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
ast::PatEnum(_, _) | ast::PatQPath(..) |
ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
match def_map.get(&pat.id).map(|d| d.full_def()) {
None => {
// no definition found: pat is not a
@ -1183,6 +1184,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
}
Some(def::DefConst(..)) |
Some(def::DefAssociatedConst(..)) |
Some(def::DefLocal(..)) => {
// This is a leaf (i.e. identifier binding
// or constant value to match); thus no

View file

@ -843,8 +843,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
Some(&sig.explicit_self.node),
item.span))
}
ast::TypeImplItem(_) => None,
ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro")
ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro"),
_ => None,
}
},
ast_map::NodeTraitItem(item) => {
@ -1723,8 +1723,8 @@ fn lifetimes_in_scope(tcx: &ty::ctxt,
taken.push_all(&sig.generics.lifetimes);
Some(ii.id)
}
ast::TypeImplItem(_) => None,
ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro")
ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro"),
_ => None,
}
}
_ => None

View file

@ -589,7 +589,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
match def {
def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
def::DefFn(..) | def::DefMethod(..) => {
def::DefAssociatedConst(..) | def::DefFn(..) | def::DefMethod(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
@ -838,20 +838,20 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
expr_ty: Ty<'tcx>)
-> cmt<'tcx> {
let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
.unwrap_or(check_const::NOT_CONST);
.unwrap_or(check_const::ConstQualif::NOT_CONST);
// Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted.
let qualif = match expr_ty.sty {
ty::ty_vec(_, Some(0)) => qualif,
_ => check_const::NOT_CONST
_ => check_const::ConstQualif::NOT_CONST
};
// Compute maximum lifetime of this rvalue. This is 'static if
// we can promote to a constant, otherwise equal to enclosing temp
// lifetime.
let re = match qualif & check_const::NON_STATIC_BORROWS {
check_const::PURE_CONST => ty::ReStatic,
let re = match qualif & check_const::ConstQualif::NON_STATIC_BORROWS {
check_const::ConstQualif::PURE_CONST => ty::ReStatic,
_ => self.temporary_scope(id),
};
let ret = self.cat_rvalue(id, span, re, expr_ty);
@ -1286,7 +1286,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
try!(self.cat_pattern_(cmt_field, &**subpat, op));
}
}
Some(def::DefConst(..)) => {
Some(def::DefConst(..)) | Some(def::DefAssociatedConst(..)) => {
for subpat in subpats {
try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
}
@ -1299,6 +1299,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
}
}
ast::PatQPath(..) => {
// Lone constant: ignore
}
ast::PatIdent(_, _, Some(ref subpat)) => {
try!(self.cat_pattern_(cmt, &**subpat, op));
}

View file

@ -30,7 +30,7 @@ pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap {
pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatLit(_) | ast::PatRange(_, _) => true,
ast::PatLit(_) | ast::PatRange(_, _) | ast::PatQPath(..) => true,
ast::PatEnum(_, _) |
ast::PatIdent(_, _, None) |
ast::PatStruct(..) => {
@ -60,9 +60,25 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool {
pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatIdent(_, _, None) | ast::PatEnum(..) => {
ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
Some(DefConst(..)) => true,
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
_ => false
}
}
_ => false
}
}
// Same as above, except that partially-resolved defs cause `false` to be
// returned instead of a panic.
pub fn pat_is_resolved_const(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
match dm.borrow().get(&pat.id)
.and_then(|d| if d.depth == 0 { Some(d.base_def) }
else { None } ) {
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
_ => false
}
}

View file

@ -113,7 +113,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
// If this path leads to a constant, then we need to
// recurse into the constant to continue finding
// items that are reachable.
def::DefConst(..) => {
def::DefConst(..) | def::DefAssociatedConst(..) => {
self.worklist.push(def_id.node);
}
@ -183,12 +183,14 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
}
Some(ast_map::NodeTraitItem(trait_method)) => {
match trait_method.node {
ast::ConstTraitItem(_, ref default) => default.is_some(),
ast::MethodTraitItem(_, ref body) => body.is_some(),
ast::TypeTraitItem(..) => false,
}
}
Some(ast_map::NodeImplItem(impl_item)) => {
match impl_item.node {
ast::ConstImplItem(..) => true,
ast::MethodImplItem(ref sig, _) => {
if generics_require_inlining(&sig.generics) ||
attr::requests_inline(&impl_item.attrs) {
@ -303,9 +305,13 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
}
ast_map::NodeTraitItem(trait_method) => {
match trait_method.node {
ast::ConstTraitItem(_, None) |
ast::MethodTraitItem(_, None) => {
// Keep going, nothing to get exported
}
ast::ConstTraitItem(_, Some(ref expr)) => {
self.visit_expr(&*expr);
}
ast::MethodTraitItem(_, Some(ref body)) => {
visit::walk_block(self, body);
}
@ -314,6 +320,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
}
ast_map::NodeImplItem(impl_item) => {
match impl_item.node {
ast::ConstImplItem(_, ref expr) => {
self.visit_expr(&*expr);
}
ast::MethodImplItem(ref sig, ref body) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, sig, impl_item, did) {

View file

@ -100,9 +100,7 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
.map(|code| ObjectSafetyViolation::Method(m.clone(), code))
.into_iter()
}
ty::TypeTraitItem(_) => {
None.into_iter()
}
_ => None.into_iter(),
}
})
.collect();

View file

@ -863,7 +863,7 @@ fn confirm_impl_candidate<'cx,'tcx>(
for impl_item in impl_items {
let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
ty::MethodTraitItem(..) => { continue; }
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; }
};
if assoc_type.name != obligation.predicate.item_name {

View file

@ -434,7 +434,7 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
for trait_item in &**trait_items {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
ty::TypeTraitItem(_) => {}
_ => {}
}
}
}
@ -445,14 +445,14 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
for trait_item in trait_items.iter().take(method_offset_in_trait) {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
ty::TypeTraitItem(_) => {}
_ => {}
}
}
// the item at the offset we were given really ought to be a method
assert!(match trait_items[method_offset_in_trait] {
ty::MethodTraitItem(_) => true,
ty::TypeTraitItem(_) => false
_ => false
});
method_count

View file

@ -80,7 +80,7 @@ use std::vec::IntoIter;
use collections::enum_set::{EnumSet, CLike};
use std::collections::{HashMap, HashSet};
use syntax::abi;
use syntax::ast::{CrateNum, DefId, ItemTrait, LOCAL_CRATE};
use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE};
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
use syntax::ast_util::{self, is_local, lit_is_str, local_def};
@ -133,6 +133,7 @@ impl ImplOrTraitItemContainer {
#[derive(Clone, Debug)]
pub enum ImplOrTraitItem<'tcx> {
ConstTraitItem(Rc<AssociatedConst<'tcx>>),
MethodTraitItem(Rc<Method<'tcx>>),
TypeTraitItem(Rc<AssociatedType>),
}
@ -140,6 +141,9 @@ pub enum ImplOrTraitItem<'tcx> {
impl<'tcx> ImplOrTraitItem<'tcx> {
fn id(&self) -> ImplOrTraitItemId {
match *self {
ConstTraitItem(ref associated_const) => {
ConstTraitItemId(associated_const.def_id)
}
MethodTraitItem(ref method) => MethodTraitItemId(method.def_id),
TypeTraitItem(ref associated_type) => {
TypeTraitItemId(associated_type.def_id)
@ -149,6 +153,7 @@ impl<'tcx> ImplOrTraitItem<'tcx> {
pub fn def_id(&self) -> ast::DefId {
match *self {
ConstTraitItem(ref associated_const) => associated_const.def_id,
MethodTraitItem(ref method) => method.def_id,
TypeTraitItem(ref associated_type) => associated_type.def_id,
}
@ -156,13 +161,23 @@ impl<'tcx> ImplOrTraitItem<'tcx> {
pub fn name(&self) -> ast::Name {
match *self {
ConstTraitItem(ref associated_const) => associated_const.name,
MethodTraitItem(ref method) => method.name,
TypeTraitItem(ref associated_type) => associated_type.name,
}
}
pub fn vis(&self) -> ast::Visibility {
match *self {
ConstTraitItem(ref associated_const) => associated_const.vis,
MethodTraitItem(ref method) => method.vis,
TypeTraitItem(ref associated_type) => associated_type.vis,
}
}
pub fn container(&self) -> ImplOrTraitItemContainer {
match *self {
ConstTraitItem(ref associated_const) => associated_const.container,
MethodTraitItem(ref method) => method.container,
TypeTraitItem(ref associated_type) => associated_type.container,
}
@ -171,13 +186,14 @@ impl<'tcx> ImplOrTraitItem<'tcx> {
pub fn as_opt_method(&self) -> Option<Rc<Method<'tcx>>> {
match *self {
MethodTraitItem(ref m) => Some((*m).clone()),
TypeTraitItem(_) => None
_ => None,
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum ImplOrTraitItemId {
ConstTraitItemId(ast::DefId),
MethodTraitItemId(ast::DefId),
TypeTraitItemId(ast::DefId),
}
@ -185,6 +201,7 @@ pub enum ImplOrTraitItemId {
impl ImplOrTraitItemId {
pub fn def_id(&self) -> ast::DefId {
match *self {
ConstTraitItemId(def_id) => def_id,
MethodTraitItemId(def_id) => def_id,
TypeTraitItemId(def_id) => def_id,
}
@ -238,6 +255,16 @@ impl<'tcx> Method<'tcx> {
}
}
#[derive(Clone, Copy, Debug)]
pub struct AssociatedConst<'tcx> {
pub name: ast::Name,
pub ty: Ty<'tcx>,
pub vis: ast::Visibility,
pub def_id: ast::DefId,
pub container: ImplOrTraitItemContainer,
pub default: Option<ast::DefId>,
}
#[derive(Clone, Copy, Debug)]
pub struct AssociatedType {
pub name: ast::Name,
@ -821,16 +848,18 @@ impl<'tcx> ctxt<'tcx> {
// recursing over the type itself.
bitflags! {
flags TypeFlags: u32 {
const NO_TYPE_FLAGS = 0b0,
const HAS_PARAMS = 0b1,
const HAS_SELF = 0b10,
const HAS_TY_INFER = 0b100,
const HAS_RE_INFER = 0b1000,
const HAS_RE_LATE_BOUND = 0b10000,
const HAS_REGIONS = 0b100000,
const HAS_TY_ERR = 0b1000000,
const HAS_PROJECTION = 0b10000000,
const NEEDS_SUBST = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits,
const NO_TYPE_FLAGS = 0,
const HAS_PARAMS = 1 << 0,
const HAS_SELF = 1 << 1,
const HAS_TY_INFER = 1 << 2,
const HAS_RE_INFER = 1 << 3,
const HAS_RE_LATE_BOUND = 1 << 4,
const HAS_REGIONS = 1 << 5,
const HAS_TY_ERR = 1 << 6,
const HAS_PROJECTION = 1 << 7,
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_REGIONS.bits,
}
}
@ -863,8 +892,8 @@ macro_rules! sty_debug_print {
ty::ty_err => /* unimportant */ continue,
$(ty::$variant(..) => &mut $variant,)*
};
let region = t.flags.intersects(ty::HAS_RE_INFER);
let ty = t.flags.intersects(ty::HAS_TY_INFER);
let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
variant.total += 1;
total.total += 1;
@ -966,23 +995,23 @@ impl<'tcx> Borrow<sty<'tcx>> for InternedTy<'tcx> {
}
pub fn type_has_params(ty: Ty) -> bool {
ty.flags.intersects(HAS_PARAMS)
ty.flags.intersects(TypeFlags::HAS_PARAMS)
}
pub fn type_has_self(ty: Ty) -> bool {
ty.flags.intersects(HAS_SELF)
ty.flags.intersects(TypeFlags::HAS_SELF)
}
pub fn type_has_ty_infer(ty: Ty) -> bool {
ty.flags.intersects(HAS_TY_INFER)
ty.flags.intersects(TypeFlags::HAS_TY_INFER)
}
pub fn type_needs_infer(ty: Ty) -> bool {
ty.flags.intersects(HAS_TY_INFER | HAS_RE_INFER)
ty.flags.intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
}
pub fn type_has_projection(ty: Ty) -> bool {
ty.flags.intersects(HAS_PROJECTION)
ty.flags.intersects(TypeFlags::HAS_PROJECTION)
}
pub fn type_has_late_bound_regions(ty: Ty) -> bool {
ty.flags.intersects(HAS_RE_LATE_BOUND)
ty.flags.intersects(TypeFlags::HAS_RE_LATE_BOUND)
}
/// An "escaping region" is a bound region whose binder is not part of `t`.
@ -2291,6 +2320,16 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
match cx.map.find(id) {
Some(ast_map::NodeImplItem(ref impl_item)) => {
match impl_item.node {
ast::ConstImplItem(_, _) => {
let def_id = ast_util::local_def(id);
let scheme = lookup_item_type(cx, def_id);
let predicates = lookup_predicates(cx, def_id);
construct_parameter_environment(cx,
impl_item.span,
&scheme.generics,
&predicates,
id)
}
ast::MethodImplItem(_, ref body) => {
let method_def_id = ast_util::local_def(id);
match ty::impl_or_trait_item(cx, method_def_id) {
@ -2304,11 +2343,10 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
method_bounds,
body.id)
}
TypeTraitItem(_) => {
_ => {
cx.sess
.bug("ParameterEnvironment::for_item(): \
can't create a parameter environment \
for type trait items")
got non-method item from impl method?!")
}
}
}
@ -2322,6 +2360,25 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
}
Some(ast_map::NodeTraitItem(trait_item)) => {
match trait_item.node {
ast::ConstTraitItem(_, ref default) => {
match *default {
Some(_) => {
let def_id = ast_util::local_def(id);
let scheme = lookup_item_type(cx, def_id);
let predicates = lookup_predicates(cx, def_id);
construct_parameter_environment(cx,
trait_item.span,
&scheme.generics,
&predicates,
id)
}
None => {
cx.sess.bug("ParameterEnvironment::from_item(): \
can't create a parameter environment \
for const trait items without defaults")
}
}
}
ast::MethodTraitItem(_, None) => {
cx.sess.span_bug(trait_item.span,
"ParameterEnvironment::for_item():
@ -2342,11 +2399,11 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
method_bounds,
body.id)
}
TypeTraitItem(_) => {
_ => {
cx.sess
.bug("ParameterEnvironment::for_item(): \
can't create a parameter environment \
for type trait items")
got non-method item from provided \
method?!")
}
}
}
@ -2755,7 +2812,7 @@ struct FlagComputation {
impl FlagComputation {
fn new() -> FlagComputation {
FlagComputation { flags: NO_TYPE_FLAGS, depth: 0 }
FlagComputation { flags: TypeFlags::NO_TYPE_FLAGS, depth: 0 }
}
fn for_sty(st: &sty) -> FlagComputation {
@ -2800,20 +2857,20 @@ impl FlagComputation {
// You might think that we could just return ty_err for
// any type containing ty_err as a component, and get
// rid of the HAS_TY_ERR flag -- likewise for ty_bot (with
// rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
// the exception of function types that return bot).
// But doing so caused sporadic memory corruption, and
// neither I (tjc) nor nmatsakis could figure out why,
// so we're doing it this way.
&ty_err => {
self.add_flags(HAS_TY_ERR)
self.add_flags(TypeFlags::HAS_TY_ERR)
}
&ty_param(ref p) => {
if p.space == subst::SelfSpace {
self.add_flags(HAS_SELF);
self.add_flags(TypeFlags::HAS_SELF);
} else {
self.add_flags(HAS_PARAMS);
self.add_flags(TypeFlags::HAS_PARAMS);
}
}
@ -2822,7 +2879,7 @@ impl FlagComputation {
}
&ty_infer(_) => {
self.add_flags(HAS_TY_INFER)
self.add_flags(TypeFlags::HAS_TY_INFER)
}
&ty_enum(_, substs) | &ty_struct(_, substs) => {
@ -2830,7 +2887,7 @@ impl FlagComputation {
}
&ty_projection(ref data) => {
self.add_flags(HAS_PROJECTION);
self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_projection_ty(data);
}
@ -2894,11 +2951,11 @@ impl FlagComputation {
}
fn add_region(&mut self, r: Region) {
self.add_flags(HAS_REGIONS);
self.add_flags(TypeFlags::HAS_REGIONS);
match r {
ty::ReInfer(_) => { self.add_flags(HAS_RE_INFER); }
ty::ReInfer(_) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
ty::ReLateBound(debruijn, _) => {
self.add_flags(HAS_RE_LATE_BOUND);
self.add_flags(TypeFlags::HAS_RE_LATE_BOUND);
self.add_depth(debruijn.depth);
}
_ => { }
@ -3252,11 +3309,11 @@ pub fn type_is_nil(ty: Ty) -> bool {
}
pub fn type_is_error(ty: Ty) -> bool {
ty.flags.intersects(HAS_TY_ERR)
ty.flags.intersects(TypeFlags::HAS_TY_ERR)
}
pub fn type_needs_subst(ty: Ty) -> bool {
ty.flags.intersects(NEEDS_SUBST)
ty.flags.intersects(TypeFlags::NEEDS_SUBST)
}
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
@ -4719,7 +4776,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
def::DefUpvar(..) |
def::DefLocal(..) => LvalueExpr,
def::DefConst(..) => RvalueDatumExpr,
def::DefConst(..) |
def::DefAssociatedConst(..) => RvalueDatumExpr,
def => {
tcx.sess.span_bug(
@ -5070,10 +5128,10 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
if let ast::MethodTraitItem(_, Some(_)) = ti.node {
match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
MethodTraitItem(m) => Some(m),
TypeTraitItem(_) => {
_ => {
cx.sess.bug("provided_trait_methods(): \
associated type found from \
looking up ProvidedMethod?!")
non-method item found from \
looking up provided method?!")
}
}
} else {
@ -5088,6 +5146,52 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
}
}
pub fn associated_consts<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
-> Vec<Rc<AssociatedConst<'tcx>>> {
if is_local(id) {
match cx.map.expect_item(id.node).node {
ItemTrait(_, _, _, ref tis) => {
tis.iter().filter_map(|ti| {
if let ast::ConstTraitItem(_, _) = ti.node {
match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
ConstTraitItem(ac) => Some(ac),
_ => {
cx.sess.bug("associated_consts(): \
non-const item found from \
looking up a constant?!")
}
}
} else {
None
}
}).collect()
}
ItemImpl(_, _, _, _, _, ref iis) => {
iis.iter().filter_map(|ii| {
if let ast::ConstImplItem(_, _) = ii.node {
match impl_or_trait_item(cx, ast_util::local_def(ii.id)) {
ConstTraitItem(ac) => Some(ac),
_ => {
cx.sess.bug("associated_consts(): \
non-const item found from \
looking up a constant?!")
}
}
} else {
None
}
}).collect()
}
_ => {
cx.sess.bug(&format!("associated_consts: `{:?}` is not a trait \
or impl", id))
}
}
} else {
csearch::get_associated_consts(cx, id)
}
}
/// Helper for looking things up in the various maps that are populated during
/// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc). All of
/// these share the pattern that if the id is local, it should have been loaded
@ -5174,7 +5278,7 @@ pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool {
Some(ref item) => {
match **item {
TypeTraitItem(_) => true,
MethodTraitItem(_) => false,
_ => false,
}
}
None => false,
@ -6188,7 +6292,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
.insert(method_def_id, source);
}
}
TypeTraitItem(_) => {}
_ => {}
}
}
@ -6240,7 +6344,7 @@ pub fn populate_implementations_for_trait_if_necessary(
.insert(method_def_id, source);
}
}
TypeTraitItem(_) => {}
_ => {}
}
}

View file

@ -621,6 +621,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
let arch = &sess.target.target.arch;
let wordsz = &sess.target.target.target_pointer_width;
let os = &sess.target.target.target_os;
let env = &sess.target.target.target_env;
let fam = match sess.target.target.options.is_like_windows {
true => InternedString::new("windows"),
@ -634,8 +635,8 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
mk(InternedString::new("target_family"), fam),
mk(InternedString::new("target_arch"), intern(arch)),
mk(InternedString::new("target_endian"), intern(end)),
mk(InternedString::new("target_pointer_width"),
intern(wordsz))
mk(InternedString::new("target_pointer_width"), intern(wordsz)),
mk(InternedString::new("target_env"), intern(env)),
];
if sess.opts.debug_assertions {
ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
@ -754,11 +755,14 @@ mod opt {
pub fn multi(a: S, b: S, c: S, d: S) -> R { stable(getopts::optmulti(a, b, c, d)) }
pub fn flag(a: S, b: S, c: S) -> R { stable(getopts::optflag(a, b, c)) }
pub fn flagopt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optflagopt(a, b, c, d)) }
pub fn flagmulti(a: S, b: S, c: S) -> R { stable(getopts::optflagmulti(a, b, c)) }
pub fn opt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optopt(a, b, c, d)) }
pub fn multi_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optmulti(a, b, c, d)) }
pub fn flag_u(a: S, b: S, c: S) -> R { unstable(getopts::optflag(a, b, c)) }
pub fn flagopt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optflagopt(a, b, c, d)) }
pub fn flagmulti_u(a: S, b: S, c: S) -> R { unstable(getopts::optflagmulti(a, b, c)) }
}
/// Returns the "short" subset of the rustc command line options,
@ -785,8 +789,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
opt::multi("", "print", "Comma separated list of compiler information to \
print on stdout",
"[crate-name|file-names|sysroot]"),
opt::flag("g", "", "Equivalent to -C debuginfo=2"),
opt::flag("O", "", "Equivalent to -C opt-level=2"),
opt::flagmulti("g", "", "Equivalent to -C debuginfo=2"),
opt::flagmulti("O", "", "Equivalent to -C opt-level=2"),
opt::opt("o", "", "Write output to <filename>", "FILENAME"),
opt::opt("", "out-dir", "Write output to compiler-chosen filename \
in <dir>", "DIR"),
@ -1111,7 +1115,7 @@ impl fmt::Display for CrateType {
}
#[cfg(test)]
mod test {
mod tests {
use session::config::{build_configuration, optgroups, build_session_options};
use session::build_session;

View file

@ -57,6 +57,8 @@ pub struct Session {
pub crate_metadata: RefCell<Vec<String>>,
pub features: RefCell<feature_gate::Features>,
pub delayed_span_bug: RefCell<Option<(codemap::Span, String)>>,
/// The maximum recursion limit for potentially infinitely recursive
/// operations such as auto-dereference and monomorphization.
pub recursion_limit: Cell<usize>,
@ -114,7 +116,15 @@ impl Session {
self.diagnostic().handler().has_errors()
}
pub fn abort_if_errors(&self) {
self.diagnostic().handler().abort_if_errors()
self.diagnostic().handler().abort_if_errors();
let delayed_bug = self.delayed_span_bug.borrow();
match *delayed_bug {
Some((span, ref errmsg)) => {
self.diagnostic().span_bug(span, errmsg);
},
_ => {}
}
}
pub fn span_warn(&self, sp: Span, msg: &str) {
if self.can_print_warnings {
@ -171,6 +181,11 @@ impl Session {
None => self.bug(msg),
}
}
/// Delay a span_bug() call until abort_if_errors()
pub fn delay_span_bug(&self, sp: Span, msg: &str) {
let mut delayed = self.delayed_span_bug.borrow_mut();
*delayed = Some((sp, msg.to_string()));
}
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
self.diagnostic().span_bug(sp, msg)
}
@ -402,6 +417,7 @@ pub fn build_session_(sopts: config::Options,
plugin_llvm_passes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
crate_metadata: RefCell::new(Vec::new()),
delayed_span_bug: RefCell::new(None),
features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
can_print_warnings: can_print_warnings

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