Auto merge of #24724 - alexcrichton:symlink-stable, r=aturon
These functions were intended to be introduced as `#[stable]` as a stable API
was deprecated in favor of them, but they just erroneously forgot the stability
attributes.
diff --git a/mk/tests.mk b/mk/tests.mk
index 0de622f..5d10095 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -753,13 +753,6 @@
PRETTY_DEPS_pretty-rfail = $(RFAIL_TESTS)
PRETTY_DEPS_pretty-bench = $(BENCH_TESTS)
PRETTY_DEPS_pretty-pretty = $(PRETTY_TESTS)
-# The stage- and host-specific dependencies are for e.g. macro_crate_test which pulls in
-# external crates.
-PRETTY_DEPS$(1)_H_$(3)_pretty-rpass =
-PRETTY_DEPS$(1)_H_$(3)_pretty-rpass-full = $$(HLIB$(1)_H_$(3))/stamp.syntax $$(HLIB$(1)_H_$(3))/stamp.rustc
-PRETTY_DEPS$(1)_H_$(3)_pretty-rfail =
-PRETTY_DEPS$(1)_H_$(3)_pretty-bench =
-PRETTY_DEPS$(1)_H_$(3)_pretty-pretty =
PRETTY_DIRNAME_pretty-rpass = run-pass
PRETTY_DIRNAME_pretty-rpass-valgrind = run-pass-valgrind
PRETTY_DIRNAME_pretty-rpass-full = run-pass-fulldeps
@@ -767,6 +760,15 @@
PRETTY_DIRNAME_pretty-bench = bench
PRETTY_DIRNAME_pretty-pretty = pretty
+define DEF_PRETTY_FULLDEPS
+PRETTY_DEPS$(1)_T_$(2)_H_$(3)_pretty-rpass-full = $$(CSREQ$(1)_T_$(3)_H_$(3))
+endef
+
+$(foreach host,$(CFG_HOST), \
+ $(foreach target,$(CFG_TARGET), \
+ $(foreach stage,$(STAGES), \
+ $(eval $(call DEF_PRETTY_FULLDEPS,$(stage),$(target),$(host))))))
+
define DEF_RUN_PRETTY_TEST
PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4) := \
@@ -780,7 +782,7 @@
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
$$(PRETTY_DEPS_$(4)) \
- $$(PRETTY_DEPS$(1)_H_$(3)_$(4))
+ $$(PRETTY_DEPS$(1)_T_$(2)_H_$(3)_$(4))
@$$(call E, run pretty-rpass [$(2)]: $$<)
$$(Q)touch [email protected]_time
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index 91550ae..3d4aeba 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -1465,7 +1465,7 @@
fn aux_output_dir_name(config: &Config, testfile: &Path) -> PathBuf {
let f = output_base_name(config, testfile);
let mut fname = f.file_name().unwrap().to_os_string();
- fname.push("libaux");
+ fname.push(&format!(".{}.libaux", config.mode));
f.with_file_name(&fname)
}
diff --git a/src/doc/grammar.md b/src/doc/grammar.md
index 3d9a5ba..542815e 100644
--- a/src/doc/grammar.md
+++ b/src/doc/grammar.md
@@ -152,19 +152,19 @@
<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 +524,15 @@
idx_expr : expr '[' expr ']' ;
```
+### Range expressions
+
+```antlr
+range_expr : expr ".." expr |
+ expr ".." |
+ ".." expr |
+ ".." ;
+```
+
### Unary operator expressions
**FIXME:** grammar?
@@ -610,7 +619,7 @@
### While loops
```antlr
-while_expr : "while" no_struct_literal_expr '{' block '}' ;
+while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
```
### Infinite loops
@@ -634,7 +643,7 @@
### 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
diff --git a/src/doc/reference.md b/src/doc/reference.md
index d918a32..059da89 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -29,46 +29,11 @@
# Notation
-Rust's grammar is defined over Unicode codepoints, 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 codepoint `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 codepoints outside the ASCII
+A few productions in Rust's grammar permit Unicode code points outside the ASCII
range. We define these productions in terms of character properties specified
-in the Unicode standard, rather than in terms of ASCII-range codepoints. The
+in the Unicode standard, rather than in terms of ASCII-range code points. The
section [Special Unicode Productions](#special-unicode-productions) lists these
productions.
@@ -91,10 +56,10 @@
## Input format
-Rust input is interpreted as a sequence of Unicode codepoints encoded in UTF-8.
+Rust input is interpreted as a sequence of Unicode code points encoded in UTF-8.
Most Rust grammar rules are defined in terms of printable ASCII-range
-codepoints, but a small number are defined in terms of Unicode properties or
-explicit codepoint lists. [^inputformat]
+code points, but a small number are defined in terms of Unicode properties or
+explicit code point lists. [^inputformat]
[^inputformat]: Substitute definitions for the special Unicode productions are
provided to the grammar verifier, restricted to ASCII range, when verifying the
@@ -132,13 +97,6 @@
## 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.
@@ -147,21 +105,18 @@
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, ie `/// Foo` turns into `#[doc="/// Foo"]`).
+characters themselves, i.e. `/// Foo` turns into `#[doc="/// Foo"]`).
-`//!` comments apply to the parent of the comment, rather than the item that
-follows. `//!` comments are usually used to display information on the crate
-index page.
+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.
Non-doc comments are interpreted as a form of whitespace.
## Whitespace
-```{.ebnf .gram}
-whitespace_char : '\x20' | '\x09' | '\x0a' | '\x0d' ;
-whitespace : [ whitespace_char | comment ] + ;
-```
-
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'`).
@@ -174,40 +129,11 @@
## 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 |
-| pub | pure | ref | return | sizeof |
-| static | self | struct | super | true |
-| trait | 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
@@ -215,11 +141,6 @@
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
@@ -268,36 +189,10 @@
##### Suffixes
| Integer | Floating-point |
|---------|----------------|
-| `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `is` (`isize`), `us` (`usize`) | `f32`, `f64` |
+| `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `isize`, `usize` | `f32`, `f64` |
#### 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
@@ -330,14 +225,14 @@
literals. An escape starts with a `U+005C` (`\`) and continues with one of the
following forms:
-* An _8-bit codepoint escape_ escape starts with `U+0078` (`x`) and is
- followed by exactly two _hex digits_. It denotes the Unicode codepoint
+* An _8-bit code point escape_ starts with `U+0078` (`x`) and is
+ followed by exactly two _hex digits_. It denotes the Unicode code point
equal to the provided hex value.
-* A _24-bit codepoint escape_ starts with `U+0075` (`u`) and is followed
+* A _24-bit code point escape_ starts with `U+0075` (`u`) and is followed
by up to six _hex digits_ surrounded by braces `U+007B` (`{`) and `U+007D`
- (`}`). It denotes the Unicode codepoint equal to the provided hex value.
+ (`}`). It denotes the Unicode code point equal to the provided hex value.
* A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072`
- (`r`), or `U+0074` (`t`), denoting the unicode values `U+000A` (LF),
+ (`r`), or `U+0074` (`t`), denoting the Unicode values `U+000A` (LF),
`U+000D` (CR) or `U+0009` (HT) respectively.
* The _backslash escape_ is the character `U+005C` (`\`) which must be
escaped in order to denote *itself*.
@@ -346,11 +241,10 @@
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
@@ -372,19 +266,6 @@
#### 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`
@@ -400,14 +281,14 @@
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
literals. An escape starts with a `U+005C` (`\`) and continues with one of the
following forms:
-* An _byte escape_ escape starts with `U+0078` (`x`) and is
+* A _byte escape_ escape starts with `U+0078` (`x`) and is
followed by exactly two _hex digits_. It denotes the byte
equal to the provided hex value.
* A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072`
@@ -421,11 +302,10 @@
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
@@ -447,19 +327,6 @@
#### 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.
@@ -537,12 +404,6 @@
### 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
@@ -552,16 +413,6 @@
## 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
@@ -657,19 +508,6 @@
## 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].
@@ -697,9 +535,9 @@
only the name of a matched nonterminal comes after the dollar sign.
In both the matcher and transcriber, the Kleene star-like operator indicates
-repetition. The Kleene star operator consists of `$` and parens, optionally
+repetition. The Kleene star operator consists of `$` and parentheses, optionally
followed by a separator token, followed by `*` or `+`. `*` means zero or more
-repetitions, `+` means at least one repetition. The parens are not matched or
+repetitions, `+` means at least one repetition. The parentheses are not matched or
transcribed. On the matcher side, a name is bound to _all_ of the names it
matches, in a structure that mimics the structure of the repetition encountered
on a successful match. The job of the transcriber is to sort that structure
@@ -735,15 +573,26 @@
# Crates and source files
-Rust is a *compiled* language. Its semantics obey a *phase distinction* between
-compile-time and run-time. Those semantic rules that have a *static
+Although Rust, like any other language, can be implemented by an interpreter as
+well as a compiler, the only existing implementation is a compiler —
+from now on referred to as *the* Rust compiler — and the language has
+always been designed to be compiled. For these reasons, this section assumes a
+compiler.
+
+Rust's semantics obey a *phase distinction* between compile-time and
+run-time.[^phase-distinction] Those semantic rules that have a *static
interpretation* govern the success or failure of compilation. Those semantics
that have a *dynamic interpretation* govern the behavior of the program at
run-time.
+[^phase-distinction]: This distinction would also exist in an interpreter.
+ Static checks like syntactic analysis, type checking, and lints should
+ happen before the program is executed regardless of when it is executed.
+
The compilation model centers on artifacts called _crates_. Each compilation
processes a single crate in source form, and if successful, produces a single
-crate in binary form: either an executable or a library.[^cratesourcefile]
+crate in binary form: either an executable or some sort of
+library.[^cratesourcefile]
[^cratesourcefile]: A crate is somewhat analogous to an *assembly* in the
ECMA-335 CLI model, a *library* in the SML/NJ Compilation Manager, a *unit*
@@ -764,21 +613,25 @@
A Rust source file describes a module, the name and location of which —
in the module tree of the current crate — are defined from outside the
source file: either by an explicit `mod_item` in a referencing source file, or
-by the name of the crate itself.
+by the name of the crate itself. Every source file is a module, but not every
+module needs its own source file: [module definitions](#modules) can be nested
+within one file.
Each source file contains a sequence of zero or more `item` definitions, and
-may optionally begin with any number of `attributes` that apply to the
-containing module. Attributes on the anonymous crate module define important
-metadata that influences the behavior of the compiler.
+may optionally begin with any number of [attributes](#Items and attributes)
+that apply to the containing module, most of which influence the behavior of
+the compiler. The anonymous crate module can have additional attributes that
+apply to the crate as a whole.
```no_run
-// Crate name
+// Specify the crate name.
#![crate_name = "projx"]
-// Specify the output type
+// Specify the type of output artifact.
#![crate_type = "lib"]
-// Turn on a warning
+// Turn on a warning.
+// This can be done in any module, not just the anonymous crate module.
#![warn(non_camel_case_types)]
```
@@ -793,12 +646,6 @@
## 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)
@@ -845,11 +692,6 @@
### 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
@@ -910,11 +752,6 @@
##### 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`.
@@ -940,17 +777,6 @@
##### 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
@@ -1099,40 +925,31 @@
angle-bracket-enclosed, comma-separated list following the function name.
```{.ignore}
-fn iter<T>(seq: &[T], f: |T|) {
- for elt in seq.iter() { f(elt); }
+fn iter<T, F>(seq: &[T], f: F) where T: Copy, F: Fn(T) {
+ for elt in seq { f(*elt); }
}
-fn map<T, U>(seq: &[T], f: |T| -> U) -> Vec<U> {
+fn map<T, U, F>(seq: &[T], f: F) -> Vec<U> where T: Copy, U: Copy, F: Fn(T) -> U {
let mut acc = vec![];
- for elt in seq.iter() { acc.push(f(elt)); }
+ for elt in seq { acc.push(f(*elt)); }
acc
}
```
Inside the function signature and body, the name of the type parameter can be
-used as a type name.
+used as a type name. [Trait](#traits) bounds can be specified for type parameters
+to allow methods with that trait to be called on values of that type. This is
+specified using the `where` syntax, as in the above example.
When a generic function is referenced, its type is instantiated based on the
context of the reference. For example, calling the `iter` function defined
above on `[1, 2]` will instantiate type parameter `T` with `i32`, and require
-the closure parameter to have type `fn(i32)`.
+the closure parameter to have type `Fn(i32)`.
The type parameters can also be explicitly supplied in a trailing
[path](#paths) component after the function name. This might be necessary if
there is not sufficient context to determine the type parameters. For example,
`mem::size_of::<u32>() == 4`.
-Since a parameter type is opaque to the generic function, the set of operations
-that can be performed on it is limited. Values of parameter type can only be
-moved, not copied.
-
-```
-fn id<T>(x: T) -> T { x }
-```
-
-Similarly, [trait](#traits) bounds can be specified for type parameters to
-allow methods with that trait to be called on values of that type.
-
#### Unsafety
Unsafe operations are those that potentially violate the memory-safety
@@ -1209,9 +1026,9 @@
[noalias]: http://llvm.org/docs/LangRef.html#noalias
-##### Behaviour not considered unsafe
+##### Behavior not considered unsafe
-This is a list of behaviour not considered *unsafe* in Rust terms, but that may
+This is a list of behavior not considered *unsafe* in Rust terms, but that may
be undesired.
* Deadlocks
@@ -1304,7 +1121,7 @@
several different type constraints.
For example, the following defines the type `Point` as a synonym for the type
-`(u8, u8)`, the type of pairs of unsigned 8 bit integers.:
+`(u8, u8)`, the type of pairs of unsigned 8 bit integers:
```
type Point = (u8, u8);
@@ -1404,10 +1221,6 @@
### 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
@@ -1444,10 +1257,6 @@
### 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
@@ -1555,7 +1364,7 @@
}
```
-Traits also define an [object type](#object-types) with the same name as the
+Traits also define an [trait object](#trait-objects) with the same name as the
trait. Values of this type are created by [casting](#type-cast-expressions)
pointer values (pointing to a type for which an implementation of the given
trait is in scope) to pointers to the trait name, used as a type.
@@ -1702,11 +1511,6 @@
### 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.
@@ -1906,13 +1710,6 @@
## 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
@@ -1958,7 +1755,7 @@
### Crate-only attributes
-- `crate_name` - specify the this crate's crate name.
+- `crate_name` - specify the crate's crate name.
- `crate_type` - see [linkage](#linkage).
- `feature` - see [compiler features](#compiler-features).
- `no_builtins` - disable optimizing certain code patterns to invocations of
@@ -2146,7 +1943,7 @@
`"unix"` or `"windows"`. The value of this configuration option is defined
as a configuration itself, like `unix` or `windows`.
* `target_os = "..."`. Operating system of the target, examples include
- `"win32"`, `"macos"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`,
+ `"windows"`, `"macos"`, `"ios"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`,
`"bitrig"` or `"openbsd"`.
* `target_pointer_width = "..."`. Target pointer width in bits. This is set
to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for
@@ -2494,7 +2291,7 @@
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
@@ -2545,11 +2342,6 @@
#### 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
@@ -2640,7 +2432,7 @@
```{.tuple}
(0,);
(0.0, 4.5);
-("a", 4us, true);
+("a", 4usize, true);
```
### Unit expressions
@@ -2650,15 +2442,6 @@
### 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,
@@ -2709,11 +2492,6 @@
### 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
@@ -2736,22 +2514,14 @@
### 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
exact `self`-type of the left-hand-side is known, or dynamically dispatching if
-the left-hand-side expression is an indirect [object type](#object-types).
+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
@@ -2772,12 +2542,6 @@
### 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.
@@ -2794,10 +2558,6 @@
### 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
@@ -2812,6 +2572,26 @@
(["a", "b"])[10]; // panics
```
+### Range expressions
+
+The `..` operator will construct an object of one of the `std::ops::Range` variants.
+
+```
+1..2; // std::ops::Range
+3..; // std::ops::RangeFrom
+..4; // std::ops::RangeTo
+..; // std::ops::RangeFull
+```
+
+The following expressions are equivalent.
+
+```
+let x = std::ops::Range {start: 0, end: 10};
+let y = 0..10;
+
+assert_eq!(x,y);
+```
+
### Unary operator expressions
Rust defines three unary operators. They are all written as prefix operators,
@@ -2836,10 +2616,6 @@
### Binary operator expressions
-```{.ebnf .gram}
-binop_expr : expr binop expr ;
-```
-
Binary operators expressions are given in terms of [operator
precedence](#operator-precedence).
@@ -3000,10 +2776,6 @@
expression. Parentheses can be used to explicitly specify evaluation order
within an expression.
-```{.ebnf .gram}
-paren_expr : '(' expr ')' ;
-```
-
An example of a parenthesized expression:
```
@@ -3013,12 +2785,6 @@
### 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.
@@ -3034,11 +2800,6 @@
### 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
@@ -3078,11 +2839,39 @@
ten_times(|j| println!("hello, {}", j));
```
-### While loops
+### Infinite loops
-```{.ebnf .gram}
-while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
-```
+A `loop` expression denotes an infinite loop.
+
+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
+within this loop may exit out of this loop or return control to its head.
+See [Break expressions](#break-expressions) and [Continue
+expressions](#continue-expressions).
+
+### Break expressions
+
+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
+present, then `break 'foo` terminates the loop with label `'foo`, which need not
+be the innermost label enclosing the `break` expression, but must enclose it.
+
+### Continue expressions
+
+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
+the case of a `while` loop, the head is the conditional expression controlling
+the loop. In the case of a `for` loop, the head is the call-expression
+controlling the loop. If the label is present, then `continue 'foo` returns
+control to the head of the loop with label `'foo`, which need not be the
+innermost label enclosing the `break` expression, but must enclose it.
+
+A `continue` expression is only permitted in the body of a loop.
+
+### While loops
A `while` loop begins by evaluating the boolean loop conditional expression.
If the loop conditional expression evaluates to `true`, the loop body block
@@ -3100,71 +2889,29 @@
}
```
-### Infinite loops
-
-A `loop` expression denotes an infinite loop.
-
-```{.ebnf .gram}
-loop_expr : [ lifetime ':' ] "loop" '{' block '}';
-```
-
-A `loop` expression may optionally have a _label_. If a label is present, then
-labeled `break` and `continue` expressions nested within this loop may exit out
-of this loop or return control to its head. See [Break
-expressions](#break-expressions) and [Continue
-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
-present, then `break foo` terminates the loop with label `foo`, which need not
-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
-the case of a `while` loop, the head is the conditional expression controlling
-the loop. In the case of a `for` loop, the head is the call-expression
-controlling the loop. If the label is present, then `continue foo` returns
-control to the head of the loop with label `foo`, which need not be the
-innermost label enclosing the `break` expression, but must enclose it.
-
-A `continue` expression is only permitted in the body of a loop.
+Like `loop` expressions, `while` loops can be controlled with `break` or
+`continue`, and may optionally have a _label_. See [infinite
+loops](#infinite-loops), [break expressions](#break-expressions), and
+[continue expressions](#continue-expressions) for more information.
### 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);
}
```
@@ -3177,16 +2924,13 @@
}
```
+Like `loop` expressions, `for` loops can be controlled with `break` or
+`continue`, and may optionally have a _label_. See [infinite
+loops](#infinite-loops), [break expressions](#break-expressions), and
+[continue expressions](#continue-expressions) for more information.
+
### 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`
@@ -3199,14 +2943,6 @@
### 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,
@@ -3323,12 +3059,6 @@
### 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
@@ -3336,10 +3066,6 @@
### 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
@@ -3348,10 +3074,6 @@
### 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
@@ -3383,17 +3105,10 @@
The primitive types are the following:
-* The "unit" type `()`, having the single "unit" value `()` (occasionally called
- "nil"). [^unittype]
* The boolean type `bool` with values `true` and `false`.
* The machine types.
* The machine-dependent integer and floating-point types.
-[^unittype]: The "unit" value `()` is *not* a sentinel "null pointer" value for
- reference variables; the "unit" type is the implicit return type from functions
- otherwise lacking a return type, and can be used in other contexts (such as
- message-sending or type-parametric code) as a zero-size type.]
-
#### Machine types
The machine types are the following:
@@ -3432,9 +3147,9 @@
UTF-32 string.
A value of type `str` is a Unicode string, represented as an array of 8-bit
-unsigned bytes holding a sequence of UTF-8 codepoints. Since `str` is of
+unsigned bytes holding a sequence of UTF-8 code points. Since `str` is of
unknown size, it is not a _first-class_ type, but can only be instantiated
-through a pointer type, such as `&str` or `String`.
+through a pointer type, such as `&str`.
### Tuple types
@@ -3490,7 +3205,7 @@
A `struct` *type* is a heterogeneous product of other types, called the
*fields* of the type.[^structtype]
-[^structtype]: `struct` types are analogous `struct` types in C,
+[^structtype]: `struct` types are analogous to `struct` types in C,
the *record* types of the ML family,
or the *structure* types of the Lisp family.
@@ -3504,7 +3219,7 @@
have the same memory layout.
The fields of a `struct` may be qualified by [visibility
-modifiers](#re-exporting-and-visibility), to allow access to data in a
+modifiers](#visibility-and-privacy), to allow access to data in a
structure outside a module.
A _tuple struct_ type is just like a structure type, except that the fields are
@@ -3572,18 +3287,18 @@
* References (`&`)
: These point to memory _owned by some other value_.
- A reference type is written `&type` for some lifetime-variable `f`,
- or just `&'a type` when you need an explicit lifetime.
+ A reference type is written `&type`,
+ or `&'a type` when you need to specify an explicit lifetime.
Copying a reference is a "shallow" operation:
it involves only copying the pointer itself.
- Releasing a reference typically has no effect on the value it points to,
- with the exception of temporary values, which are released when the last
- reference to them is released.
+ Releasing a reference has no effect on the value it points to,
+ but a reference of a temporary value will keep it alive during the scope
+ of the reference itself.
* Raw pointers (`*`)
: Raw pointers are pointers without safety or liveness guarantees.
Raw pointers are written as `*const T` or `*mut T`,
- for example `*const int` means a raw pointer to an integer.
+ for example `*const i32` means a raw pointer to a 32-bit integer.
Copying or dropping a raw pointer has no effect on the lifecycle of any
other value. Dereferencing a raw pointer or converting it to any other
pointer type is an [`unsafe` operation](#unsafe-functions).
@@ -3616,56 +3331,44 @@
### Closure types
-```{.ebnf .notation}
-closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
- [ ':' bound-list ] [ '->' type ]
-lifetime-list := lifetime | lifetime ',' lifetime-list
-arg-list := ident ':' type | ident ':' type ',' arg-list
-bound-list := bound | bound '+' bound-list
-bound := path | lifetime
-```
+A [lambda expression](#lambda-expressions) produces a closure value with
+a unique, anonymous type that cannot be written out.
-The type of a closure mapping an input of type `A` to an output of type `B` is
-`|A| -> B`. A closure with no arguments or return values has type `||`.
+Depending on the requirements of the closure, its type implements one or
+more of the closure traits:
-An example of creating and calling a closure:
+* `FnOnce`
+ : The closure can be called once. A closure called as `FnOnce`
+ can move out values from its environment.
-```rust
-let captured_var = 10;
+* `FnMut`
+ : The closure can be called multiple times as mutable. A closure called as
+ `FnMut` can mutate values from its environment. `FnMut` implies
+ `FnOnce`.
-let closure_no_args = || println!("captured_var={}", captured_var);
+* `Fn`
+ : The closure can be called multiple times through a shared reference.
+ A closure called as `Fn` can neither move out from nor mutate values
+ from its environment. `Fn` implies `FnMut` and `FnOnce`.
-let closure_args = |arg: i32| -> i32 {
- println!("captured_var={}, arg={}", captured_var, arg);
- arg // Note lack of semicolon after 'arg'
-};
-fn call_closure<F: Fn(), G: Fn(i32) -> i32>(c1: F, c2: G) {
- c1();
- c2(2);
-}
-
-call_closure(closure_no_args, closure_args);
-
-```
-
-### Object types
+### Trait objects
Every trait item (see [traits](#traits)) defines a type with the same name as
-the trait. This type is called the _object type_ of the trait. Object types
+the trait. This type is called the _trait object_ of the trait. Trait objects
permit "late binding" of methods, dispatched using _virtual method tables_
("vtables"). Whereas most calls to trait methods are "early bound" (statically
resolved) to specific implementations at compile time, a call to a method on an
-object type is only resolved to a vtable entry at compile time. The actual
+trait objects is only resolved to a vtable entry at compile time. The actual
implementation for each vtable entry can vary on an object-by-object basis.
Given a pointer-typed expression `E` of type `&T` or `Box<T>`, where `T`
implements trait `R`, casting `E` to the corresponding pointer type `&R` or
-`Box<R>` results in a value of the _object type_ `R`. This result is
+`Box<R>` results in a value of the _trait object_ `R`. This result is
represented as a pair of pointers: the vtable pointer for the `T`
implementation of `R`, and the pointer value of `E`.
-An example of an object type:
+An example of a trait object:
```
trait Printable {
@@ -3685,7 +3388,7 @@
}
```
-In this example, the trait `Printable` occurs as an object type in both the
+In this example, the trait `Printable` occurs as a trait object in both the
type signature of `print`, and the cast expression in `main`.
### Type parameters
@@ -3694,19 +3397,19 @@
its type parameters are types:
```ignore
-fn map<A: Clone, B: Clone>(f: |A| -> B, xs: &[A]) -> Vec<B> {
+fn to_vec<A: Clone>(xs: &[A]) -> Vec<A> {
if xs.is_empty() {
return vec![];
}
- let first: B = f(xs[0].clone());
- let mut rest: Vec<B> = map(f, xs.slice(1, xs.len()));
+ let first: A = xs[0].clone();
+ let mut rest: Vec<A> = to_vec(&xs[1..]);
rest.insert(0, first);
- return rest;
+ rest
}
```
-Here, `first` has type `B`, referring to `map`'s `B` type parameter; and `rest`
-has type `Vec<B>`, a vector type with element type `B`.
+Here, `first` has type `A`, referring to `to_vec`'s `A` type parameter; and `rest`
+has type `Vec<A>`, a vector with element type `A`.
### Self types
diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md
index 0edadeb..695dc42 100644
--- a/src/doc/trpl/SUMMARY.md
+++ b/src/doc/trpl/SUMMARY.md
@@ -7,7 +7,6 @@
* [Learn Rust](learn-rust.md)
* [Effective Rust](effective-rust.md)
* [The Stack and the Heap](the-stack-and-the-heap.md)
- * [Debug and Display](debug-and-display.md)
* [Testing](testing.md)
* [Conditional Compilation](conditional-compilation.md)
* [Documentation](documentation.md)
@@ -37,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)
@@ -51,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)
diff --git a/src/doc/trpl/debug-and-display.md b/src/doc/trpl/debug-and-display.md
deleted file mode 100644
index 918f4c4..0000000
--- a/src/doc/trpl/debug-and-display.md
+++ /dev/null
@@ -1,3 +0,0 @@
-% Debug and Display
-
-Coming soon!
diff --git a/src/doc/trpl/deref-coercions.md b/src/doc/trpl/deref-coercions.md
index afacd30..b701110 100644
--- a/src/doc/trpl/deref-coercions.md
+++ b/src/doc/trpl/deref-coercions.md
@@ -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`.
diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md
index 9fa870a..9d01f10 100644
--- a/src/doc/trpl/macros.md
+++ b/src/doc/trpl/macros.md
@@ -57,8 +57,7 @@
We can implement this shorthand, using a macro: [^actual]
[^actual]: The actual definition of `vec!` in libcollections differs from the
- one presented here, for reasons of efficiency and reusability. Some
- of these are mentioned in the [advanced macros chapter][].
+ one presented here, for reasons of efficiency and reusability.
```rust
macro_rules! vec {
@@ -106,7 +105,7 @@
The matcher `$x:expr` will match any Rust expression, binding that syntax tree
to the ‘metavariable’ `$x`. The identifier `expr` is a ‘fragment specifier’;
-the full possibilities are enumerated in the [advanced macros chapter][].
+the full possibilities are enumerated later in this chapter.
Surrounding the matcher with `$(...),*` will match zero or more expressions,
separated by commas.
@@ -566,7 +565,7 @@
be imported.
The Rust Reference has a [listing of macro-related
-attributes](../reference.html#macro--and-plugin-related-attributes).
+attributes](../reference.html#macro-related-attributes).
# The variable `$crate`
diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md
index 5853f3d..1445d39 100644
--- a/src/doc/trpl/method-syntax.md
+++ b/src/doc/trpl/method-syntax.md
@@ -18,7 +18,7 @@
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 @@
}
```
-## 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 @@
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 @@
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`
diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md
index ccb03c7..e7506df 100644
--- a/src/doc/trpl/mutability.md
+++ b/src/doc/trpl/mutability.md
@@ -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
+
+Mutabilty 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`.
diff --git a/src/doc/trpl/operators-and-overloading.md b/src/doc/trpl/operators-and-overloading.md
index f6f9d5c..6a59465 100644
--- a/src/doc/trpl/operators-and-overloading.md
+++ b/src/doc/trpl/operators-and-overloading.md
@@ -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;
+```
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 554ca3e..9d7f9ea 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -675,7 +675,7 @@
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Default + Sync + Send> Default for Arc<T> {
+impl<T: Default> Default for Arc<T> {
#[stable(feature = "rust1", since = "1.0.0")]
fn default() -> Arc<T> { Arc::new(Default::default()) }
}
diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs
index 2b502b2..4480a7d 100644
--- a/src/libcollections/fmt.rs
+++ b/src/libcollections/fmt.rs
@@ -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
//!
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
index 1c1ad5f..d9cda58 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert.rs
@@ -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.
diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs
index 685b3e5..ec84ef7 100644
--- a/src/libcore/raw.rs
+++ b/src/libcore/raw.rs
@@ -80,7 +80,7 @@
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g. the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
-/// definition will not change the layout of a `&SometTrait`). It is
+/// definition will not change the layout of a `&SomeTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 33ecc0c..182405a 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -75,11 +75,13 @@
into a variable called `op_string` while simultaneously requiring the inner
String to be moved into a variable called `s`.
+```
let x = Some("s".to_string());
match x {
op_string @ Some(s) => ...
None => ...
}
+```
See also Error 303.
"##,
@@ -90,10 +92,12 @@
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:
+```
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => // use s.
...
}
+```
The variable `s` has type String, and its use in the guard is as a variable of
type String. The guard code effectively executes in a separate scope to the body
@@ -102,11 +106,13 @@
innocuous, the problem is most clear when considering functions that take their
argument by value.
+```
match Some("hi".to_string()) {
Some(s) if { drop(s); false } => (),
Some(s) => // use s.
...
}
+```
The value would be dropped in the guard then become unavailable not only in the
body of that arm but also in all subsequent arms! The solution is to bind by
@@ -219,8 +225,10 @@
You can build a free-standing crate by adding `#![no_std]` to the crate
attributes:
+```
#![feature(no_std)]
#![no_std]
+```
See also https://doc.rust-lang.org/book/no-stdlib.html
"##,
@@ -236,11 +244,13 @@
If you want to match against a `static`, consider using a guard instead:
+```
static FORTY_TWO: i32 = 42;
match Some(42) {
Some(x) if x == FORTY_TWO => ...
...
}
+```
"##,
E0161: r##"
@@ -256,6 +266,7 @@
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding instead. For instance:
+```
struct Irrefutable(i32);
let irr = Irrefutable(0);
@@ -268,6 +279,7 @@
// Try this instead:
let Irrefutable(x) = irr;
foo(x);
+```
"##,
E0165: r##"
@@ -275,6 +287,7 @@
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding inside a `loop` instead. For instance:
+```
struct Irrefutable(i32);
let irr = Irrefutable(0);
@@ -288,22 +301,27 @@
let Irrefutable(x) = irr;
...
}
+```
"##,
E0170: r##"
Enum variants are qualified by default. For example, given this type:
+```
enum Method {
GET,
POST
}
+```
you would match it using:
+```
match m {
Method::GET => ...
Method::POST => ...
}
+```
If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so rustc warns when
@@ -312,8 +330,10 @@
Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:
+```
use Method::*;
enum Method { GET, POST }
+```
"##,
E0267: r##"
@@ -333,7 +353,9 @@
This error indicates that the given recursion limit could not be parsed. Ensure
that the value provided is a positive integer between quotes, like so:
+```
#![recursion_limit="1000"]
+```
"##,
E0297: r##"
@@ -342,6 +364,7 @@
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:
+```
// This fails because `None` is not covered.
for Some(x) in xs {
...
@@ -361,6 +384,7 @@
...
}
}
+```
"##,
E0301: r##"
@@ -370,11 +394,13 @@
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:
+```
match Some(()) {
None => { },
option if option.take().is_none() => { /* impossible, option is `Some` */ },
Some(_) => { } // When the previous match failed, the option became `None`.
}
+```
"##,
E0302: r##"
@@ -384,11 +410,13 @@
exhaustive. For instance, the following would not match any arm if assignments
were allowed:
+```
match Some(()) {
None => { },
option if { option = None; false } { },
Some(_) => { } // When the previous match failed, the option became `None`.
}
+```
"##,
E0303: r##"
@@ -396,9 +424,10 @@
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.
-// Before.
-match Some("hi".to_string()) {
- ref op_string_ref @ Some(ref s) => ...
+```
+// Code like this...
+match Some(5) {
+ ref op_num @ Some(num) => ...
None => ...
}
@@ -410,6 +439,7 @@
}
None => ...
}
+```
The `op_string_ref` binding has type &Option<&String> in both cases.
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 9093b3b..d4012f2 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -106,8 +106,10 @@
pub mod entry;
pub mod expr_use_visitor;
pub mod fast_reject;
+ pub mod free_region;
pub mod intrinsicck;
pub mod infer;
+ pub mod implicator;
pub mod lang_items;
pub mod liveness;
pub mod mem_categorization;
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
new file mode 100644
index 0000000..0c8a956
--- /dev/null
+++ b/src/librustc/middle/free_region.rs
@@ -0,0 +1,127 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This file defines
+
+use middle::implicator::Implication;
+use middle::ty::{self, FreeRegion};
+use util::common::can_reach;
+use util::nodemap::FnvHashMap;
+use util::ppaux::Repr;
+
+#[derive(Clone)]
+pub struct FreeRegionMap {
+ /// `free_region_map` maps from a free region `a` to a list of
+ /// free regions `bs` such that `a <= b for all b in bs`
+ map: FnvHashMap<FreeRegion, Vec<FreeRegion>>,
+}
+
+impl FreeRegionMap {
+ pub fn new() -> FreeRegionMap {
+ FreeRegionMap { map: FnvHashMap() }
+ }
+
+ pub fn relate_free_regions_from_implications<'tcx>(&mut self,
+ tcx: &ty::ctxt<'tcx>,
+ implications: &[Implication<'tcx>])
+ {
+ for implication in implications {
+ debug!("implication: {}", implication.repr(tcx));
+ match *implication {
+ Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => {
+ self.relate_free_regions(free_a, free_b);
+ }
+ Implication::RegionSubRegion(..) |
+ Implication::RegionSubClosure(..) |
+ Implication::RegionSubGeneric(..) |
+ Implication::Predicate(..) => {
+ }
+ }
+ }
+ }
+
+ pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
+ tcx: &ty::ctxt<'tcx>,
+ predicates: &[ty::Predicate<'tcx>]) {
+ debug!("relate_free_regions_from_predicates(predicates={})", predicates.repr(tcx));
+ for predicate in predicates {
+ match *predicate {
+ ty::Predicate::Projection(..) |
+ ty::Predicate::Trait(..) |
+ ty::Predicate::Equate(..) |
+ ty::Predicate::TypeOutlives(..) => {
+ // No region bounds here
+ }
+ ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
+ match (r_a, r_b) {
+ (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
+ // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
+ self.relate_free_regions(fr_b, fr_a);
+ }
+ _ => {
+ // All named regions are instantiated with free regions.
+ tcx.sess.bug(
+ &format!("record_region_bounds: non free region: {} / {}",
+ r_a.repr(tcx),
+ r_b.repr(tcx)));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
+ let mut sups = self.map.entry(sub).or_insert(Vec::new());
+ if !sups.contains(&sup) {
+ sups.push(sup);
+ }
+ }
+
+ /// Determines whether two free regions have a subregion relationship
+ /// by walking the graph encoded in `map`. Note that
+ /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
+ /// (that is, the user can give two different names to the same lifetime).
+ pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
+ can_reach(&self.map, sub, sup)
+ }
+
+ /// Determines whether one region is a subregion of another. This is intended to run *after
+ /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
+ pub fn is_subregion_of(&self,
+ tcx: &ty::ctxt,
+ sub_region: ty::Region,
+ super_region: ty::Region)
+ -> bool {
+ debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
+ sub_region, super_region);
+
+ sub_region == super_region || {
+ match (sub_region, super_region) {
+ (ty::ReEmpty, _) |
+ (_, ty::ReStatic) =>
+ true,
+
+ (ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
+ tcx.region_maps.is_subscope_of(sub_scope, super_scope),
+
+ (ty::ReScope(sub_scope), ty::ReFree(ref fr)) =>
+ tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()),
+
+ (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
+ self.sub_free_region(sub_fr, super_fr),
+
+ _ =>
+ false,
+ }
+ }
+ }
+}
+
diff --git a/src/librustc_typeck/check/implicator.rs b/src/librustc/middle/implicator.rs
similarity index 91%
rename from src/librustc_typeck/check/implicator.rs
rename to src/librustc/middle/implicator.rs
index a4a18c7..0d6a1df 100644
--- a/src/librustc_typeck/check/implicator.rs
+++ b/src/librustc/middle/implicator.rs
@@ -10,11 +10,10 @@
// #![warn(deprecated_mode)]
-use astconv::object_region_bounds;
use middle::infer::{InferCtxt, GenericKind};
use middle::subst::Substs;
use middle::traits;
-use middle::ty::{self, ToPolyTraitRef, Ty};
+use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty_fold::{TypeFoldable, TypeFolder};
use std::rc::Rc;
@@ -423,6 +422,39 @@
}
}
+/// Given an object type like `SomeTrait+Send`, computes the lifetime
+/// bounds that must hold on the elided self type. These are derived
+/// from the declarations of `SomeTrait`, `Send`, and friends -- if
+/// they declare `trait SomeTrait : 'static`, for example, then
+/// `'static` would appear in the list. The hard work is done by
+/// `ty::required_region_bounds`, see that for more information.
+pub fn object_region_bounds<'tcx>(
+ tcx: &ty::ctxt<'tcx>,
+ principal: &ty::PolyTraitRef<'tcx>,
+ others: ty::BuiltinBounds)
+ -> Vec<ty::Region>
+{
+ // Since we don't actually *know* the self type for an object,
+ // this "open(err)" serves as a kind of dummy standin -- basically
+ // a skolemized type.
+ let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
+
+ // Note that we preserve the overall binding levels here.
+ assert!(!open_ty.has_escaping_regions());
+ let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
+ let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
+
+ let param_bounds = ty::ParamBounds {
+ region_bounds: Vec::new(),
+ builtin_bounds: others,
+ trait_bounds: trait_refs,
+ projection_bounds: Vec::new(), // not relevant to computing region bounds
+ };
+
+ let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
+ ty::required_region_bounds(tcx, open_ty, predicates)
+}
+
impl<'tcx> Repr<'tcx> for Implication<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index b0921a2..63e4a5c 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -22,6 +22,7 @@
pub use self::freshen::TypeFreshener;
pub use self::region_inference::GenericKind;
+use middle::free_region::FreeRegionMap;
use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
@@ -855,8 +856,10 @@
self.region_vars.new_bound(debruijn)
}
- pub fn resolve_regions_and_report_errors(&self, subject_node_id: ast::NodeId) {
- let errors = self.region_vars.resolve_regions(subject_node_id);
+ pub fn resolve_regions_and_report_errors(&self,
+ free_regions: &FreeRegionMap,
+ subject_node_id: ast::NodeId) {
+ let errors = self.region_vars.resolve_regions(free_regions, subject_node_id);
self.report_region_errors(&errors); // see error_reporting.rs
}
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index e764681..9de362f 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -21,6 +21,7 @@
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use rustc_data_structures::graph::{self, Direction, NodeIndex};
+use middle::free_region::FreeRegionMap;
use middle::region;
use middle::ty::{self, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
@@ -711,19 +712,19 @@
/// fixed-point iteration to find region values which satisfy all
/// constraints, assuming such values can be found; if they cannot,
/// errors are reported.
- pub fn resolve_regions(&self, subject_node: ast::NodeId) -> Vec<RegionResolutionError<'tcx>> {
+ pub fn resolve_regions(&self,
+ free_regions: &FreeRegionMap,
+ subject_node: ast::NodeId)
+ -> Vec<RegionResolutionError<'tcx>>
+ {
debug!("RegionVarBindings: resolve_regions()");
let mut errors = vec!();
- let v = self.infer_variable_values(&mut errors, subject_node);
+ let v = self.infer_variable_values(free_regions, &mut errors, subject_node);
*self.values.borrow_mut() = Some(v);
errors
}
- fn is_subregion_of(&self, sub: Region, sup: Region) -> bool {
- self.tcx.region_maps.is_subregion_of(sub, sup)
- }
-
- fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
+ fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Region) -> Region {
match (a, b) {
(ReLateBound(..), _) |
(_, ReLateBound(..)) |
@@ -781,7 +782,7 @@
}
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
- self.lub_free_regions(a_fr, b_fr)
+ self.lub_free_regions(free_regions, a_fr, b_fr)
}
// For these types, we cannot define any additional
@@ -796,23 +797,25 @@
/// Computes a region that encloses both free region arguments. Guarantee that if the same two
/// regions are given as argument, in any order, a consistent result is returned.
fn lub_free_regions(&self,
+ free_regions: &FreeRegionMap,
a: &FreeRegion,
b: &FreeRegion)
-> ty::Region
{
return match a.cmp(b) {
- Less => helper(self, a, b),
- Greater => helper(self, b, a),
+ Less => helper(self, free_regions, a, b),
+ Greater => helper(self, free_regions, b, a),
Equal => ty::ReFree(*a)
};
- fn helper(this: &RegionVarBindings,
+ fn helper(_this: &RegionVarBindings,
+ free_regions: &FreeRegionMap,
a: &FreeRegion,
b: &FreeRegion) -> ty::Region
{
- if this.tcx.region_maps.sub_free_region(*a, *b) {
+ if free_regions.sub_free_region(*a, *b) {
ty::ReFree(*b)
- } else if this.tcx.region_maps.sub_free_region(*b, *a) {
+ } else if free_regions.sub_free_region(*b, *a) {
ty::ReFree(*a)
} else {
ty::ReStatic
@@ -821,6 +824,7 @@
}
fn glb_concrete_regions(&self,
+ free_regions: &FreeRegionMap,
a: Region,
b: Region)
-> RelateResult<'tcx, Region>
@@ -878,7 +882,7 @@
}
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
- self.glb_free_regions(a_fr, b_fr)
+ self.glb_free_regions(free_regions, a_fr, b_fr)
}
// For these types, we cannot define any additional
@@ -898,23 +902,25 @@
/// if the same two regions are given as argument, in any order, a consistent result is
/// returned.
fn glb_free_regions(&self,
+ free_regions: &FreeRegionMap,
a: &FreeRegion,
b: &FreeRegion)
-> RelateResult<'tcx, ty::Region>
{
return match a.cmp(b) {
- Less => helper(self, a, b),
- Greater => helper(self, b, a),
+ Less => helper(self, free_regions, a, b),
+ Greater => helper(self, free_regions, b, a),
Equal => Ok(ty::ReFree(*a))
};
fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
+ free_regions: &FreeRegionMap,
a: &FreeRegion,
b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
{
- if this.tcx.region_maps.sub_free_region(*a, *b) {
+ if free_regions.sub_free_region(*a, *b) {
Ok(ty::ReFree(*a))
- } else if this.tcx.region_maps.sub_free_region(*b, *a) {
+ } else if free_regions.sub_free_region(*b, *a) {
Ok(ty::ReFree(*b))
} else {
this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
@@ -970,6 +976,7 @@
impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
fn infer_variable_values(&self,
+ free_regions: &FreeRegionMap,
errors: &mut Vec<RegionResolutionError<'tcx>>,
subject: ast::NodeId) -> Vec<VarValue>
{
@@ -980,12 +987,13 @@
debug!("----() End constraint listing {:?}---", self.dump_constraints());
graphviz::maybe_print_constraints_for(self, subject);
- self.expansion(&mut var_data);
- self.contraction(&mut var_data);
+ self.expansion(free_regions, &mut var_data);
+ self.contraction(free_regions, &mut var_data);
let values =
- self.extract_values_and_collect_conflicts(&var_data[..],
+ self.extract_values_and_collect_conflicts(free_regions,
+ &var_data[..],
errors);
- self.collect_concrete_region_errors(&values, errors);
+ self.collect_concrete_region_errors(free_regions, &values, errors);
values
}
@@ -1009,7 +1017,7 @@
}
}
- fn expansion(&self, var_data: &mut [VarData]) {
+ fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Expansion", |constraint| {
debug!("expansion: constraint={} origin={}",
constraint.repr(self.tcx),
@@ -1020,14 +1028,14 @@
match *constraint {
ConstrainRegSubVar(a_region, b_vid) => {
let b_data = &mut var_data[b_vid.index as usize];
- self.expand_node(a_region, b_vid, b_data)
+ self.expand_node(free_regions, a_region, b_vid, b_data)
}
ConstrainVarSubVar(a_vid, b_vid) => {
match var_data[a_vid.index as usize].value {
NoValue | ErrorValue => false,
Value(a_region) => {
let b_node = &mut var_data[b_vid.index as usize];
- self.expand_node(a_region, b_vid, b_node)
+ self.expand_node(free_regions, a_region, b_vid, b_node)
}
}
}
@@ -1040,6 +1048,7 @@
}
fn expand_node(&self,
+ free_regions: &FreeRegionMap,
a_region: Region,
b_vid: RegionVid,
b_data: &mut VarData)
@@ -1072,7 +1081,7 @@
}
Value(cur_region) => {
- let lub = self.lub_concrete_regions(a_region, cur_region);
+ let lub = self.lub_concrete_regions(free_regions, a_region, cur_region);
if lub == cur_region {
return false;
}
@@ -1093,6 +1102,7 @@
}
fn contraction(&self,
+ free_regions: &FreeRegionMap,
var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Contraction", |constraint| {
debug!("contraction: constraint={} origin={}",
@@ -1111,19 +1121,20 @@
NoValue | ErrorValue => false,
Value(b_region) => {
let a_data = &mut var_data[a_vid.index as usize];
- self.contract_node(a_vid, a_data, b_region)
+ self.contract_node(free_regions, a_vid, a_data, b_region)
}
}
}
ConstrainVarSubReg(a_vid, b_region) => {
let a_data = &mut var_data[a_vid.index as usize];
- self.contract_node(a_vid, a_data, b_region)
+ self.contract_node(free_regions, a_vid, a_data, b_region)
}
}
})
}
fn contract_node(&self,
+ free_regions: &FreeRegionMap,
a_vid: RegionVid,
a_data: &mut VarData,
b_region: Region)
@@ -1143,19 +1154,23 @@
Value(a_region) => {
match a_data.classification {
- Expanding => check_node(self, a_vid, a_data, a_region, b_region),
- Contracting => adjust_node(self, a_vid, a_data, a_region, b_region),
+ Expanding =>
+ check_node(self, free_regions, a_vid, a_data, a_region, b_region),
+ Contracting =>
+ adjust_node(self, free_regions, a_vid, a_data, a_region, b_region),
}
}
};
fn check_node(this: &RegionVarBindings,
+ free_regions: &FreeRegionMap,
a_vid: RegionVid,
a_data: &mut VarData,
a_region: Region,
b_region: Region)
- -> bool {
- if !this.is_subregion_of(a_region, b_region) {
+ -> bool
+ {
+ if !free_regions.is_subregion_of(this.tcx, a_region, b_region) {
debug!("Setting {:?} to ErrorValue: {} not subregion of {}",
a_vid,
a_region.repr(this.tcx),
@@ -1166,12 +1181,13 @@
}
fn adjust_node(this: &RegionVarBindings,
+ free_regions: &FreeRegionMap,
a_vid: RegionVid,
a_data: &mut VarData,
a_region: Region,
b_region: Region)
-> bool {
- match this.glb_concrete_regions(a_region, b_region) {
+ match this.glb_concrete_regions(free_regions, a_region, b_region) {
Ok(glb) => {
if glb == a_region {
false
@@ -1197,6 +1213,7 @@
}
fn collect_concrete_region_errors(&self,
+ free_regions: &FreeRegionMap,
values: &Vec<VarValue>,
errors: &mut Vec<RegionResolutionError<'tcx>>)
{
@@ -1204,7 +1221,7 @@
for verify in &*self.verifys.borrow() {
match *verify {
VerifyRegSubReg(ref origin, sub, sup) => {
- if self.is_subregion_of(sub, sup) {
+ if free_regions.is_subregion_of(self.tcx, sub, sup) {
continue;
}
@@ -1222,7 +1239,7 @@
let sub = normalize(values, sub);
if sups.iter()
.map(|&sup| normalize(values, sup))
- .any(|sup| self.is_subregion_of(sub, sup))
+ .any(|sup| free_regions.is_subregion_of(self.tcx, sub, sup))
{
continue;
}
@@ -1239,6 +1256,7 @@
fn extract_values_and_collect_conflicts(
&self,
+ free_regions: &FreeRegionMap,
var_data: &[VarData],
errors: &mut Vec<RegionResolutionError<'tcx>>)
-> Vec<VarValue>
@@ -1304,12 +1322,12 @@
match var_data[idx].classification {
Expanding => {
self.collect_error_for_expanding_node(
- graph, var_data, &mut dup_vec,
+ free_regions, graph, var_data, &mut dup_vec,
node_vid, errors);
}
Contracting => {
self.collect_error_for_contracting_node(
- graph, var_data, &mut dup_vec,
+ free_regions, graph, var_data, &mut dup_vec,
node_vid, errors);
}
}
@@ -1355,13 +1373,13 @@
return graph;
}
- fn collect_error_for_expanding_node(
- &self,
- graph: &RegionGraph,
- var_data: &[VarData],
- dup_vec: &mut [u32],
- node_idx: RegionVid,
- errors: &mut Vec<RegionResolutionError<'tcx>>)
+ fn collect_error_for_expanding_node(&self,
+ free_regions: &FreeRegionMap,
+ graph: &RegionGraph,
+ var_data: &[VarData],
+ dup_vec: &mut [u32],
+ node_idx: RegionVid,
+ errors: &mut Vec<RegionResolutionError<'tcx>>)
{
// Errors in expanding nodes result from a lower-bound that is
// not contained by an upper-bound.
@@ -1394,8 +1412,9 @@
for lower_bound in &lower_bounds {
for upper_bound in &upper_bounds {
- if !self.is_subregion_of(lower_bound.region,
- upper_bound.region) {
+ if !free_regions.is_subregion_of(self.tcx,
+ lower_bound.region,
+ upper_bound.region) {
debug!("pushing SubSupConflict sub: {:?} sup: {:?}",
lower_bound.region, upper_bound.region);
errors.push(SubSupConflict(
@@ -1420,6 +1439,7 @@
fn collect_error_for_contracting_node(
&self,
+ free_regions: &FreeRegionMap,
graph: &RegionGraph,
var_data: &[VarData],
dup_vec: &mut [u32],
@@ -1438,7 +1458,8 @@
for upper_bound_1 in &upper_bounds {
for upper_bound_2 in &upper_bounds {
- match self.glb_concrete_regions(upper_bound_1.region,
+ match self.glb_concrete_regions(free_regions,
+ upper_bound_1.region,
upper_bound_2.region) {
Ok(_) => {}
Err(_) => {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 2f72960..2c510b5 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -17,9 +17,8 @@
//! `middle/typeck/infer/region_inference.rs`
use session::Session;
-use middle::ty::{self, Ty, FreeRegion};
+use middle::ty::{self, Ty};
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
-use util::common::can_reach;
use std::cell::RefCell;
use syntax::codemap::{self, Span};
@@ -234,14 +233,6 @@
/// which that variable is declared.
var_map: RefCell<NodeMap<CodeExtent>>,
- /// `free_region_map` maps from a free region `a` to a list of
- /// free regions `bs` such that `a <= b for all b in bs`
- ///
- /// NB. the free region map is populated during type check as we
- /// check each function. See the function `relate_free_regions`
- /// for more information.
- free_region_map: RefCell<FnvHashMap<FreeRegion, Vec<FreeRegion>>>,
-
/// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
/// larger than the default. The map goes from the expression id
/// to the cleanup scope id. For rvalues not present in this
@@ -390,13 +381,6 @@
e(child, parent)
}
}
- pub fn each_encl_free_region<E>(&self, mut e:E) where E: FnMut(&FreeRegion, &FreeRegion) {
- for (child, parents) in self.free_region_map.borrow().iter() {
- for parent in parents.iter() {
- e(child, parent)
- }
- }
- }
pub fn each_rvalue_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) {
for (child, parent) in self.rvalue_scopes.borrow().iter() {
e(child, parent)
@@ -408,21 +392,6 @@
}
}
- pub fn relate_free_regions(&self, sub: FreeRegion, sup: FreeRegion) {
- match self.free_region_map.borrow_mut().get_mut(&sub) {
- Some(sups) => {
- if !sups.iter().any(|x| x == &sup) {
- sups.push(sup);
- }
- return;
- }
- None => {}
- }
-
- debug!("relate_free_regions(sub={:?}, sup={:?})", sub, sup);
- self.free_region_map.borrow_mut().insert(sub, vec!(sup));
- }
-
/// Records that `sub_fn` is defined within `sup_fn`. These ids
/// should be the id of the block that is the fn body, which is
/// also the root of the region hierarchy for that fn.
@@ -567,56 +536,6 @@
return true;
}
- /// Determines whether two free regions have a subregion relationship
- /// by walking the graph encoded in `free_region_map`. Note that
- /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
- /// (that is, the user can give two different names to the same lifetime).
- pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
- can_reach(&*self.free_region_map.borrow(), sub, sup)
- }
-
- /// Determines whether one region is a subregion of another. This is intended to run *after
- /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
- pub fn is_subregion_of(&self,
- sub_region: ty::Region,
- super_region: ty::Region)
- -> bool {
- debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
- sub_region, super_region);
-
- sub_region == super_region || {
- match (sub_region, super_region) {
- (ty::ReEmpty, _) |
- (_, ty::ReStatic) => {
- true
- }
-
- (ty::ReScope(sub_scope), ty::ReScope(super_scope)) => {
- self.is_subscope_of(sub_scope, super_scope)
- }
-
- (ty::ReScope(sub_scope), ty::ReFree(ref fr)) => {
- self.is_subscope_of(sub_scope, fr.scope.to_code_extent())
- }
-
- (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => {
- self.sub_free_region(sub_fr, super_fr)
- }
-
- (ty::ReEarlyBound(data_a), ty::ReEarlyBound(data_b)) => {
- // This case is used only to make sure that explicitly-
- // specified `Self` types match the real self type in
- // implementations. Yuck.
- data_a == data_b
- }
-
- _ => {
- false
- }
- }
- }
- }
-
/// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest
/// scope which is greater than or equal to both `scope_a` and `scope_b`.
pub fn nearest_common_ancestor(&self,
@@ -1291,7 +1210,6 @@
let maps = RegionMaps {
scope_map: RefCell::new(FnvHashMap()),
var_map: RefCell::new(NodeMap()),
- free_region_map: RefCell::new(FnvHashMap()),
rvalue_scopes: RefCell::new(NodeMap()),
terminating_scopes: RefCell::new(FnvHashSet()),
fn_tree: RefCell::new(NodeMap()),
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 8809abd..b221c4b 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -15,6 +15,7 @@
pub use self::Vtable::*;
pub use self::ObligationCauseCode::*;
+use middle::free_region::FreeRegionMap;
use middle::subst;
use middle::ty::{self, HasProjectionTypes, Ty};
use middle::ty_fold::TypeFoldable;
@@ -424,7 +425,8 @@
}
};
- infcx.resolve_regions_and_report_errors(body_id);
+ let free_regions = FreeRegionMap::new();
+ infcx.resolve_regions_and_report_errors(&free_regions, body_id);
let predicates = match infcx.fully_resolve(&predicates) {
Ok(predicates) => predicates,
Err(fixup_err) => {
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index ed8a6fb..153ec0a 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -532,11 +532,8 @@
obligation.repr(self.tcx()));
self.infcx.probe(|snapshot| {
- let (skol_obligation_trait_ref, skol_map) =
- self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
- match self.match_impl(impl_def_id, obligation, snapshot,
- &skol_map, skol_obligation_trait_ref.trait_ref.clone()) {
- Ok(substs) => {
+ match self.match_impl(impl_def_id, obligation, snapshot) {
+ Ok((substs, skol_map)) => {
let vtable_impl = self.vtable_impl(impl_def_id,
substs,
obligation.cause.clone(),
@@ -1160,10 +1157,7 @@
let all_impls = self.all_impls(def_id);
for &impl_def_id in &all_impls {
self.infcx.probe(|snapshot| {
- let (skol_obligation_trait_pred, skol_map) =
- self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
- match self.match_impl(impl_def_id, obligation, snapshot,
- &skol_map, skol_obligation_trait_pred.trait_ref.clone()) {
+ match self.match_impl(impl_def_id, obligation, snapshot) {
Ok(_) => {
candidates.vec.push(ImplCandidate(impl_def_id));
}
@@ -2115,11 +2109,9 @@
// First, create the substitutions by matching the impl again,
// this time not in a probe.
self.infcx.commit_if_ok(|snapshot| {
- let (skol_obligation_trait_ref, skol_map) =
- self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
- let substs =
+ let (substs, skol_map) =
self.rematch_impl(impl_def_id, obligation,
- snapshot, &skol_map, skol_obligation_trait_ref.trait_ref);
+ snapshot);
debug!("confirm_impl_candidate substs={}", substs.repr(self.tcx()));
Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
obligation.recursion_depth + 1, skol_map, snapshot))
@@ -2306,14 +2298,11 @@
fn rematch_impl(&mut self,
impl_def_id: ast::DefId,
obligation: &TraitObligation<'tcx>,
- snapshot: &infer::CombinedSnapshot,
- skol_map: &infer::SkolemizationMap,
- skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>)
- -> Normalized<'tcx, Substs<'tcx>>
+ snapshot: &infer::CombinedSnapshot)
+ -> (Normalized<'tcx, Substs<'tcx>>, infer::SkolemizationMap)
{
- match self.match_impl(impl_def_id, obligation, snapshot,
- skol_map, skol_obligation_trait_ref) {
- Ok(substs) => substs,
+ match self.match_impl(impl_def_id, obligation, snapshot) {
+ Ok((substs, skol_map)) => (substs, skol_map),
Err(()) => {
self.tcx().sess.bug(
&format!("Impl {} was matchable against {} but now is not",
@@ -2326,10 +2315,9 @@
fn match_impl(&mut self,
impl_def_id: ast::DefId,
obligation: &TraitObligation<'tcx>,
- snapshot: &infer::CombinedSnapshot,
- skol_map: &infer::SkolemizationMap,
- skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>)
- -> Result<Normalized<'tcx, Substs<'tcx>>, ()>
+ snapshot: &infer::CombinedSnapshot)
+ -> Result<(Normalized<'tcx, Substs<'tcx>>,
+ infer::SkolemizationMap), ()>
{
let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
@@ -2340,6 +2328,11 @@
return Err(());
}
+ let (skol_obligation, skol_map) = self.infcx().skolemize_late_bound_regions(
+ &obligation.predicate,
+ snapshot);
+ let skol_obligation_trait_ref = skol_obligation.trait_ref;
+
let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
obligation.cause.span,
impl_def_id);
@@ -2370,17 +2363,17 @@
return Err(());
}
- if let Err(e) = self.infcx.leak_check(skol_map, snapshot) {
+ if let Err(e) = self.infcx.leak_check(&skol_map, snapshot) {
debug!("match_impl: failed leak check due to `{}`",
ty::type_err_to_str(self.tcx(), &e));
return Err(());
}
debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx()));
- Ok(Normalized {
+ Ok((Normalized {
value: impl_substs,
obligations: impl_trait_ref.obligations
- })
+ }, skol_map))
}
fn fast_reject_trait_refs(&mut self,
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 2c94399..232e962 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -45,12 +45,14 @@
use middle::const_eval;
use middle::def::{self, DefMap, ExportMap};
use middle::dependency_format;
+use middle::free_region::FreeRegionMap;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::mem_categorization as mc;
use middle::region;
use middle::resolve_lifetime;
use middle::infer;
use middle::pat_util;
+use middle::region::RegionMaps;
use middle::stability;
use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
use middle::traits;
@@ -620,7 +622,14 @@
pub named_region_map: resolve_lifetime::NamedRegionMap,
- pub region_maps: middle::region::RegionMaps,
+ pub region_maps: RegionMaps,
+
+ // For each fn declared in the local crate, type check stores the
+ // free-region relationships that were deduced from its where
+ // clauses and parameter types. These are then read-again by
+ // borrowck. (They are not used during trans, and hence are not
+ // serialized or needed for cross-crate fns.)
+ free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
/// Stores the types for various nodes in the AST. Note that this table
/// is not guaranteed to be populated until after typeck. See
@@ -795,6 +804,15 @@
pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
self.node_types.borrow_mut().insert(id, ty);
}
+
+ pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
+ self.free_region_maps.borrow_mut()
+ .insert(id, map);
+ }
+
+ pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
+ self.free_region_maps.borrow()[&id].clone()
+ }
}
// Flags that we track on types. These flags are propagated upwards
@@ -2546,7 +2564,7 @@
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
freevars: RefCell<FreevarMap>,
- region_maps: middle::region::RegionMaps,
+ region_maps: RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index) -> ctxt<'tcx>
{
@@ -2561,11 +2579,12 @@
region_interner: RefCell::new(FnvHashMap()),
types: common_types,
named_region_map: named_region_map,
+ region_maps: region_maps,
+ free_region_maps: RefCell::new(FnvHashMap()),
item_variance_map: RefCell::new(DefIdMap()),
variance_computed: Cell::new(false),
sess: s,
def_map: def_map,
- region_maps: region_maps,
node_types: RefCell::new(FnvHashMap()),
item_substs: RefCell::new(NodeMap()),
impl_trait_refs: RefCell::new(NodeMap()),
@@ -6537,14 +6556,6 @@
let bounds = liberate_late_bound_regions(tcx, free_id_outlive, &ty::Binder(bounds));
let predicates = bounds.predicates.into_vec();
- //
- // Compute region bounds. For now, these relations are stored in a
- // global table on the tcx, so just enter them there. I'm not
- // crazy about this scheme, but it's convenient, at least.
- //
-
- record_region_bounds(tcx, &*predicates);
-
debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}",
free_id,
free_substs.repr(tcx),
@@ -6573,37 +6584,7 @@
};
let cause = traits::ObligationCause::misc(span, free_id);
- return traits::normalize_param_env_or_error(unnormalized_env, cause);
-
- fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, predicates: &[ty::Predicate<'tcx>]) {
- debug!("record_region_bounds(predicates={:?})", predicates.repr(tcx));
-
- for predicate in predicates {
- match *predicate {
- Predicate::Projection(..) |
- Predicate::Trait(..) |
- Predicate::Equate(..) |
- Predicate::TypeOutlives(..) => {
- // No region bounds here
- }
- Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
- match (r_a, r_b) {
- (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
- // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
- tcx.region_maps.relate_free_regions(fr_b, fr_a);
- }
- _ => {
- // All named regions are instantiated with free regions.
- tcx.sess.bug(
- &format!("record_region_bounds: non free region: {} / {}",
- r_a.repr(tcx),
- r_b.repr(tcx)));
- }
- }
- }
- }
- }
- }
+ traits::normalize_param_env_or_error(unnormalized_env, cause)
}
impl BorrowKind {
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 502321d..aedc0d2 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -27,9 +27,11 @@
use rustc::middle::dataflow::KillFrom;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
+use rustc::middle::free_region::FreeRegionMap;
use rustc::middle::region;
use rustc::middle::ty::{self, Ty};
use rustc::util::ppaux::{note_and_explain_region, Repr, UserString};
+use std::mem;
use std::rc::Rc;
use std::string::String;
use syntax::ast;
@@ -56,7 +58,20 @@
impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
b: &'v Block, s: Span, id: ast::NodeId) {
- borrowck_fn(self, fk, fd, b, s, id);
+ match fk {
+ visit::FkItemFn(..) |
+ visit::FkMethod(..) => {
+ let new_free_region_map = self.tcx.free_region_map(id);
+ let old_free_region_map =
+ mem::replace(&mut self.free_region_map, new_free_region_map);
+ borrowck_fn(self, fk, fd, b, s, id);
+ self.free_region_map = old_free_region_map;
+ }
+
+ visit::FkFnBlock => {
+ borrowck_fn(self, fk, fd, b, s, id);
+ }
+ }
}
fn visit_item(&mut self, item: &ast::Item) {
@@ -67,6 +82,7 @@
pub fn check_crate(tcx: &ty::ctxt) {
let mut bccx = BorrowckCtxt {
tcx: tcx,
+ free_region_map: FreeRegionMap::new(),
stats: BorrowStats {
loaned_paths_same: 0,
loaned_paths_imm: 0,
@@ -129,11 +145,13 @@
let cfg = cfg::CFG::new(this.tcx, body);
let AnalysisData { all_loans,
loans: loan_dfcx,
- move_data:flowed_moves } =
+ move_data: flowed_moves } =
build_borrowck_dataflow_data(this, fk, decl, &cfg, body, sp, id);
move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
- this.tcx, sp, id);
+ this.tcx,
+ sp,
+ id);
check_loans::check_loans(this,
&loan_dfcx,
@@ -152,7 +170,9 @@
cfg: &cfg::CFG,
body: &ast::Block,
sp: Span,
- id: ast::NodeId) -> AnalysisData<'a, 'tcx> {
+ id: ast::NodeId)
+ -> AnalysisData<'a, 'tcx>
+{
// Check the body of fn items.
let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id);
let (all_loans, move_data) =
@@ -203,10 +223,13 @@
/// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer.
pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
tcx: &'a ty::ctxt<'tcx>,
- input: FnPartsWithCFG<'a>) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>) {
+ input: FnPartsWithCFG<'a>)
+ -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>)
+{
let mut bccx = BorrowckCtxt {
tcx: tcx,
+ free_region_map: FreeRegionMap::new(),
stats: BorrowStats {
loaned_paths_same: 0,
loaned_paths_imm: 0,
@@ -234,6 +257,18 @@
pub struct BorrowckCtxt<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
+ // Hacky. As we visit various fns, we have to load up the
+ // free-region map for each one. This map is computed by during
+ // typeck for each fn item and stored -- closures just use the map
+ // from the fn item that encloses them. Since we walk the fns in
+ // order, we basically just overwrite this field as we enter a fn
+ // item and restore it afterwards in a stack-like fashion. Then
+ // the borrow checking code can assume that `free_region_map` is
+ // always the correct map for the current fn. Feels like it'd be
+ // better to just recompute this, rather than store it, but it's a
+ // bit of a pain to factor that code out at the moment.
+ free_region_map: FreeRegionMap,
+
// Statistics:
stats: BorrowStats
}
@@ -518,8 +553,9 @@
impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
- -> bool {
- self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
+ -> bool
+ {
+ self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
}
pub fn report(&self, err: BckError<'tcx>) {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 12b16e9..a8cf753 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -16,6 +16,7 @@
use rustc_lint;
use rustc_resolve as resolve;
use rustc_typeck::middle::lang_items;
+use rustc_typeck::middle::free_region::FreeRegionMap;
use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData};
use rustc_typeck::middle::resolve_lifetime;
use rustc_typeck::middle::stability;
@@ -138,7 +139,8 @@
stability::Index::new(krate));
let infcx = infer::new_infer_ctxt(&tcx);
body(Env { infcx: &infcx });
- infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);
+ let free_regions = FreeRegionMap::new();
+ infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
assert_eq!(tcx.sess.err_count(), expected_err_count);
}
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 78797d0..9dbf918 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -51,6 +51,7 @@
use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
use middle::const_eval;
use middle::def;
+use middle::implicator::object_region_bounds;
use middle::resolve_lifetime as rl;
use middle::privacy::{AllPublic, LastMod};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
@@ -2087,39 +2088,6 @@
return r;
}
-/// Given an object type like `SomeTrait+Send`, computes the lifetime
-/// bounds that must hold on the elided self type. These are derived
-/// from the declarations of `SomeTrait`, `Send`, and friends -- if
-/// they declare `trait SomeTrait : 'static`, for example, then
-/// `'static` would appear in the list. The hard work is done by
-/// `ty::required_region_bounds`, see that for more information.
-pub fn object_region_bounds<'tcx>(
- tcx: &ty::ctxt<'tcx>,
- principal: &ty::PolyTraitRef<'tcx>,
- others: ty::BuiltinBounds)
- -> Vec<ty::Region>
-{
- // Since we don't actually *know* the self type for an object,
- // this "open(err)" serves as a kind of dummy standin -- basically
- // a skolemized type.
- let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
-
- // Note that we preserve the overall binding levels here.
- assert!(!open_ty.has_escaping_regions());
- let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
- let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
-
- let param_bounds = ty::ParamBounds {
- region_bounds: Vec::new(),
- builtin_bounds: others,
- trait_bounds: trait_refs,
- projection_bounds: Vec::new(), // not relevant to computing region bounds
- };
-
- let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
- ty::required_region_bounds(tcx, open_ty, predicates)
-}
-
pub struct PartitionedBounds<'a> {
pub builtin_bounds: ty::BuiltinBounds,
pub trait_bounds: Vec<&'a ast::PolyTraitRef>,
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 532277d..c4ee7e7 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use middle::free_region::FreeRegionMap;
use middle::infer;
use middle::traits;
use middle::ty::{self};
@@ -354,9 +355,19 @@
Ok(_) => {}
}
- // Finally, resolve all regions. This catches wily misuses of lifetime
- // parameters.
- infcx.resolve_regions_and_report_errors(impl_m_body_id);
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters. We have to build up a plausible lifetime
+ // environment based on what we find in the trait. We could also
+ // include the obligations derived from the method argument types,
+ // but I don't think it's necessary -- after all, those are still
+ // in effect when type-checking the body, and all the
+ // where-clauses in the header etc should be implied by the trait
+ // anyway, so it shouldn't be needed there either. Anyway, we can
+ // always add more relations later (it's backwards compat).
+ let mut free_regions = FreeRegionMap::new();
+ free_regions.relate_free_regions_from_predicates(tcx, &trait_param_env.caller_bounds);
+
+ infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 348846b..e87deba 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -132,7 +132,6 @@
pub mod _match;
pub mod vtable;
pub mod writeback;
-pub mod implicator;
pub mod regionck;
pub mod coercion;
pub mod demand;
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 6dfc1e0..2e8c573 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -85,8 +85,9 @@
use astconv::AstConv;
use check::dropck;
use check::FnCtxt;
-use check::implicator;
use check::vtable;
+use middle::free_region::FreeRegionMap;
+use middle::implicator;
use middle::mem_categorization as mc;
use middle::region::CodeExtent;
use middle::subst::Substs;
@@ -124,6 +125,8 @@
pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) {
let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id));
+ let tcx = fcx.tcx();
+ rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds);
rcx.visit_region_obligations(item.id);
rcx.resolve_regions_and_report_errors();
}
@@ -135,12 +138,21 @@
blk: &ast::Block) {
debug!("regionck_fn(id={})", fn_id);
let mut rcx = Rcx::new(fcx, RepeatingScope(blk.id), blk.id, Subject(fn_id));
+
if fcx.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_fn_body(fn_id, decl, blk, fn_span);
}
+ let tcx = fcx.tcx();
+ rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds);
+
rcx.resolve_regions_and_report_errors();
+
+ // For the top-level fn, store the free-region-map. We don't store
+ // any map for closures; they just share the same map as the
+ // function that created them.
+ fcx.tcx().store_free_region_map(fn_id, rcx.free_region_map);
}
/// Checks that the types in `component_tys` are well-formed. This will add constraints into the
@@ -167,6 +179,8 @@
region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>,
+ free_region_map: FreeRegionMap,
+
// id of innermost fn body id
body_id: ast::NodeId,
@@ -191,7 +205,8 @@
repeating_scope: initial_repeating_scope,
body_id: initial_body_id,
subject: subject,
- region_bound_pairs: Vec::new()
+ region_bound_pairs: Vec::new(),
+ free_region_map: FreeRegionMap::new(),
}
}
@@ -277,13 +292,16 @@
}
};
- let len = self.region_bound_pairs.len();
+ let old_region_bounds_pairs_len = self.region_bound_pairs.len();
+
let old_body_id = self.set_body_id(body.id);
self.relate_free_regions(&fn_sig[..], body.id, span);
link_fn_args(self, CodeExtent::from_node_id(body.id), &fn_decl.inputs[..]);
self.visit_block(body);
self.visit_region_obligations(body.id);
- self.region_bound_pairs.truncate(len);
+
+ self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
+
self.set_body_id(old_body_id);
}
@@ -340,16 +358,18 @@
let body_scope = ty::ReScope(body_scope);
let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id,
ty, body_scope, span);
+
+ // Record any relations between free regions that we observe into the free-region-map.
+ self.free_region_map.relate_free_regions_from_implications(tcx, &implications);
+
+ // But also record other relationships, such as `T:'x`,
+ // that don't go into the free-region-map but which we use
+ // here.
for implication in implications {
debug!("implication: {}", implication.repr(tcx));
match implication {
implicator::Implication::RegionSubRegion(_,
ty::ReFree(free_a),
- ty::ReFree(free_b)) => {
- tcx.region_maps.relate_free_regions(free_a, free_b);
- }
- implicator::Implication::RegionSubRegion(_,
- ty::ReFree(free_a),
ty::ReInfer(ty::ReVar(vid_b))) => {
self.fcx.inh.infcx.add_given(free_a, vid_b);
}
@@ -388,7 +408,8 @@
}
};
- self.fcx.infcx().resolve_regions_and_report_errors(subject_node_id);
+ self.fcx.infcx().resolve_regions_and_report_errors(&self.free_region_map,
+ subject_node_id);
}
}
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 5ed9370..23959d5 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -68,6 +68,7 @@
use middle::def;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
+use middle::free_region::FreeRegionMap;
use middle::region;
use middle::resolve_lifetime;
use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
@@ -2158,7 +2159,16 @@
format!("mismatched self type: expected `{}`",
ppaux::ty_to_string(tcx, required_type))
}));
- infcx.resolve_regions_and_report_errors(body_id);
+
+ // We could conceviably add more free-reion relations here,
+ // but since this code is just concerned with checking that
+ // the `&Self` types etc match up, it's not really necessary.
+ // It would just allow people to be more approximate in some
+ // cases. In any case, we can do it later as we feel the need;
+ // I'd like this function to go away eventually.
+ let free_regions = FreeRegionMap::new();
+
+ infcx.resolve_regions_and_report_errors(&free_regions, body_id);
}
fn liberate_early_bound_regions<'tcx,T>(
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 3f3f820..1993f03 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1460,7 +1460,7 @@
try!(write!(fmt, "<span class='out-of-band'>"));
try!(write!(fmt,
r##"<span id='render-detail'>
- <a id="collapse-all" href="#">[-]</a> <a id="expand-all" href="#">[+]</a>
+ <a id="toggle-all-docs" href="#" title="collapse all docs">[-]</a>
</span>"##));
// Write `src` tag
@@ -1473,8 +1473,8 @@
match self.href(self.cx) {
Some(l) => {
try!(write!(fmt, "<a id='src-{}' class='srclink' \
- href='{}'>[src]</a>",
- self.item.def_id.node, l));
+ href='{}' title='{}'>[src]</a>",
+ self.item.def_id.node, l, "goto source code"));
}
None => {}
}
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 0379c04..56cea50 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -806,23 +806,31 @@
window.location = $('.srclink').attr('href');
}
- $("#expand-all").on("click", function() {
- $(".docblock").show();
- $(".toggle-label").hide();
- $(".toggle-wrapper").removeClass("collapsed");
- $(".collapse-toggle").children(".inner").html("-");
- });
-
- $("#collapse-all").on("click", function() {
- $(".docblock").hide();
- $(".toggle-label").show();
- $(".toggle-wrapper").addClass("collapsed");
- $(".collapse-toggle").children(".inner").html("+");
+ $("#toggle-all-docs").on("click", function() {
+ var toggle = $("#toggle-all-docs");
+ if (toggle.html() == "[-]") {
+ toggle.html("[+]");
+ toggle.attr("title", "expand all docs");
+ $(".docblock").hide();
+ $(".toggle-label").show();
+ $(".toggle-wrapper").addClass("collapsed");
+ $(".collapse-toggle").children(".inner").html("+");
+ } else {
+ toggle.html("[-]");
+ toggle.attr("title", "collapse all docs");
+ $(".docblock").show();
+ $(".toggle-label").hide();
+ $(".toggle-wrapper").removeClass("collapsed");
+ $(".collapse-toggle").children(".inner").html("-");
+ }
});
$(document).on("click", ".collapse-toggle", function() {
var toggle = $(this);
var relatedDoc = toggle.parent().next();
+ if (relatedDoc.is(".stability")) {
+ relatedDoc = relatedDoc.next();
+ }
if (relatedDoc.is(".docblock")) {
if (relatedDoc.is(":visible")) {
relatedDoc.slideUp({duration:'fast', easing:'linear'});
@@ -843,9 +851,10 @@
.html("[<span class='inner'>-</span>]");
$(".method").each(function() {
- if ($(this).next().is(".docblock")) {
- $(this).children().first().after(toggle.clone());
- }
+ if ($(this).next().is(".docblock") ||
+ ($(this).next().is(".stability") && $(this).next().next().is(".docblock"))) {
+ $(this).children().first().after(toggle.clone());
+ }
});
var mainToggle =
diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs
index 8ca462f..d0f990ea 100644
--- a/src/libstd/dynamic_lib.rs
+++ b/src/libstd/dynamic_lib.rs
@@ -40,14 +40,6 @@
}
impl DynamicLibrary {
- // FIXME (#12938): Until DST lands, we cannot decompose &str into
- // & and str, so we cannot usefully take ToCStr arguments by
- // reference (without forcing an additional & around &str). So we
- // are instead temporarily adding an instance for &Path, so that
- // we can take ToCStr as owned. When DST lands, the &Path instance
- // should be removed, and arguments bound by ToCStr should be
- // passed by reference. (Here: in the `open` method.)
-
/// Lazily open a dynamic library. When passed None it gives a
/// handle to the calling process
pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index cd6af77..42fad70 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -95,6 +95,8 @@
///
/// This handle implements the `Read` trait, but beware that concurrent reads
/// of `Stdin` must be executed with care.
+///
+/// Created by the function `io::stdin()`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdin {
inner: Arc<Mutex<BufReader<StdinRaw>>>,
@@ -206,6 +208,8 @@
/// Each handle shares a global buffer of data to be written to the standard
/// output stream. Access is also synchronized via a lock and explicit control
/// over locking is available via the `lock` method.
+///
+/// Created by the function `io::stdout()`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdout {
// FIXME: this should be LineWriter or BufWriter depending on the state of
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index 422439f..b3cc133 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -306,6 +306,14 @@
rx: &'a Receiver<T>
}
+/// An owning iterator over messages on a receiver, this iterator will block
+/// whenever `next` is called, waiting for a new message, and `None` will be
+/// returned when the corresponding channel has hung up.
+#[stable(feature = "receiver_into_iter", since = "1.1.0")]
+pub struct IntoIter<T> {
+ rx: Receiver<T>
+}
+
/// The sending-half of Rust's asynchronous channel type. This half can only be
/// owned by one task, but it can be cloned to send to other tasks.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -899,6 +907,29 @@
fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
}
+#[stable(feature = "receiver_into_iter", since = "1.1.0")]
+impl<'a, T> IntoIterator for &'a Receiver<T> {
+ type Item = T;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> { self.iter() }
+}
+
+impl<T> Iterator for IntoIter<T> {
+ type Item = T;
+ fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
+}
+
+#[stable(feature = "receiver_into_iter", since = "1.1.0")]
+impl <T> IntoIterator for Receiver<T> {
+ type Item = T;
+ type IntoIter = IntoIter<T>;
+
+ fn into_iter(self) -> IntoIter<T> {
+ IntoIter { rx: self }
+ }
+}
+
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Receiver<T> {
@@ -1508,6 +1539,32 @@
}
#[test]
+ fn test_recv_into_iter_owned() {
+ let mut iter = {
+ let (tx, rx) = channel::<i32>();
+ tx.send(1).unwrap();
+ tx.send(2).unwrap();
+
+ rx.into_iter()
+ };
+ assert_eq!(iter.next().unwrap(), 1);
+ assert_eq!(iter.next().unwrap(), 2);
+ assert_eq!(iter.next().is_none(), true);
+ }
+
+ #[test]
+ fn test_recv_into_iter_borrowed() {
+ let (tx, rx) = channel::<i32>();
+ tx.send(1).unwrap();
+ tx.send(2).unwrap();
+ drop(tx);
+ let mut iter = (&rx).into_iter();
+ assert_eq!(iter.next().unwrap(), 1);
+ assert_eq!(iter.next().unwrap(), 2);
+ assert_eq!(iter.next().is_none(), true);
+ }
+
+ #[test]
fn try_recv_states() {
let (tx1, rx1) = channel::<i32>();
let (tx2, rx2) = channel::<()>();
diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs
index 7d42d65..2b2c31d 100644
--- a/src/libstd/sys/common/net2.rs
+++ b/src/libstd/sys/common/net2.rs
@@ -202,15 +202,19 @@
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
seconds as c_int)
}
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "linux"))]
fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
seconds as c_int)
}
+
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
- target_os = "dragonfly")))]
+ target_os = "dragonfly",
+ target_os = "linux")))]
fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> {
Ok(())
}
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index d0975c7..fa95f66 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -394,7 +394,7 @@
are reserved for internal compiler diagnostics");
} else if name.starts_with("derive_") {
self.gate_feature("custom_derive", attr.span,
- "attributes of the form `#[derive_*]` are reserved
+ "attributes of the form `#[derive_*]` are reserved \
for the compiler");
} else {
self.gate_feature("custom_attribute", attr.span,
@@ -620,7 +620,7 @@
pattern.span,
"multiple-element slice matches anywhere \
but at the end of a slice (e.g. \
- `[0, ..xs, 0]` are experimental")
+ `[0, ..xs, 0]`) are experimental")
}
ast::PatVec(..) => {
self.gate_feature("slice_patterns",
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index dc577f6..68006a8 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1151,8 +1151,8 @@
&token::CloseDelim(token::Brace),
seq_sep_none(),
|p| {
- let lo = p.span.lo;
let mut attrs = p.parse_outer_attributes();
+ let lo = p.span.lo;
let (name, node) = if try!(p.eat_keyword(keywords::Type)) {
let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
@@ -3409,8 +3409,8 @@
}
}
- let lo = self.span.lo;
let attrs = self.parse_outer_attributes();
+ let lo = self.span.lo;
Ok(Some(if self.check_keyword(keywords::Let) {
check_expected_item(self, &attrs);
@@ -4304,8 +4304,8 @@
/// Parse an impl item.
pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
- let lo = self.span.lo;
let mut attrs = self.parse_outer_attributes();
+ let lo = self.span.lo;
let vis = try!(self.parse_visibility());
let (name, node) = if try!(self.eat_keyword(keywords::Type)) {
let name = try!(self.parse_ident());
@@ -5380,9 +5380,8 @@
/// Parse a foreign item.
fn parse_foreign_item(&mut self) -> PResult<Option<P<ForeignItem>>> {
- let lo = self.span.lo;
-
let attrs = self.parse_outer_attributes();
+ let lo = self.span.lo;
let visibility = try!(self.parse_visibility());
if self.check_keyword(keywords::Static) {
diff --git a/src/rustbook/javascript.rs b/src/rustbook/javascript.rs
index d548359..26303d1 100644
--- a/src/rustbook/javascript.rs
+++ b/src/rustbook/javascript.rs
@@ -52,7 +52,7 @@
}
for (var i = 0; i < toc.length; i++) {
- if (toc[i].attributes['href'].value === href) {
+ if (toc[i].attributes['href'].value.split('/').pop() === href) {
var nav = document.createElement('p');
if (i > 0) {
var prevNode = toc[i-1].cloneNode(true);
diff --git a/src/test/compile-fail-fulldeps/macro-crate-rlib.rs b/src/test/compile-fail-fulldeps/macro-crate-rlib.rs
index 7a36299..396b1c1 100644
--- a/src/test/compile-fail-fulldeps/macro-crate-rlib.rs
+++ b/src/test/compile-fail-fulldeps/macro-crate-rlib.rs
@@ -11,7 +11,6 @@
// aux-build:rlib_crate_test.rs
// ignore-stage1
// ignore-tidy-linelength
-// ignore-android
// ignore-cross-compile gives a different error message
#![feature(plugin)]
diff --git a/src/test/compile-fail/gated-box-patterns.rs b/src/test/compile-fail/feature-gate-negate-unsigned.rs
similarity index 66%
copy from src/test/compile-fail/gated-box-patterns.rs
copy to src/test/compile-fail/feature-gate-negate-unsigned.rs
index d82d0de..7dc654f 100644
--- a/src/test/compile-fail/gated-box-patterns.rs
+++ b/src/test/compile-fail/feature-gate-negate-unsigned.rs
@@ -8,14 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that patterns including the box syntax are gated by `box_patterns` feature gate.
+// Test that negating unsigned integers is gated by `negate_unsigned` feature
+// gate
-fn main() {
- let x = Box::new(1);
+const MAX: usize = -1;
+//~^ ERROR unary negation of unsigned integers may be removed in the future
- match x {
- box 1 => (),
- //~^ box pattern syntax is experimental
- _ => ()
- };
-}
+fn main() {}
diff --git a/src/test/compile-fail/gated-box-patterns.rs b/src/test/compile-fail/feature-gate-on-unimplemented.rs
similarity index 63%
copy from src/test/compile-fail/gated-box-patterns.rs
copy to src/test/compile-fail/feature-gate-on-unimplemented.rs
index d82d0de..5d32bba 100644
--- a/src/test/compile-fail/gated-box-patterns.rs
+++ b/src/test/compile-fail/feature-gate-on-unimplemented.rs
@@ -8,14 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that patterns including the box syntax are gated by `box_patterns` feature gate.
+// Test that `#[rustc_on_unimplemented]` is gated by `on_unimplemented` feature
+// gate.
-fn main() {
- let x = Box::new(1);
+#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
+//~^ ERROR the `#[rustc_on_unimplemented]` attribute is an experimental feature
+trait Foo<Bar>
+{}
- match x {
- box 1 => (),
- //~^ box pattern syntax is experimental
- _ => ()
- };
-}
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-optin-builtin-traits.rs b/src/test/compile-fail/feature-gate-optin-builtin-traits.rs
new file mode 100644
index 0000000..59d7473
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-optin-builtin-traits.rs
@@ -0,0 +1,26 @@
+// 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.
+
+// Test that default and negative trait implementations are gated by
+// `optin_builtin_traits` feature gate
+
+struct DummyStruct;
+
+trait DummyTrait {
+ fn dummy(&self) {}
+}
+
+impl DummyTrait for .. {}
+//~^ ERROR default trait implementations are experimental and possibly buggy
+
+impl !DummyTrait for DummyStruct {}
+//~^ ERROR negative trait bounds are not yet fully implemented; use marker types for now
+
+fn main() {}
diff --git a/src/test/compile-fail/gated-box-patterns.rs b/src/test/compile-fail/feature-gate-plugin.rs
similarity index 66%
copy from src/test/compile-fail/gated-box-patterns.rs
copy to src/test/compile-fail/feature-gate-plugin.rs
index d82d0de..3b5d762 100644
--- a/src/test/compile-fail/gated-box-patterns.rs
+++ b/src/test/compile-fail/feature-gate-plugin.rs
@@ -8,14 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that patterns including the box syntax are gated by `box_patterns` feature gate.
+// Test that `#![plugin(...)]` attribute is gated by `plugin` feature gate
-fn main() {
- let x = Box::new(1);
+#![plugin(foo)]
+//~^ ERROR compiler plugins are experimental and possibly buggy
- match x {
- box 1 => (),
- //~^ box pattern syntax is experimental
- _ => ()
- };
-}
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-rustc-attrs.rs b/src/test/compile-fail/feature-gate-rustc-attrs.rs
new file mode 100644
index 0000000..dab44b6
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-rustc-attrs.rs
@@ -0,0 +1,21 @@
+// 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.
+
+// ignore-tidy-linelength
+
+// Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate.
+
+#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is an experimental feature
+#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is an experimental feature
+#[rustc_move_fragments] //~ ERROR the `#[rustc_move_fragments]` attribute is an experimental feature
+#[rustc_foo]
+//~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-rustc-diagnostic-macros.rs b/src/test/compile-fail/feature-gate-rustc-diagnostic-macros.rs
new file mode 100644
index 0000000..8286d83
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-rustc-diagnostic-macros.rs
@@ -0,0 +1,23 @@
+// 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.
+
+// Test that diagnostic macros are gated by `rustc_diagnostic_macros` feature
+// gate
+
+__register_diagnostic!(E0001);
+//~^ ERROR macro undefined: '__register_diagnostic!'
+
+fn main() {
+ __diagnostic_used!(E0001);
+ //~^ ERROR macro undefined: '__diagnostic_used!'
+}
+
+__build_diagnostic_array!(DIAGNOSTICS);
+//~^ ERROR macro undefined: '__build_diagnostic_array!'
diff --git a/src/test/compile-fail/gated-box-patterns.rs b/src/test/compile-fail/feature-gate-slice-patterns.rs
similarity index 70%
rename from src/test/compile-fail/gated-box-patterns.rs
rename to src/test/compile-fail/feature-gate-slice-patterns.rs
index d82d0de..625cb2d 100644
--- a/src/test/compile-fail/gated-box-patterns.rs
+++ b/src/test/compile-fail/feature-gate-slice-patterns.rs
@@ -8,14 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that patterns including the box syntax are gated by `box_patterns` feature gate.
+// Test that slice pattern syntax is gated by `slice_patterns` feature gate
fn main() {
- let x = Box::new(1);
-
+ let x = [1, 2, 3, 4, 5];
match x {
- box 1 => (),
- //~^ box pattern syntax is experimental
- _ => ()
- };
+ [1, 2, xs..] => {} //~ ERROR slice pattern syntax is experimental
+ }
}
diff --git a/src/test/compile-fail/gated-simd-ffi.rs b/src/test/compile-fail/gated-simd-ffi.rs
deleted file mode 100644
index 883e1be..0000000
--- a/src/test/compile-fail/gated-simd-ffi.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-
-// Test that the use of smid types in the ffi is gated by `smid_ffi` feature gate.
-
-#![feature(simd)]
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-#[simd]
-pub struct f32x4(f32, f32, f32, f32);
-
-#[allow(dead_code)]
-extern {
- fn foo(x: f32x4);
- //~^ ERROR use of SIMD type `f32x4` in FFI is highly experimental and may result in invalid code
- //~| HELP add #![feature(simd_ffi)] to the crate attributes to enable
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/region-bound-extra-bound-in-impl.rs b/src/test/compile-fail/region-bound-extra-bound-in-impl.rs
new file mode 100644
index 0000000..5bcc6be
--- /dev/null
+++ b/src/test/compile-fail/region-bound-extra-bound-in-impl.rs
@@ -0,0 +1,25 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #22779. An extra where clause was
+// permitted on the impl that is not present on the trait.
+
+trait Tr<'a, T> {
+ fn renew<'b: 'a>(self) -> &'b mut [T];
+}
+
+impl<'a, T> Tr<'a, T> for &'a mut [T] {
+ fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+ //~^ ERROR lifetime bound not satisfied
+ &mut self[..]
+ }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/region-bound-extra-bound-in-inherent-impl.rs b/src/test/compile-fail/region-bound-extra-bound-in-inherent-impl.rs
new file mode 100644
index 0000000..c1df057
--- /dev/null
+++ b/src/test/compile-fail/region-bound-extra-bound-in-inherent-impl.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test related to #22779. In this case, the impl is an inherent impl,
+// so it doesn't have to match any trait, so no error results.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+struct MySlice<'a, T:'a>(&'a mut [T]);
+
+impl<'a, T> MySlice<'a, T> {
+ fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+ &mut self.0[..]
+ }
+}
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
diff --git a/src/test/compile-fail/region-bound-same-bounds-in-trait-and-impl.rs b/src/test/compile-fail/region-bound-same-bounds-in-trait-and-impl.rs
new file mode 100644
index 0000000..3115e5a
--- /dev/null
+++ b/src/test/compile-fail/region-bound-same-bounds-in-trait-and-impl.rs
@@ -0,0 +1,27 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test related to #22779, but where the `'a:'b` relation
+// appears in the trait too. No error here.
+
+#![feature(rustc_attrs)]
+
+trait Tr<'a, T> {
+ fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b;
+}
+
+impl<'a, T> Tr<'a, T> for &'a mut [T] {
+ fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+ &mut self[..]
+ }
+}
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
index 278ccd3..abffd33 100644
--- a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
+++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
@@ -50,7 +50,9 @@
fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
}
- fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {}
+ fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+ //~^ ERROR lifetime bound not satisfied
+ }
}
fn main() { }
diff --git a/src/test/run-make/simd-ffi/Makefile b/src/test/run-make/simd-ffi/Makefile
index 68a6a5f..dc0fcec 100644
--- a/src/test/run-make/simd-ffi/Makefile
+++ b/src/test/run-make/simd-ffi/Makefile
@@ -27,7 +27,8 @@
# on some platforms, but LLVM just prints a warning so that's fine for
# now.
$(1): simd.rs
- $$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs -C target-feature='+neon,+sse2'
+ $$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs \
+ -C target-feature='+neon,+sse2' -C extra-filename=-$(1)
endef
$(foreach targetxxx,$(TARGETS),$(eval $(call MK_TARGETS,$(targetxxx))))
diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs
index 4bacde0..1cf36da 100644
--- a/src/test/run-pass-fulldeps/compiler-calls.rs
+++ b/src/test/run-pass-fulldeps/compiler-calls.rs
@@ -10,7 +10,7 @@
// Test that the CompilerCalls interface to the compiler works.
-// ignore-android
+// ignore-cross-compile
#![feature(rustc_private, path)]
#![feature(core)]
diff --git a/src/test/run-pass-fulldeps/create-dir-all-bare.rs b/src/test/run-pass-fulldeps/create-dir-all-bare.rs
index e4fb7c1..e22736d 100644
--- a/src/test/run-pass-fulldeps/create-dir-all-bare.rs
+++ b/src/test/run-pass-fulldeps/create-dir-all-bare.rs
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-android
+// ignore-cross-compile
#![feature(rustc_private)]
diff --git a/src/test/run-pass-fulldeps/issue-15149.rs b/src/test/run-pass-fulldeps/issue-15149.rs
index 7e64bbd..ea7e959 100644
--- a/src/test/run-pass-fulldeps/issue-15149.rs
+++ b/src/test/run-pass-fulldeps/issue-15149.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// no-prefer-dynamic
-// ignore-android
+// ignore-cross-compile
#![feature(rustc_private)]
diff --git a/src/test/run-pass-fulldeps/issue-16992.rs b/src/test/run-pass-fulldeps/issue-16992.rs
index 40947b2..a439e2b 100644
--- a/src/test/run-pass-fulldeps/issue-16992.rs
+++ b/src/test/run-pass-fulldeps/issue-16992.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// ignore-pretty
-// ignore-android
+// ignore-cross-compile
#![feature(quote, rustc_private)]
diff --git a/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs b/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs
index e1ef32b..829fdb1 100644
--- a/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs
+++ b/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-android
+// ignore-cross-compile
// ignore-pretty: does not work well with `--test`
#![feature(quote, rustc_private)]
diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs
index 7e11b9d..710b3b0 100644
--- a/src/test/run-pass-fulldeps/qquote.rs
+++ b/src/test/run-pass-fulldeps/qquote.rs
@@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-cross-compile
// ignore-pretty
// ignore-test
diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs
index 99e0333..64061eb 100644
--- a/src/test/run-pass-fulldeps/quote-tokens.rs
+++ b/src/test/run-pass-fulldeps/quote-tokens.rs
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-android
+// ignore-cross-compile
// ignore-pretty: does not work well with `--test`
#![feature(quote, rustc_private)]
diff --git a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs
index 928368f..e9de95b 100644
--- a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs
+++ b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-android
+// ignore-cross-compile
// ignore-pretty: does not work well with `--test`
#![feature(quote, rustc_private)]
diff --git a/src/test/run-pass-fulldeps/rename-directory.rs b/src/test/run-pass-fulldeps/rename-directory.rs
index a0644e5..2bec41f 100644
--- a/src/test/run-pass-fulldeps/rename-directory.rs
+++ b/src/test/run-pass-fulldeps/rename-directory.rs
@@ -11,7 +11,7 @@
// This test can't be a unit test in std,
// because it needs TempDir, which is in extra
-// ignore-android
+// ignore-cross-compile
#![feature(rustc_private, path_ext)]
diff --git a/src/test/rustdoc/default-impl.rs b/src/test/rustdoc/default-impl.rs
index 92b2431..6153a39 100644
--- a/src/test/rustdoc/default-impl.rs
+++ b/src/test/rustdoc/default-impl.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:rustdoc-default-impl.rs
-// ignore-android
+// ignore-cross-compile
extern crate rustdoc_default_impl as foo;
diff --git a/src/test/rustdoc/extern-default-method.rs b/src/test/rustdoc/extern-default-method.rs
index 9178c1b..10d2884 100644
--- a/src/test/rustdoc/extern-default-method.rs
+++ b/src/test/rustdoc/extern-default-method.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:rustdoc-extern-default-method.rs
-// ignore-android
+// ignore-cross-compile
extern crate rustdoc_extern_default_method as ext;
diff --git a/src/test/rustdoc/extern-method.rs b/src/test/rustdoc/extern-method.rs
index 5e30e6c..c422871 100644
--- a/src/test/rustdoc/extern-method.rs
+++ b/src/test/rustdoc/extern-method.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:rustdoc-extern-method.rs
-// ignore-android
+// ignore-cross-compile
#![feature(unboxed_closures)]
diff --git a/src/test/rustdoc/ffi.rs b/src/test/rustdoc/ffi.rs
index 717c64b..3997dcd 100644
--- a/src/test/rustdoc/ffi.rs
+++ b/src/test/rustdoc/ffi.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:rustdoc-ffi.rs
-// ignore-android
+// ignore-cross-compile
extern crate rustdoc_ffi as lib;
diff --git a/src/test/rustdoc/inline-default-methods.rs b/src/test/rustdoc/inline-default-methods.rs
index a613736..055af01 100644
--- a/src/test/rustdoc/inline-default-methods.rs
+++ b/src/test/rustdoc/inline-default-methods.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:inline-default-methods.rs
-// ignore-android
+// ignore-cross-compile
extern crate inline_default_methods;
diff --git a/src/test/rustdoc/issue-13698.rs b/src/test/rustdoc/issue-13698.rs
index 5c31c29..cf9b30a 100644
--- a/src/test/rustdoc/issue-13698.rs
+++ b/src/test/rustdoc/issue-13698.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-13698.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_13698;
diff --git a/src/test/rustdoc/issue-15318-2.rs b/src/test/rustdoc/issue-15318-2.rs
index 32898d6..7999af4 100644
--- a/src/test/rustdoc/issue-15318-2.rs
+++ b/src/test/rustdoc/issue-15318-2.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-15318.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_15318;
diff --git a/src/test/rustdoc/issue-15318.rs b/src/test/rustdoc/issue-15318.rs
index 3bcc8f4..fd46b6e 100644
--- a/src/test/rustdoc/issue-15318.rs
+++ b/src/test/rustdoc/issue-15318.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-15318.rs
-// ignore-android
+// ignore-cross-compile
#![feature(no_std)]
#![no_std]
diff --git a/src/test/rustdoc/issue-17476.rs b/src/test/rustdoc/issue-17476.rs
index 8d31a1c..dcd3f2a 100644
--- a/src/test/rustdoc/issue-17476.rs
+++ b/src/test/rustdoc/issue-17476.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-17476.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_17476;
diff --git a/src/test/rustdoc/issue-19190-3.rs b/src/test/rustdoc/issue-19190-3.rs
index c315ea2..eec5c02 100644
--- a/src/test/rustdoc/issue-19190-3.rs
+++ b/src/test/rustdoc/issue-19190-3.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-19190-3.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_19190_3;
diff --git a/src/test/rustdoc/issue-20646.rs b/src/test/rustdoc/issue-20646.rs
index 77abe35..87c40d1 100644
--- a/src/test/rustdoc/issue-20646.rs
+++ b/src/test/rustdoc/issue-20646.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-20646.rs
-// ignore-android
+// ignore-cross-compile
#![feature(associated_types)]
diff --git a/src/test/rustdoc/issue-20727-2.rs b/src/test/rustdoc/issue-20727-2.rs
index 03181be..1f29a9c 100644
--- a/src/test/rustdoc/issue-20727-2.rs
+++ b/src/test/rustdoc/issue-20727-2.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-20727.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_20727;
diff --git a/src/test/rustdoc/issue-20727-3.rs b/src/test/rustdoc/issue-20727-3.rs
index 9d05ce9..e4a9dd7 100644
--- a/src/test/rustdoc/issue-20727-3.rs
+++ b/src/test/rustdoc/issue-20727-3.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-20727.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_20727;
diff --git a/src/test/rustdoc/issue-20727-4.rs b/src/test/rustdoc/issue-20727-4.rs
index 39db387..9ebd1c4 100644
--- a/src/test/rustdoc/issue-20727-4.rs
+++ b/src/test/rustdoc/issue-20727-4.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-20727.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_20727;
diff --git a/src/test/rustdoc/issue-20727.rs b/src/test/rustdoc/issue-20727.rs
index 3205f5b..e38f06c 100644
--- a/src/test/rustdoc/issue-20727.rs
+++ b/src/test/rustdoc/issue-20727.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-20727.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_20727;
diff --git a/src/test/rustdoc/issue-21092.rs b/src/test/rustdoc/issue-21092.rs
index 38983ae..745c6e2 100644
--- a/src/test/rustdoc/issue-21092.rs
+++ b/src/test/rustdoc/issue-21092.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-21092.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_21092;
diff --git a/src/test/rustdoc/issue-21801.rs b/src/test/rustdoc/issue-21801.rs
index a4392b8..4e2c778 100644
--- a/src/test/rustdoc/issue-21801.rs
+++ b/src/test/rustdoc/issue-21801.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-21801.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_21801;
diff --git a/src/test/rustdoc/issue-22025.rs b/src/test/rustdoc/issue-22025.rs
index d2eb4fb..c0e4e67 100644
--- a/src/test/rustdoc/issue-22025.rs
+++ b/src/test/rustdoc/issue-22025.rs
@@ -9,7 +9,7 @@
// except according to those terms.
// aux-build:issue-22025.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_22025;
diff --git a/src/test/rustdoc/issue-23207.rs b/src/test/rustdoc/issue-23207.rs
index 7220467..4931d15 100644
--- a/src/test/rustdoc/issue-23207.rs
+++ b/src/test/rustdoc/issue-23207.rs
@@ -10,7 +10,7 @@
// aux-build:issue-23207-1.rs
// aux-build:issue-23207-2.rs
-// ignore-android
+// ignore-cross-compile
extern crate issue_23207_2;