Merge branch 'master' into mulit-decor
This commit is contained in:
commit
b2ddd937b2
488 changed files with 12552 additions and 7327 deletions
|
|
@ -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) &&
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub fn add_two(a: i32) -> i32 {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use test::Bencher;
|
||||
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ is `Fn(i32) -> i32`.
|
|||
|
||||
There’s one other key point here: because we’re bounding a generic with a
|
||||
trait, this will get monomorphized, and therefore, we’ll be doing static
|
||||
dispatch into the closure. That’s pretty neat. In many langauges, closures are
|
||||
dispatch into the closure. That’s 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
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ unsafe {
|
|||
}
|
||||
```
|
||||
|
||||
[unsafe]: unsafe.html
|
||||
|
||||
Furthermore, any type stored in a `static` must be `Sync`.
|
||||
|
||||
# Initializing
|
||||
|
|
|
|||
|
|
@ -1,3 +1,119 @@
|
|||
% `Deref` coercions
|
||||
|
||||
Coming soon!
|
||||
The standard library provides a special trait, [`Deref`][deref]. It’s 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, there’s a language
|
||||
feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a
|
||||
type `U`, and it implements `Deref<Target=T>`, values of `&U` will
|
||||
automatically coerce to a `&T`. Here’s 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.
|
||||
|
||||
That’s 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 we’ve done is wrap our `String` in an `Rc<T>`. But we can now pass the
|
||||
`Rc<String>` around anywhere we’d have a `String`. The signature of `foo`
|
||||
didn’t 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` isn’t a reference, and `foo` takes `&self`, this works.
|
||||
That’s 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 it’s inserting `*`s, that uses `Deref`.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
% Getting Started
|
||||
|
||||
This first section of the book will get you going with Rust and its tooling.
|
||||
First, we’ll install Rust. Then: the classic ‘Hello World’ program. Finally,
|
||||
First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally,
|
||||
we’ll talk about Cargo, Rust’s build system and package manager.
|
||||
|
|
|
|||
|
|
@ -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’, or‘AST’. This tree is a representation of the
|
||||
structure of your program. For example, `2 + 3` can be turned into a tree:
|
||||
|
||||
```text
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -765,7 +765,7 @@ as `unimplemented!` until you’re ready to write them.
|
|||
# Procedural macros
|
||||
|
||||
If Rust’s macro system can’t do what you need, you may want to write a
|
||||
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
||||
[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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
Here’s 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 we’re 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. Here’s a
|
||||
pattern that’s 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
|
||||
|
||||
Let’s 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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
you’re allowed to change what the binding points to. So in the above example,
|
||||
it’s 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, you’ll 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 can’t
|
||||
bind `y` to something else (`y = &mut z`), but you can mutate the thing that’s
|
||||
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 it’s referencing can be
|
||||
changed.
|
||||
|
||||
It’s 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 doesn’t mean that
|
||||
it’s 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
|
||||
we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take
|
||||
`&mut 5` or anything. So what gives?
|
||||
|
||||
To this, we have to go back to the core of Rust’s 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, that’s 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. It’s 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 what’s inside of it with the
|
||||
`borrow_mut()` method. Isn’t 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
|
||||
Rust’s borrowing rules at runtime, and `panic!`s if they’re violated. This
|
||||
allows us to get around another aspect of Rust’s mutability rules. Let’s 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 }`. We’ve successfully updated `y`.
|
||||
|
|
|
|||
|
|
@ -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, there’s 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 we’ve 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. Let’s 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
|
||||
|
||||
There’s 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;
|
||||
```
|
||||
|
|
|
|||
|
|
@ -62,14 +62,14 @@ let y = 1.0; // y has type f64
|
|||
Here’s 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 @@ Let’s go over them by category:
|
|||
Integer types come in two varieties: signed and unsigned. To understand the
|
||||
difference, let’s 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
|
||||
‘two’s compliment representation’. An unsigned four bit number, since it does
|
||||
“two’s 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ won’t have its methods:
|
|||
```rust,ignore
|
||||
let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
|
||||
let result = f.write("whatever".as_bytes());
|
||||
# result.unwrap(); // ignore the erorr
|
||||
# result.unwrap(); // ignore the error
|
||||
```
|
||||
|
||||
Here’s the error:
|
||||
|
|
@ -203,7 +203,7 @@ use std::io::Write;
|
|||
|
||||
let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t 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.
|
||||
|
|
|
|||
|
|
@ -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. There’s an expanded form of this that’s needed in some
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>`.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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>`.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
45
src/libcollections/range.rs
Normal file
45
src/libcollections/range.rs
Normal 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) }
|
||||
}
|
||||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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))]
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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 .. { }
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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`,
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#![feature(box_syntax)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unsafe_destructor)]
|
||||
#![feature(core)]
|
||||
#![feature(test)]
|
||||
#![feature(rand)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ impl Rand for ChaChaRng {
|
|||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use std::prelude::v1::*;
|
||||
|
||||
use core::iter::order;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ impl IndependentSample<f64> for Exp {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use std::prelude::v1::*;
|
||||
|
||||
use distributions::{Sample, IndependentSample};
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ impl IndependentSample<f64> for StudentT {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use std::prelude::v1::*;
|
||||
|
||||
use distributions::{Sample, IndependentSample};
|
||||
|
|
|
|||
|
|
@ -510,7 +510,7 @@ impl Rand for Isaac64Rng {
|
|||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use std::prelude::v1::*;
|
||||
|
||||
use core::iter::order;
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ impl Default for ReseedWithDefault {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use std::prelude::v1::*;
|
||||
|
||||
use core::iter::{order, repeat};
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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(_) => {
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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, ¶m_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) => {
|
||||
|
|
|
|||
|
|
@ -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(..) => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue