]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #44569 - est31:master, r=estebank
authorCorey Farwell <coreyf@rwell.org>
Fri, 15 Sep 2017 02:32:51 +0000 (22:32 -0400)
committerGitHub <noreply@github.com>
Fri, 15 Sep 2017 02:32:51 +0000 (22:32 -0400)
"avoid" is a better word here than "disable"

You don't "disable" the warning really, you just avoid it (as a conscious action).

91 files changed:
CONTRIBUTING.md
fn.rs [new file with mode: 0644]
src/Cargo.lock
src/bootstrap/native.rs
src/liballoc/btree/set.rs
src/liballoc/str.rs
src/liballoc/string.rs
src/liballoc/vec.rs
src/libcore/intrinsics.rs
src/libcore/mem.rs
src/libcore/str/mod.rs
src/liblibc
src/librustc/hir/lowering.rs
src/librustc/infer/error_reporting/different_lifetimes.rs
src/librustc/middle/lang_items.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc_data_structures/bitslice.rs
src/librustc_data_structures/indexed_set.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/test.rs
src/librustc_incremental/lib.rs
src/librustc_incremental/persist/fs.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/mod.rs
src/librustc_incremental/persist/save.rs
src/librustc_incremental/persist/work_product.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/dataflow/impls/mod.rs
src/librustc_mir/dataflow/impls/storage_liveness.rs [new file with mode: 0644]
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/transform/generator.rs
src/librustc_trans/back/write.rs
src/librustc_typeck/variance/terms.rs
src/librustdoc/core.rs
src/librustdoc/html/render.rs
src/librustdoc/test.rs
src/libstd/fs.rs
src/libstd/net/tcp.rs
src/libstd/net/udp.rs
src/libstd/os/mod.rs
src/libstd/os/raw.rs
src/libstd/sys/redox/thread.rs
src/libstd/sys/unix/args.rs
src/libstd/sys/unix/condvar.rs
src/libstd/sys/unix/env.rs
src/libstd/sys/unix/fd.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/l4re.rs [new file with mode: 0644]
src/libstd/sys/unix/mod.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/process/process_unix.rs
src/libstd/sys/unix/thread.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/thread.rs
src/libstd/sys_common/mod.rs
src/libstd/sys_common/net.rs
src/libstd/sys_common/thread.rs
src/libstd/sys_common/util.rs
src/libstd/thread/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax_pos/lib.rs
src/test/mir-opt/end_region_1.rs
src/test/mir-opt/end_region_2.rs
src/test/mir-opt/end_region_3.rs
src/test/mir-opt/end_region_4.rs
src/test/mir-opt/end_region_5.rs
src/test/mir-opt/end_region_6.rs
src/test/mir-opt/end_region_7.rs
src/test/mir-opt/end_region_8.rs
src/test/mir-opt/end_region_9.rs
src/test/mir-opt/end_region_cyclic.rs [new file with mode: 0644]
src/test/mir-opt/end_region_destruction_extents_1.rs [new file with mode: 0644]
src/test/mir-opt/validate_1.rs
src/test/mir-opt/validate_5.rs
src/test/run-make/issue-19371/foo.rs
src/test/run-pass/closure-returning-closure.rs [new file with mode: 0644]
src/test/run-pass/generator/match-bindings.rs [new file with mode: 0644]
src/test/rustdoc/const-fn.rs [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr [new file with mode: 0644]
src/tools/rustbook/Cargo.toml
src/tools/rustbook/src/main.rs

index 7441d51055ffb2bb83098675d380d102ff9a7fec..741ced8f0912d21157b9919522f9b767a30ba164 100644 (file)
@@ -400,30 +400,53 @@ labels to triage issues:
 
 * Magenta, **B**-prefixed labels identify bugs which are **blockers**.
 
+* Dark blue, **beta-** labels track changes which need to be backported into
+  the beta branches.
+
+* Light purple, **C**-prefixed labels represent the **category** of an issue.
+
 * Green, **E**-prefixed labels explain the level of **experience** necessary
   to fix the issue.
 
+* The dark blue **final-comment-period** label marks bugs that are using the
+  RFC signoff functionality of [rfcbot][rfcbot] and are currenty in the final
+  comment period.
+
 * Red, **I**-prefixed labels indicate the **importance** of the issue. The
   [I-nominated][inom] label indicates that an issue has been nominated for
   prioritizing at the next triage meeting.
 
+* The purple **metabug** label marks lists of bugs collected by other
+  categories.
+
+* Purple gray, **O**-prefixed labels are the **operating system** or platform
+  that this issue is specific to.
+
 * Orange, **P**-prefixed labels indicate a bug's **priority**. These labels
   are only assigned during triage meetings, and replace the [I-nominated][inom]
   label.
 
-* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
+* The gray **proposed-final-comment-period** label marks bugs that are using
+  the RFC signoff functionality of [rfcbot][rfcbot] and are currently awaiting
+  signoff of all team members in order to enter the final comment period.
 
-* Dark blue, **beta-** labels track changes which need to be backported into
-  the beta branches.
+* Pink, **regression**-prefixed labels track regressions from stable to the
+  release channels.
 
-* The purple **metabug** label marks lists of bugs collected by other
-  categories.
+* The light orange **relnotes** label marks issues that should be documented in
+  the release notes of the next release.
+
+* Gray, **S**-prefixed labels are used for tracking the **status** of pull
+  requests.
+
+* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
 
 If you're looking for somewhere to start, check out the [E-easy][eeasy] tag.
 
 [inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated
 [eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy
 [lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
+[rfcbot]: https://github.com/dikaiosune/rust-dashboard/blob/master/RFCBOT.md
 
 ## Out-of-tree Contributions
 
diff --git a/fn.rs b/fn.rs
new file mode 100644 (file)
index 0000000..186eda9
--- /dev/null
+++ b/fn.rs
@@ -0,0 +1,8 @@
+
+fn foo(x:  fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
+// Debruijn   1    1            1        1
+// Anon-Index 0    1            0        1
+//            ------
+//            debruijn indices are shifted by 1 in here
+  y.push(z); // index will be zero or one
+}
index 1bbe8ca7575f11b6b9110ec415b1dd504296cfda..79822675364cfd76ad912c0dd135cac285511a2b 100644 (file)
@@ -490,6 +490,14 @@ dependencies = [
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "error-chain"
 version = "0.11.0"
@@ -642,7 +650,7 @@ dependencies = [
 
 [[package]]
 name = "handlebars"
-version = "0.26.2"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -926,18 +934,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "mdbook"
-version = "0.0.22"
+version = "0.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "handlebars 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1398,7 +1410,7 @@ name = "rustbook"
 version = "0.1.0"
 dependencies = [
  "clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2463,6 +2475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
 "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
 "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
 "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
@@ -2478,7 +2491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum globset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "feeb1b6840809ef5efcf7a4a990bc4e1b7ee3df8cf9e2379a75aeb2ba42ac9c3"
 "checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4"
-"checksum handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fbba80e74e9591a5f6a4ffff6b7f9d645759a896e431cfbdc853e9184370294a"
+"checksum handlebars 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef7567daf271a32e60301e4821fcb5b51a5b535167115d1ce04f46c3f0a15f0b"
 "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
 "checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db"
 "checksum html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5298d63081a642508fce965740ddb03a386c5d81bf1fef0579a815cf49cb8c68"
@@ -2503,7 +2516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699"
 "checksum markup5ever 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff834ac7123c6a37826747e5ca09db41fd7a83126792021c2e636ad174bb77d3"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "22911d86cde6f80fa9f0fb2a68bbbde85d97af4fe0ce267141c83a4187d28700"
+"checksum mdbook 0.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "146eadfc6d141452a364c351f07bb19208d1401e931f40b8532f87bba3ecc40f"
 "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
 "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
 "checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726"
index 2cbae083fc464bd7610d825fcb72e3e5e41e8c95..a2c436627f6da0c360618ec4dc997d2dac04ad15 100644 (file)
@@ -389,7 +389,8 @@ fn run(self, builder: &Builder) {
         drop(fs::remove_dir_all(&dst));
         build.run(Command::new("tar").arg("xf").arg(&tarball).current_dir(&out));
 
-        let mut configure = Command::new(obj.join("Configure"));
+        let mut configure = Command::new("perl");
+        configure.arg(obj.join("Configure"));
         configure.arg(format!("--prefix={}", dst.display()));
         configure.arg("no-dso");
         configure.arg("no-ssl2");
index d32460da9392342e12834e28d1e5684956297b0a..7da6371cc19072dd94e001a317ebe107c6d4a46c 100644 (file)
@@ -1110,15 +1110,13 @@ impl<'a, T: Ord> Iterator for Union<'a, T> {
     type Item = &'a T;
 
     fn next(&mut self) -> Option<&'a T> {
-        loop {
-            match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
-                Less => return self.a.next(),
-                Equal => {
-                    self.b.next();
-                    return self.a.next();
-                }
-                Greater => return self.b.next(),
+        match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
+            Less => self.a.next(),
+            Equal => {
+                self.b.next();
+                self.a.next()
             }
+            Greater => self.b.next(),
         }
     }
 
index f0c63a2eb55d5cb99f58c2861f8e3e7b2f428a4f..62b5f13675c231c31012fa755749683a94255c59 100644 (file)
@@ -855,6 +855,19 @@ pub fn lines_any(&self) -> LinesAny {
     }
 
     /// Returns an iterator of `u16` over the string encoded as UTF-16.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// let text = "Zażółć gęślÄ… jaźń";
+    ///
+    /// let utf8_len = text.len();
+    /// let utf16_len = text.encode_utf16().count();
+    ///
+    /// assert!(utf16_len <= utf8_len);
+    /// ```
     #[stable(feature = "encode_utf16", since = "1.8.0")]
     pub fn encode_utf16(&self) -> EncodeUtf16 {
         EncodeUtf16 { encoder: Utf16Encoder::new(self[..].chars()) }
@@ -1783,6 +1796,17 @@ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
     }
 
     /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// let s = "this is a string";
+    /// let boxed_str = s.to_owned().into_boxed_str();
+    /// let boxed_bytes = boxed_str.into_boxed_bytes();
+    /// assert_eq!(*boxed_bytes, *s.as_bytes());
+    /// ```
     #[stable(feature = "str_box_extras", since = "1.20.0")]
     pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
         self.into()
@@ -2050,6 +2074,17 @@ pub fn repeat(&self, n: usize) -> String {
 
 /// Converts a boxed slice of bytes to a boxed string slice without checking
 /// that the string contains valid UTF-8.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// let smile_utf8 = Box::new([226, 152, 186]);
+/// let smile = unsafe { std::str::from_boxed_utf8_unchecked(smile_utf8) };
+///
+/// assert_eq!("☺", &*smile);
+/// ```
 #[stable(feature = "str_box_extras", since = "1.20.0")]
 pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
     mem::transmute(v)
index 1708f3e398756d493b22d8ec6c8810363c6ede06..8cecc59127eb1ece4cdccb1aa200e1c8ffe64df8 100644 (file)
@@ -759,7 +759,22 @@ pub fn as_str(&self) -> &str {
         self
     }
 
-    /// Extracts a string slice containing the entire string.
+    /// Converts a `String` into a mutable string slice.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::ascii::AsciiExt;
+    ///
+    /// let mut s = String::from("foobar");
+    /// let s_mut_str = s.as_mut_str();
+    ///
+    /// s_mut_str.make_ascii_uppercase();
+    ///
+    /// assert_eq!("FOOBAR", s_mut_str);
+    /// ```
     #[inline]
     #[stable(feature = "string_as_str", since = "1.7.0")]
     pub fn as_mut_str(&mut self) -> &mut str {
index 8141851b8c9af9cbd22567a94cc40309a55bccfd..45574bad9ac07eb93b2abeb5629e73445fd6bbac 100644 (file)
@@ -370,6 +370,7 @@ pub fn with_capacity(capacity: usize) -> Vec<T> {
     ///
     /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
     ///   (at least, it's highly likely to be incorrect if it wasn't).
+    /// * `ptr`'s `T` needs to have the same size and alignment as it was allocated with.
     /// * `length` needs to be less than or equal to `capacity`.
     /// * `capacity` needs to be the capacity that the pointer was allocated with.
     ///
@@ -1969,16 +1970,19 @@ pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<I::IntoIter>
     /// Using this method is equivalent to the following code:
     ///
     /// ```
-    /// # let some_predicate = |x: &mut i32| { *x == 2 };
-    /// # let mut vec = vec![1, 2, 3, 4, 5];
+    /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
+    /// # let mut vec = vec![1, 2, 3, 4, 5, 6];
     /// let mut i = 0;
     /// while i != vec.len() {
     ///     if some_predicate(&mut vec[i]) {
     ///         let val = vec.remove(i);
     ///         // your code here
+    ///     } else {
+    ///         i += 1;
     ///     }
-    ///     i += 1;
     /// }
+    ///
+    /// # assert_eq!(vec, vec![1, 4, 5]);
     /// ```
     ///
     /// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
index 607f6f3701799c3337f0bad75fe5878f17c34fd9..f7f1dd12d28b150be07d9bd7b58a45ef5bc6e078 100644 (file)
     /// // The no-copy, unsafe way, still using transmute, but not UB.
     /// // This is equivalent to the original, but safer, and reuses the
     /// // same Vec internals. Therefore the new inner type must have the
-    /// // exact same size, and the same or lesser alignment, as the old
-    /// // type. The same caveats exist for this method as transmute, for
+    /// // exact same size, and the same alignment, as the old type.
+    /// // The same caveats exist for this method as transmute, for
     /// // the original inner type (`&i32`) to the converted inner type
     /// // (`Option<&i32>`), so read the nomicon pages linked above.
     /// let v_from_raw = unsafe {
-    ///     Vec::from_raw_parts(v_orig.as_mut_ptr(),
+    ///     Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut Option<&i32>,
     ///                         v_orig.len(),
     ///                         v_orig.capacity())
     /// };
index af2f876a2f35906010bad6e63e94c1d8c4ceeca6..bae1f4dee14f35b05e3a79efeddd04e47d3196aa 100644 (file)
@@ -712,39 +712,39 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
 /// Opaque type representing the discriminant of an enum.
 ///
 /// See the `discriminant` function in this module for more information.
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 pub struct Discriminant<T>(u64, PhantomData<*const T>);
 
 // N.B. These trait implementations cannot be derived because we don't want any bounds on T.
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> Copy for Discriminant<T> {}
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> clone::Clone for Discriminant<T> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> cmp::PartialEq for Discriminant<T> {
     fn eq(&self, rhs: &Self) -> bool {
         self.0 == rhs.0
     }
 }
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> cmp::Eq for Discriminant<T> {}
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> hash::Hash for Discriminant<T> {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
         self.0.hash(state);
     }
 }
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> fmt::Debug for Discriminant<T> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         fmt.debug_tuple("Discriminant")
@@ -777,7 +777,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 /// assert!(mem::discriminant(&Foo::B(1))     == mem::discriminant(&Foo::B(2)));
 /// assert!(mem::discriminant(&Foo::B(3))     != mem::discriminant(&Foo::C(3)));
 /// ```
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 pub fn discriminant<T>(v: &T) -> Discriminant<T> {
     unsafe {
         Discriminant(intrinsics::discriminant_value(v), PhantomData)
index 62e84c9ebd0175f5278e644411e5950493fcfd72..d4fef45ae4e8f1f94cba2c903d4165b1b2076cb0 100644 (file)
@@ -302,6 +302,37 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
 }
 
 /// Converts a mutable slice of bytes to a mutable string slice.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // "Hello, Rust!" as a mutable vector
+/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33];
+///
+/// // As we know these bytes are valid, we can use `unwrap()`
+/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap();
+///
+/// assert_eq!("Hello, Rust!", outstr);
+/// ```
+///
+/// Incorrect bytes:
+///
+/// ```
+/// use std::str;
+///
+/// // Some invalid bytes in a mutable vector
+/// let mut invalid = vec![128, 223];
+///
+/// assert!(str::from_utf8_mut(&mut invalid).is_err());
+/// ```
+/// See the docs for [`Utf8Error`][error] for more details on the kinds of
+/// errors that can be returned.
+///
+/// [error]: struct.Utf8Error.html
 #[stable(feature = "str_mut_extras", since = "1.20.0")]
 pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
     run_utf8_validation(v)?;
@@ -382,6 +413,19 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
 /// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
 ///
 /// [fromutf8]: fn.from_utf8_unchecked.html
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// let mut heart = vec![240, 159, 146, 150];
+/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) };
+///
+/// assert_eq!("💖", heart);
+/// ```
 #[inline]
 #[stable(feature = "str_mut_extras", since = "1.20.0")]
 pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
index 04a5e75c99dc92afab490c38fcbbeac9b4bc8104..95848f9622deccc9cbadcd5d3a4faef01a90ead4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 04a5e75c99dc92afab490c38fcbbeac9b4bc8104
+Subproject commit 95848f9622deccc9cbadcd5d3a4faef01a90ead4
index bae419da26c58839e44bf087cf222ba563806c6f..113a5d0e5e96e28d72f7ffefcb3b6224c132126b 100644 (file)
@@ -40,6 +40,7 @@
 //! get confused if the spans from leaf AST nodes occur in multiple places
 //! in the HIR, especially for multiple identifiers.
 
+use dep_graph::DepGraph;
 use hir;
 use hir::map::{Definitions, DefKey};
 use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX};
@@ -122,13 +123,14 @@ pub trait Resolver {
 
 pub fn lower_crate(sess: &Session,
                    cstore: &CrateStore,
+                   dep_graph: &DepGraph,
                    krate: &Crate,
                    resolver: &mut Resolver)
                    -> hir::Crate {
     // We're constructing the HIR here; we don't care what we will
     // read, since we haven't even constructed the *input* to
     // incr. comp. yet.
-    let _ignore = sess.dep_graph.in_ignore();
+    let _ignore = dep_graph.in_ignore();
 
     LoweringContext {
         crate_root: std_inject::injected_crate_name(krate),
index 23f6d1a3fb0d4521a1094e9f95d53c3e25fdd546..051263dfb53ef30f5e8f5283c7550d25049b3f70 100644 (file)
@@ -173,6 +173,7 @@ fn find_component_for_bound_region(&self,
             hir_map: &self.tcx.hir,
             bound_region: *br,
             found_type: None,
+            depth: 1,
         };
         nested_visitor.visit_ty(arg);
         nested_visitor.found_type
@@ -195,6 +196,7 @@ struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     // The type where the anonymous lifetime appears
     // for e.g. Vec<`&u8`> and <`&u8`>
     found_type: Option<&'gcx hir::Ty>,
+    depth: u32,
 }
 
 impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
@@ -204,6 +206,21 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
 
     fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
         match arg.node {
+            hir::TyBareFn(_) => {
+                self.depth += 1;
+                intravisit::walk_ty(self, arg);
+                self.depth -= 1;
+                return;
+            }
+
+            hir::TyTraitObject(ref bounds, _) => {
+                for bound in bounds {
+                    self.depth += 1;
+                    self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
+                    self.depth -= 1;
+                }
+            }
+
             hir::TyRptr(ref lifetime, _) => {
                 // the lifetime of the TyRptr
                 let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id);
@@ -217,7 +234,7 @@ fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
                                debruijn_index.depth,
                                anon_index,
                                br_index);
-                        if debruijn_index.depth == 1 && anon_index == br_index {
+                        if debruijn_index.depth == self.depth && anon_index == br_index {
                             self.found_type = Some(arg);
                             return; // we can stop visiting now
                         }
@@ -246,7 +263,7 @@ fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
                         debug!("self.infcx.tcx.hir.local_def_id(id)={:?}",
                                self.infcx.tcx.hir.local_def_id(id));
                         debug!("def_id={:?}", def_id);
-                        if debruijn_index.depth == 1 &&
+                        if debruijn_index.depth == self.depth &&
                            self.infcx.tcx.hir.local_def_id(id) == def_id {
                             self.found_type = Some(arg);
                             return; // we can stop visiting now
index cb59d9870faacfd3042e0979c1af4b5258f38153..da9f9128cf4cef6b4bbe8b2be146f9b62f9e9244 100644 (file)
@@ -46,6 +46,14 @@ pub enum LangItem {
     }
 }
 
+impl LangItem {
+    fn name(self) -> &'static str {
+        match self {
+            $( $variant => $name, )*
+        }
+    }
+}
+
 pub struct LanguageItems {
     pub items: Vec<Option<DefId>>,
     pub missing: Vec<LangItem>,
@@ -65,42 +73,17 @@ pub fn items(&self) -> &[Option<DefId>] {
         &*self.items
     }
 
-    pub fn item_name(index: usize) -> &'static str {
-        let item: Option<LangItem> = LangItem::from_u32(index as u32);
-        match item {
-            $( Some($variant) => $name, )*
-            None => "???"
-        }
-    }
-
     pub fn require(&self, it: LangItem) -> Result<DefId, String> {
-        match self.items[it as usize] {
-            Some(id) => Ok(id),
-            None => {
-                Err(format!("requires `{}` lang_item",
-                            LanguageItems::item_name(it as usize)))
-            }
-        }
-    }
-
-    pub fn require_owned_box(&self) -> Result<DefId, String> {
-        self.require(OwnedBoxLangItem)
+        self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
     }
 
     pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
-        let def_id_kinds = [
-            (self.fn_trait(), ty::ClosureKind::Fn),
-            (self.fn_mut_trait(), ty::ClosureKind::FnMut),
-            (self.fn_once_trait(), ty::ClosureKind::FnOnce),
-            ];
-
-        for &(opt_def_id, kind) in &def_id_kinds {
-            if Some(id) == opt_def_id {
-                return Some(kind);
-            }
+        match Some(id) {
+            x if x == self.fn_trait() => Some(ty::ClosureKind::Fn),
+            x if x == self.fn_mut_trait() => Some(ty::ClosureKind::FnMut),
+            x if x == self.fn_once_trait() => Some(ty::ClosureKind::FnOnce),
+            _ => None
         }
-
-        None
     }
 
     $(
@@ -162,7 +145,7 @@ fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
         // Check for duplicates.
         match self.items.items[item_index] {
             Some(original_def_id) if original_def_id != item_def_id => {
-                let name = LanguageItems::item_name(item_index);
+                let name = LangItem::from_u32(item_index as u32).unwrap().name();
                 let mut err = match self.tcx.hir.span_if_local(item_def_id) {
                     Some(span) => struct_span_err!(
                         self.tcx.sess,
@@ -327,14 +310,6 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
 
     PhantomDataItem,                 "phantom_data",            phantom_data;
 
-    // Deprecated:
-    CovariantTypeItem,               "covariant_type",          covariant_type;
-    ContravariantTypeItem,           "contravariant_type",      contravariant_type;
-    InvariantTypeItem,               "invariant_type",          invariant_type;
-    CovariantLifetimeItem,           "covariant_lifetime",      covariant_lifetime;
-    ContravariantLifetimeItem,       "contravariant_lifetime",  contravariant_lifetime;
-    InvariantLifetimeItem,           "invariant_lifetime",      invariant_lifetime;
-
     NonZeroItem,                     "non_zero",                non_zero;
 
     DebugTraitLangItem,              "debug_trait",             debug_trait;
index 59f600f39077c33e53cdad551b39b5d5bc8b4afd..df2de17f1e4711409610e76c9a49a87217dfabbb 100644 (file)
@@ -1949,7 +1949,6 @@ pub fn stable_hash(sub_hashes: BTreeMap<&'static str, &DepTrackingHash>,
 
 #[cfg(test)]
 mod tests {
-    use dep_graph::DepGraph;
     use errors;
     use getopts;
     use lint;
@@ -1982,7 +1981,6 @@ fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
     // When the user supplies --test we should implicitly supply --cfg test
     #[test]
     fn test_switch_implies_cfg_test() {
-        let dep_graph = DepGraph::new(false);
         let matches =
             &match optgroups().parse(&["--test".to_string()]) {
               Ok(m) => m,
@@ -1990,7 +1988,7 @@ fn test_switch_implies_cfg_test() {
             };
         let registry = errors::registry::Registry::new(&[]);
         let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-        let sess = build_session(sessopts, &dep_graph, None, registry);
+        let sess = build_session(sessopts, None, registry);
         let cfg = build_configuration(&sess, cfg);
         assert!(cfg.contains(&(Symbol::intern("test"), None)));
     }
@@ -1999,7 +1997,6 @@ fn test_switch_implies_cfg_test() {
     // another --cfg test
     #[test]
     fn test_switch_implies_cfg_test_unless_cfg_test() {
-        let dep_graph = DepGraph::new(false);
         let matches =
             &match optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]) {
               Ok(m) => m,
@@ -2009,7 +2006,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
             };
         let registry = errors::registry::Registry::new(&[]);
         let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-        let sess = build_session(sessopts, &dep_graph, None, registry);
+        let sess = build_session(sessopts, None, registry);
         let cfg = build_configuration(&sess, cfg);
         let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
         assert!(test_items.next().is_some());
@@ -2018,14 +2015,13 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
 
     #[test]
     fn test_can_print_warnings() {
-        let dep_graph = DepGraph::new(false);
         {
             let matches = optgroups().parse(&[
                 "-Awarnings".to_string()
             ]).unwrap();
             let registry = errors::registry::Registry::new(&[]);
             let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, &dep_graph, None, registry);
+            let sess = build_session(sessopts, None, registry);
             assert!(!sess.diagnostic().can_emit_warnings);
         }
 
@@ -2036,7 +2032,7 @@ fn test_can_print_warnings() {
             ]).unwrap();
             let registry = errors::registry::Registry::new(&[]);
             let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, &dep_graph, None, registry);
+            let sess = build_session(sessopts, None, registry);
             assert!(sess.diagnostic().can_emit_warnings);
         }
 
@@ -2046,7 +2042,7 @@ fn test_can_print_warnings() {
             ]).unwrap();
             let registry = errors::registry::Registry::new(&[]);
             let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, &dep_graph, None, registry);
+            let sess = build_session(sessopts, None, registry);
             assert!(sess.diagnostic().can_emit_warnings);
         }
     }
index 1f9cb2b03100fba2fec8d091d2c3b554e2bed528..df5a2648e270ce92b6e517c109911e830fec4242 100644 (file)
@@ -11,7 +11,6 @@
 pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
 pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
 
-use dep_graph::DepGraph;
 use hir::def_id::{CrateNum, DefIndex};
 
 use lint;
@@ -58,7 +57,6 @@
 // Represents the data associated with a compilation
 // session for a single crate.
 pub struct Session {
-    pub dep_graph: DepGraph,
     pub target: config::Config,
     pub host: Target,
     pub opts: config::Options,
@@ -91,7 +89,7 @@ pub struct Session {
     // forms a unique global identifier for the crate. It is used to allow
     // multiple crates with the same name to coexist. See the
     // trans::back::symbol_names module for more information.
-    pub crate_disambiguator: RefCell<Symbol>,
+    pub crate_disambiguator: RefCell<Option<Symbol>>,
     pub features: RefCell<feature_gate::Features>,
 
     /// The maximum recursion limit for potentially infinitely recursive
@@ -169,7 +167,10 @@ enum DiagnosticBuilderMethod {
 
 impl Session {
     pub fn local_crate_disambiguator(&self) -> Symbol {
-        *self.crate_disambiguator.borrow()
+        match *self.crate_disambiguator.borrow() {
+            Some(sym) => sym,
+            None => bug!("accessing disambiguator before initialization"),
+        }
     }
     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
                                                     sp: S,
@@ -501,9 +502,29 @@ pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
             kind)
     }
 
+    pub fn set_incr_session_load_dep_graph(&self, load: bool) {
+        let mut incr_comp_session = self.incr_comp_session.borrow_mut();
+
+        match *incr_comp_session {
+            IncrCompSession::Active { ref mut load_dep_graph, .. } => {
+                *load_dep_graph = load;
+            }
+            _ => {}
+        }
+    }
+
+    pub fn incr_session_load_dep_graph(&self) -> bool {
+        let incr_comp_session = self.incr_comp_session.borrow();
+        match *incr_comp_session {
+            IncrCompSession::Active { load_dep_graph, .. } => load_dep_graph,
+            _ => false,
+        }
+    }
+
     pub fn init_incr_comp_session(&self,
                                   session_dir: PathBuf,
-                                  lock_file: flock::Lock) {
+                                  lock_file: flock::Lock,
+                                  load_dep_graph: bool) {
         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
 
         if let IncrCompSession::NotInitialized = *incr_comp_session { } else {
@@ -513,6 +534,7 @@ pub fn init_incr_comp_session(&self,
         *incr_comp_session = IncrCompSession::Active {
             session_directory: session_dir,
             lock_file,
+            load_dep_graph,
         };
     }
 
@@ -617,14 +639,12 @@ pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -
 }
 
 pub fn build_session(sopts: config::Options,
-                     dep_graph: &DepGraph,
                      local_crate_source_file: Option<PathBuf>,
                      registry: errors::registry::Registry)
                      -> Session {
     let file_path_mapping = sopts.file_path_mapping();
 
     build_session_with_codemap(sopts,
-                               dep_graph,
                                local_crate_source_file,
                                registry,
                                Rc::new(codemap::CodeMap::new(file_path_mapping)),
@@ -632,7 +652,6 @@ pub fn build_session(sopts: config::Options,
 }
 
 pub fn build_session_with_codemap(sopts: config::Options,
-                                  dep_graph: &DepGraph,
                                   local_crate_source_file: Option<PathBuf>,
                                   registry: errors::registry::Registry,
                                   codemap: Rc<codemap::CodeMap>,
@@ -672,14 +691,12 @@ pub fn build_session_with_codemap(sopts: config::Options,
                                       emitter);
 
     build_session_(sopts,
-                   dep_graph,
                    local_crate_source_file,
                    diagnostic_handler,
                    codemap)
 }
 
 pub fn build_session_(sopts: config::Options,
-                      dep_graph: &DepGraph,
                       local_crate_source_file: Option<PathBuf>,
                       span_diagnostic: errors::Handler,
                       codemap: Rc<codemap::CodeMap>)
@@ -715,7 +732,6 @@ pub fn build_session_(sopts: config::Options,
     let working_dir = file_path_mapping.map_prefix(working_dir);
 
     let sess = Session {
-        dep_graph: dep_graph.clone(),
         target: target_cfg,
         host,
         opts: sopts,
@@ -735,7 +751,7 @@ pub fn build_session_(sopts: config::Options,
         plugin_attributes: RefCell::new(Vec::new()),
         crate_types: RefCell::new(Vec::new()),
         dependency_formats: RefCell::new(FxHashMap()),
-        crate_disambiguator: RefCell::new(Symbol::intern("")),
+        crate_disambiguator: RefCell::new(None),
         features: RefCell::new(feature_gate::Features::new()),
         recursion_limit: Cell::new(64),
         type_length_limit: Cell::new(1048576),
@@ -793,6 +809,7 @@ pub enum IncrCompSession {
     Active {
         session_directory: PathBuf,
         lock_file: flock::Lock,
+        load_dep_graph: bool,
     },
     // This is the state after the session directory has been finalized. In this
     // state, the contents of the directory must not be modified any more.
index f74af6ee1632e793f8f6fef0922f9262443e2eb1..7665bfd5b1117316c0a758338ad103adca34e2b5 100644 (file)
@@ -132,6 +132,11 @@ pub trait BitwiseOperator {
     fn join(&self, pred1: usize, pred2: usize) -> usize;
 }
 
+pub struct Intersect;
+impl BitwiseOperator for Intersect {
+    #[inline]
+    fn join(&self, a: usize, b: usize) -> usize { a & b }
+}
 pub struct Union;
 impl BitwiseOperator for Union {
     #[inline]
index 47fa21e3bf0b2bf6a1e47f4d6c78b94c1aca9246..c790463e47adb4f2ce3e897c2229e22dc9f7d88f 100644 (file)
@@ -15,7 +15,7 @@
 use std::ops::{Deref, DerefMut, Range};
 use std::slice;
 use bitslice::{BitSlice, Word};
-use bitslice::{bitwise, Union, Subtract};
+use bitslice::{bitwise, Union, Subtract, Intersect};
 use indexed_vec::Idx;
 
 /// Represents a set (or packed family of sets), of some element type
@@ -164,6 +164,10 @@ pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
         bitwise(self.words_mut(), other.words(), &Subtract)
     }
 
+    pub fn intersect(&mut self, other: &IdxSet<T>) -> bool {
+        bitwise(self.words_mut(), other.words(), &Intersect)
+    }
+
     pub fn iter(&self) -> Iter<T> {
         Iter {
             cur: None,
index c41d5beec6877ab61570ae2f6fcfa17601e1b080..ed012f87996d7a10ba3824ded6ffa76becff2295 100644 (file)
@@ -10,6 +10,7 @@
 
 #![cfg_attr(not(feature="llvm"), allow(dead_code))]
 
+use rustc::dep_graph::DepGraph;
 use rustc::hir::{self, map as hir_map};
 use rustc::hir::lowering::lower_crate;
 use rustc::ich::Fingerprint;
@@ -115,7 +116,7 @@ macro_rules! controller_entry_point {
     // We need nested scopes here, because the intermediate results can keep
     // large chunks of memory alive and we want to free them as soon as
     // possible to keep the peak memory usage low
-    let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = {
+    let (outputs, trans, dep_graph): (OutputFilenames, OngoingCrateTranslation, DepGraph) = {
         let krate = match phase_1_parse_input(control, sess, input) {
             Ok(krate) => krate,
             Err(mut parse_error) => {
@@ -144,7 +145,13 @@ macro_rules! controller_entry_point {
             ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
         let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
             phase_2_configure_and_expand(
-                sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
+                sess,
+                &cstore,
+                krate,
+                registry,
+                &crate_name,
+                addl_plugins,
+                control.make_glob_map,
                 |expanded_crate| {
                     let mut state = CompileState::state_after_expand(
                         input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
@@ -251,7 +258,7 @@ macro_rules! controller_entry_point {
                 }
             }
 
-            Ok((outputs, trans))
+            Ok((outputs, trans, tcx.dep_graph.clone()))
         })??
     };
 
@@ -266,7 +273,7 @@ macro_rules! controller_entry_point {
             sess.code_stats.borrow().print_type_sizes();
         }
 
-        let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
+        let (phase5_result, trans) = phase_5_run_llvm_passes(sess, &dep_graph, trans);
 
         controller_entry_point!(after_llvm,
                                 sess,
@@ -624,7 +631,15 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
     *sess.features.borrow_mut() = features;
 
     *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
-    *sess.crate_disambiguator.borrow_mut() = Symbol::intern(&compute_crate_disambiguator(sess));
+
+    let disambiguator = Symbol::intern(&compute_crate_disambiguator(sess));
+    *sess.crate_disambiguator.borrow_mut() = Some(disambiguator);
+    rustc_incremental::prepare_session_directory(
+        sess,
+        &crate_name,
+        &disambiguator.as_str(),
+    );
+    let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
 
     time(time_passes, "recursion limit", || {
         middle::recursion_limit::update_limits(sess, &krate);
@@ -694,7 +709,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
     // item, much like we do for macro expansion. In other words, the hash reflects not just
     // its contents but the results of name resolution on those contents. Hopefully we'll push
     // this back at some point.
-    let _ignore = sess.dep_graph.in_ignore();
+    let _ignore = dep_graph.in_ignore();
     let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name);
     let resolver_arenas = Resolver::arenas();
     let mut resolver = Resolver::new(sess,
@@ -847,13 +862,13 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 
     // Lower ast -> hir.
     let hir_forest = time(time_passes, "lowering ast -> hir", || {
-        let hir_crate = lower_crate(sess, cstore, &krate, &mut resolver);
+        let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver);
 
         if sess.opts.debugging_opts.hir_stats {
             hir_stats::print_hir_stats(&hir_crate);
         }
 
-        hir_map::Forest::new(hir_crate, &sess.dep_graph)
+        hir_map::Forest::new(hir_crate, &dep_graph)
     });
 
     time(time_passes,
@@ -1134,9 +1149,10 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// as a side effect.
 #[cfg(feature="llvm")]
 pub fn phase_5_run_llvm_passes(sess: &Session,
+                               dep_graph: &DepGraph,
                                trans: write::OngoingCrateTranslation)
                                -> (CompileResult, trans::CrateTranslation) {
-    let trans = trans.join(sess);
+    let trans = trans.join(sess, dep_graph);
 
     if sess.opts.debugging_opts.incremental_info {
         write::dump_incremental_data(&trans);
@@ -1144,7 +1160,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 
     time(sess.time_passes(),
          "serialize work products",
-         move || rustc_incremental::save_work_products(sess));
+         move || rustc_incremental::save_work_products(sess, dep_graph));
 
     (sess.compile_status(), trans)
 }
index 099dda17823e67f864b112e437ae8ba72c65ec77..522b9eb22320e9d00bc7f806a32236d80e24c67b 100644 (file)
@@ -64,7 +64,6 @@
 use rustc_resolve as resolve;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config, Session, build_session, CompileResult};
 use rustc::session::CompileIncomplete;
 use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
@@ -294,13 +293,12 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         },
     };
 
-    let dep_graph = DepGraph::new(sopts.build_dep_graph());
     let cstore = Rc::new(CStore::new(box ::MetadataLoader));
 
     let loader = file_loader.unwrap_or(box RealFileLoader);
     let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
     let mut sess = session::build_session_with_codemap(
-        sopts, &dep_graph, input_file_path, descriptions, codemap, emitter_dest,
+        sopts, input_file_path, descriptions, codemap, emitter_dest,
     );
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
@@ -318,7 +316,13 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
 
     let plugins = sess.opts.debugging_opts.extra_plugins.clone();
     let control = callbacks.build_controller(&sess, &matches);
-    (driver::compile_input(&sess, &cstore, &input, &odir, &ofile, Some(plugins), &control),
+    (driver::compile_input(&sess,
+                           &cstore,
+                           &input,
+                           &odir,
+                           &ofile,
+                           Some(plugins),
+                           &control),
      Some(sess))
 }
 
@@ -580,9 +584,7 @@ fn no_input(&mut self,
                     describe_lints(&ls, false);
                     return None;
                 }
-                let dep_graph = DepGraph::new(sopts.build_dep_graph());
                 let mut sess = build_session(sopts.clone(),
-                    &dep_graph,
                     None,
                     descriptions.clone());
                 rustc_trans::init(&sess);
index d2fb9903683676a5e6b853183108de3d203166c0..d0edcbc326098eb738d0ac37347eb37c11d561fb 100644 (file)
@@ -11,7 +11,6 @@
 //! # Standalone Tests for the Inference Module
 
 use driver;
-use rustc::dep_graph::DepGraph;
 use rustc_lint;
 use rustc_resolve::MakeGlobMap;
 use rustc_trans;
@@ -102,11 +101,8 @@ fn test_env<F>(source_string: &str,
     options.unstable_features = UnstableFeatures::Allow;
     let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
 
-    let dep_graph = DepGraph::new(false);
-    let _ignore = dep_graph.in_ignore();
     let cstore = Rc::new(CStore::new(box ::MetadataLoader));
     let sess = session::build_session_(options,
-                                       &dep_graph,
                                        None,
                                        diagnostic_handler,
                                        Rc::new(CodeMap::new(FilePathMapping::empty())));
@@ -130,7 +126,6 @@ fn test_env<F>(source_string: &str,
                                              |_| Ok(()))
             .expect("phase 2 aborted")
     };
-    let _ignore = dep_graph.in_ignore();
 
     let arena = DroplessArena::new();
     let arenas = ty::GlobalArenas::new();
index 8870033095c9c2a1106ddd91d3d88ca049367cb3..3c1e02f8a5adde4c72a4519cc474b84a833de246 100644 (file)
@@ -40,4 +40,5 @@
 pub use persist::save_trans_partition;
 pub use persist::save_work_products;
 pub use persist::in_incr_comp_dir;
+pub use persist::prepare_session_directory;
 pub use persist::finalize_session_directory;
index 434c82095bd9a98d0e21cbf8a3639d934646202c..f3f35a50fe0b3638a17c774548256328055c5e1d 100644 (file)
 //! unsupported file system and emit a warning in that case. This is not yet
 //! implemented.
 
-use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc::hir::def_id::CrateNum;
 use rustc::hir::svh::Svh;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
@@ -193,13 +193,21 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
 /// a dep-graph and work products from a previous session.
 /// If the call fails, the fn may leave behind an invalid session directory.
 /// The garbage collection will take care of it.
-pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
+pub fn prepare_session_directory(sess: &Session,
+                                 crate_name: &str,
+                                 crate_disambiguator: &str) {
+    if sess.opts.incremental.is_none() {
+        return
+    }
+
     debug!("prepare_session_directory");
 
     // {incr-comp-dir}/{crate-name-and-disambiguator}
-    let crate_dir = crate_path_tcx(tcx, LOCAL_CRATE);
+    let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
     debug!("crate-dir: {}", crate_dir.display());
-    try!(create_dir(tcx.sess, &crate_dir, "crate"));
+    if create_dir(sess, &crate_dir, "crate").is_err() {
+        return
+    }
 
     // Hack: canonicalize the path *after creating the directory*
     // because, on windows, long paths can cause problems;
@@ -208,9 +216,9 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
     let crate_dir = match crate_dir.canonicalize() {
         Ok(v) => v,
         Err(err) => {
-            tcx.sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
-                                  crate_dir.display(), err));
-            return Err(());
+            sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
+                              crate_dir.display(), err));
+            return
         }
     };
 
@@ -225,11 +233,16 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
 
         // Lock the new session directory. If this fails, return an
         // error without retrying
-        let (directory_lock, lock_file_path) = try!(lock_directory(tcx.sess, &session_dir));
+        let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
+            Ok(e) => e,
+            Err(_) => return,
+        };
 
         // Now that we have the lock, we can actually create the session
         // directory
-        try!(create_dir(tcx.sess, &session_dir, "session"));
+        if create_dir(sess, &session_dir, "session").is_err() {
+            return
+        }
 
         // Find a suitable source directory to copy from. Ignore those that we
         // have already tried before.
@@ -243,14 +256,14 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
             debug!("no source directory found. Continuing with empty session \
                     directory.");
 
-            tcx.sess.init_incr_comp_session(session_dir, directory_lock);
-            return Ok(false)
+            sess.init_incr_comp_session(session_dir, directory_lock, false);
+            return
         };
 
         debug!("attempting to copy data from source: {}",
                source_directory.display());
 
-        let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info;
+        let print_file_copy_stats = sess.opts.debugging_opts.incremental_info;
 
         // Try copying over all files from the source directory
         if let Ok(allows_links) = copy_files(&session_dir, &source_directory,
@@ -259,7 +272,7 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
                    source_directory.display());
 
             if !allows_links {
-                tcx.sess.warn(&format!("Hard linking files in the incremental \
+                sess.warn(&format!("Hard linking files in the incremental \
                                         compilation cache failed. Copying files \
                                         instead. Consider moving the cache \
                                         directory to a file system which supports \
@@ -268,8 +281,8 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
                     );
             }
 
-            tcx.sess.init_incr_comp_session(session_dir, directory_lock);
-            return Ok(true)
+            sess.init_incr_comp_session(session_dir, directory_lock, true);
+            return
         } else {
              debug!("copying failed - trying next directory");
 
@@ -280,13 +293,13 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
             // Try to remove the session directory we just allocated. We don't
             // know if there's any garbage in it from the failed copy action.
             if let Err(err) = safe_remove_dir_all(&session_dir) {
-                tcx.sess.warn(&format!("Failed to delete partly initialized \
-                                        session dir `{}`: {}",
-                                       session_dir.display(),
-                                       err));
+                sess.warn(&format!("Failed to delete partly initialized \
+                                    session dir `{}`: {}",
+                                   session_dir.display(),
+                                   err));
             }
 
-            delete_session_dir_lock_file(tcx.sess, &lock_file_path);
+            delete_session_dir_lock_file(sess, &lock_file_path);
             mem::drop(directory_lock);
         }
     }
index 2c43896ec73d242d9170957f423373baa109006d..ba638289fdf03168b9c5ee60f2a22cdcaa11f60d 100644 (file)
 /// more general overview.
 pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 incremental_hashes_map: &IncrementalHashesMap) {
-    if tcx.sess.opts.incremental.is_none() {
-        return;
+    if tcx.sess.incr_session_load_dep_graph() {
+        let _ignore = tcx.dep_graph.in_ignore();
+        load_dep_graph_if_exists(tcx, incremental_hashes_map);
     }
-
-    match prepare_session_directory(tcx) {
-        Ok(true) => {
-            // We successfully allocated a session directory and there is
-            // something in it to load, so continue
-        }
-        Ok(false) => {
-            // We successfully allocated a session directory, but there is no
-            // dep-graph data in it to load (because this is the first
-            // compilation session with this incr. comp. dir.)
-            return
-        }
-        Err(()) => {
-            // Something went wrong while trying to allocate the session
-            // directory. Don't try to use it any further.
-            return
-        }
-    }
-
-    let _ignore = tcx.dep_graph.in_ignore();
-    load_dep_graph_if_exists(tcx, incremental_hashes_map);
 }
 
 fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
index 5c1582daa78fa07119caa53219831e699ed60e88..fb3308132261f37d722dbdb5e771353388502515 100644 (file)
@@ -22,6 +22,7 @@
 mod work_product;
 mod file_format;
 
+pub use self::fs::prepare_session_directory;
 pub use self::fs::finalize_session_directory;
 pub use self::fs::in_incr_comp_dir;
 pub use self::load::load_dep_graph;
index 339e2bdc15734960534873ae46a39402f11a37f9..65fbaf1ad047a484da1c659d956e324283fdcfb1 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::dep_graph::DepNode;
+use rustc::dep_graph::{DepGraph, DepNode};
 use rustc::hir::def_id::DefId;
 use rustc::hir::svh::Svh;
 use rustc::ich::Fingerprint;
@@ -79,21 +79,21 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             &current_metadata_hashes);
 }
 
-pub fn save_work_products(sess: &Session) {
+pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
     if sess.opts.incremental.is_none() {
         return;
     }
 
     debug!("save_work_products()");
-    let _ignore = sess.dep_graph.in_ignore();
+    let _ignore = dep_graph.in_ignore();
     let path = work_products_path(sess);
-    save_in(sess, path, |e| encode_work_products(sess, e));
+    save_in(sess, path, |e| encode_work_products(dep_graph, e));
 
     // We also need to clean out old work-products, as not all of them are
     // deleted during invalidation. Some object files don't change their
     // content, they are just not needed anymore.
-    let new_work_products = sess.dep_graph.work_products();
-    let previous_work_products = sess.dep_graph.previous_work_products();
+    let new_work_products = dep_graph.work_products();
+    let previous_work_products = dep_graph.previous_work_products();
 
     for (id, wp) in previous_work_products.iter() {
         if !new_work_products.contains_key(id) {
@@ -309,8 +309,9 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
     Ok(())
 }
 
-pub fn encode_work_products(sess: &Session, encoder: &mut Encoder) -> io::Result<()> {
-    let work_products: Vec<_> = sess.dep_graph
+pub fn encode_work_products(dep_graph: &DepGraph,
+                            encoder: &mut Encoder) -> io::Result<()> {
+    let work_products: Vec<_> = dep_graph
         .work_products()
         .iter()
         .map(|(id, work_product)| {
index e20d7a006b0ddb0844ec0a88f54eba4624447c36..70d96e3a83d376bed6bd6dbd219e299b7f2960b9 100644 (file)
@@ -11,7 +11,7 @@
 //! This module contains files for saving intermediate work-products.
 
 use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId};
+use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph};
 use rustc::session::Session;
 use rustc::session::config::OutputType;
 use rustc::util::fs::link_or_copy;
@@ -19,6 +19,7 @@
 use std::fs as std_fs;
 
 pub fn save_trans_partition(sess: &Session,
+                            dep_graph: &DepGraph,
                             cgu_name: &str,
                             partition_hash: u64,
                             files: &[(OutputType, PathBuf)]) {
@@ -60,7 +61,7 @@ pub fn save_trans_partition(sess: &Session,
         saved_files,
     };
 
-    sess.dep_graph.insert_work_product(&work_product_id, work_product);
+    dep_graph.insert_work_product(&work_product_id, work_product);
 }
 
 pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
index c08620c1e41040371f402e07287bbafb60167a15..bac884b4d01e9f94dfa898838a0073d7cadbe89d 100644 (file)
@@ -352,6 +352,8 @@ pub fn pop_scope(&mut self,
         }
         let scope = self.scopes.pop().unwrap();
         assert_eq!(scope.region_scope, region_scope.0);
+
+        self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
         unpack!(block = build_scope_drops(&mut self.cfg,
                                           &scope,
                                           &self.scopes,
@@ -359,7 +361,6 @@ pub fn pop_scope(&mut self,
                                           self.arg_count,
                                           false));
 
-        self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
         block.unit()
     }
 
@@ -406,15 +407,16 @@ pub fn exit_scope(&mut self,
                 scope.cached_exits.insert((target, region_scope.0), b);
                 b
             };
+
+            // End all regions for scopes out of which we are breaking.
+            self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
+
             unpack!(block = build_scope_drops(&mut self.cfg,
                                               scope,
                                               rest,
                                               block,
                                               self.arg_count,
                                               false));
-
-            // End all regions for scopes out of which we are breaking.
-            self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
         }
         }
         let scope = &self.scopes[len - scope_count];
index a4421b216c311b4d50134c8e4885123d708216e7..19a595622b92edf62b9a4394407a4e5dffa4a1d9 100644 (file)
 use super::drop_flag_effects_for_location;
 use super::on_lookup_result_bits;
 
+mod storage_liveness;
+
+pub use self::storage_liveness::*;
+
 #[allow(dead_code)]
 pub(super) mod borrows;
 
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
new file mode 100644 (file)
index 0000000..98615c6
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use super::*;
+
+use rustc::mir::*;
+use dataflow::BitDenotation;
+
+#[derive(Copy, Clone)]
+pub struct MaybeStorageLive<'a, 'tcx: 'a> {
+    mir: &'a Mir<'tcx>,
+}
+
+impl<'a, 'tcx: 'a> MaybeStorageLive<'a, 'tcx> {
+    pub fn new(mir: &'a Mir<'tcx>)
+               -> Self {
+        MaybeStorageLive { mir: mir }
+    }
+
+    pub fn mir(&self) -> &Mir<'tcx> {
+        self.mir
+    }
+}
+
+impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> {
+    type Idx = Local;
+    fn name() -> &'static str { "maybe_storage_live" }
+    fn bits_per_block(&self) -> usize {
+        self.mir.local_decls.len()
+    }
+
+    fn start_block_effect(&self, _sets: &mut BlockSets<Local>) {
+        // Nothing is live on function entry
+    }
+
+    fn statement_effect(&self,
+                        sets: &mut BlockSets<Local>,
+                        loc: Location) {
+        let stmt = &self.mir[loc.block].statements[loc.statement_index];
+
+        match stmt.kind {
+            StatementKind::StorageLive(l) => sets.gen(&l),
+            StatementKind::StorageDead(l) => sets.kill(&l),
+            _ => (),
+        }
+    }
+
+    fn terminator_effect(&self,
+                         _sets: &mut BlockSets<Local>,
+                         _loc: Location) {
+        // Terminators have no effect
+    }
+
+    fn propagate_call_return(&self,
+                             _in_out: &mut IdxSet<Local>,
+                             _call_bb: mir::BasicBlock,
+                             _dest_bb: mir::BasicBlock,
+                             _dest_lval: &mir::Lvalue) {
+        // Nothing to do when a call returns successfully
+    }
+}
+
+impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> {
+    #[inline]
+    fn join(&self, pred1: usize, pred2: usize) -> usize {
+        pred1 | pred2 // "maybe" means we union effects of both preds
+    }
+}
+
+impl<'a, 'tcx> DataflowOperator for MaybeStorageLive<'a, 'tcx> {
+    #[inline]
+    fn bottom_value() -> bool {
+        false // bottom = dead
+    }
+}
index 9f9909a8f57a99f9b1d4cf74e5319d0432fcb254..9fa5691d647b70015204c5c98d93cc11ee61c4c9 100644 (file)
@@ -24,6 +24,7 @@
 use std::path::PathBuf;
 use std::usize;
 
+pub use self::impls::{MaybeStorageLive};
 pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
 pub use self::impls::{DefinitelyInitializedLvals};
 pub use self::impls::borrows::{Borrows, BorrowData, BorrowIndex};
@@ -351,6 +352,29 @@ fn apply_local_effect(&mut self,
                           flow_state: &mut Self::FlowState);
 }
 
+pub fn state_for_location<T: BitDenotation>(loc: Location,
+                                            analysis: &T,
+                                            result: &DataflowResults<T>)
+    -> IdxSetBuf<T::Idx> {
+    let mut entry = result.sets().on_entry_set_for(loc.block.index()).to_owned();
+
+    {
+        let mut sets = BlockSets {
+            on_entry: &mut entry.clone(),
+            kill_set: &mut entry.clone(),
+            gen_set: &mut entry,
+        };
+
+        for stmt in 0..loc.statement_index {
+            let mut stmt_loc = loc;
+            stmt_loc.statement_index = stmt;
+            analysis.statement_effect(&mut sets, stmt_loc);
+        }
+    }
+
+    entry
+}
+
 pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation
 {
     flow_state: DataflowState<O>,
index a52656becd74534190b114501df7e4bff8d6be39..78fe7b26ebfe0063434fe785a4dd08207b2329e6 100644 (file)
@@ -38,7 +38,8 @@
 //! This pass computes the meaning of the state field and the MIR locals which are live
 //! across a suspension point. There are however two hardcoded generator states:
 //!     0 - Generator have not been resumed yet
-//!     1 - Generator has been poisoned
+//!     1 - Generator has returned / is completed
+//!     2 - Generator has been poisoned
 //!
 //! It also rewrites `return x` and `yield y` as setting a new generator state and returning
 //! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
 //! the action to take.
 //!
 //! One of them is the implementation of Generator::resume.
-//! For generators which have already returned it panics.
 //! For generators with state 0 (unresumed) it starts the execution of the generator.
-//! For generators with state 1 (poisoned) it panics.
+//! For generators with state 1 (returned) and state 2 (poisoned) it panics.
 //! Otherwise it continues the execution from the last suspension point.
 //!
 //! The other function is the drop glue for the generator.
-//! For generators which have already returned it does nothing.
 //! For generators with state 0 (unresumed) it drops the upvars of the generator.
-//! For generators with state 1 (poisoned) it does nothing.
+//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
 //! Otherwise it drops all the values in scope at the last suspension point.
 
 use rustc::hir;
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::mir::transform::{MirPass, MirSource};
-use rustc::mir::visit::{LvalueContext, MutVisitor};
+use rustc::mir::visit::{LvalueContext, Visitor, MutVisitor};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
 use rustc::ty::subst::{Kind, Substs};
 use util::dump_mir;
 use util::liveness;
 use rustc_const_math::ConstInt;
 use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::indexed_set::IdxSetBuf;
 use std::collections::HashMap;
 use std::borrow::Cow;
 use std::iter::once;
 use std::mem;
 use transform::simplify;
 use transform::no_landing_pads::no_landing_pads;
+use dataflow::{self, MaybeStorageLive, state_for_location};
 
 pub struct StateTransform;
 
@@ -126,6 +127,13 @@ fn self_arg() -> Local {
     Local::new(1)
 }
 
+struct SuspensionPoint {
+    state: u32,
+    resume: BasicBlock,
+    drop: Option<BasicBlock>,
+    storage_liveness: liveness::LocalSet,
+}
+
 struct TransformVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     state_adt_ref: &'tcx AdtDef,
@@ -137,18 +145,14 @@ struct TransformVisitor<'a, 'tcx: 'a> {
     // Mapping from Local to (type of local, generator struct index)
     remap: HashMap<Local, (Ty<'tcx>, usize)>,
 
-    // The number of generator states. 0 is unresumed, 1 is poisoned. So this is initialized to 2
-    bb_target_count: u32,
+    // A map from a suspension point in a block to the locals which have live storage at that point
+    storage_liveness: HashMap<BasicBlock, liveness::LocalSet>,
 
-    // Map from a (which block to resume execution at, which block to use to drop the generator)
-    // to a generator state
-    bb_targets: HashMap<(BasicBlock, Option<BasicBlock>), u32>,
+    // A list of suspension points, generated during the transform
+    suspension_points: Vec<SuspensionPoint>,
 
     // The original RETURN_POINTER local
     new_ret_local: Local,
-
-    // The block to resume execution when for Return
-    return_block: BasicBlock,
 }
 
 impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
@@ -225,33 +229,39 @@ fn visit_basic_block_data(&mut self,
 
         let ret_val = match data.terminator().kind {
             TerminatorKind::Return => Some((1,
-                self.return_block,
+                None,
                 Operand::Consume(Lvalue::Local(self.new_ret_local)),
                 None)),
             TerminatorKind::Yield { ref value, resume, drop } => Some((0,
-                resume,
+                Some(resume),
                 value.clone(),
                 drop)),
             _ => None
         };
 
         if let Some((state_idx, resume, v, drop)) = ret_val {
-            let bb_idx = {
-                let bb_targets = &mut self.bb_targets;
-                let bb_target = &mut self.bb_target_count;
-                *bb_targets.entry((resume, drop)).or_insert_with(|| {
-                    let target = *bb_target;
-                    *bb_target = target.checked_add(1).unwrap();
-                    target
-                })
-            };
             let source_info = data.terminator().source_info;
-            data.statements.push(self.set_state(bb_idx, source_info));
+            // We must assign the value first in case it gets declared dead below
             data.statements.push(Statement {
                 source_info,
                 kind: StatementKind::Assign(Lvalue::Local(RETURN_POINTER),
                     self.make_state(state_idx, v)),
             });
+            let state = if let Some(resume) = resume { // Yield
+                let state = 3 + self.suspension_points.len() as u32;
+
+                self.suspension_points.push(SuspensionPoint {
+                    state,
+                    resume,
+                    drop,
+                    storage_liveness: self.storage_liveness.get(&block).unwrap().clone(),
+                });
+
+                state
+            } else { // Return
+                 1 // state for returned
+            };
+            data.statements.push(self.set_state(state, source_info));
             data.terminator.as_mut().unwrap().kind = TerminatorKind::Return;
         }
 
@@ -286,16 +296,11 @@ fn make_generator_state_argument_indirect<'a, 'tcx>(
 
 fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
                             mir: &mut Mir<'tcx>) -> Local {
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
-
     let new_ret = LocalDecl {
         mutability: Mutability::Mut,
         ty: ret_ty,
         name: None,
-        source_info,
+        source_info: source_info(mir),
         internal: false,
         is_user_variable: false,
     };
@@ -311,33 +316,84 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
     new_ret_local
 }
 
+struct StorageIgnored(liveness::LocalSet);
+
+impl<'tcx> Visitor<'tcx> for StorageIgnored {
+    fn visit_statement(&mut self,
+                       _block: BasicBlock,
+                       statement: &Statement<'tcx>,
+                       _location: Location) {
+        match statement.kind {
+            StatementKind::StorageLive(l) |
+            StatementKind::StorageDead(l) => { self.0.remove(&l); }
+            _ => (),
+        }
+    }
+}
+
 fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                mir: &Mir<'tcx>,
-                                               source: MirSource) -> liveness::LocalSet {
+                                               source: MirSource) ->
+                                               (liveness::LocalSet,
+                                                HashMap<BasicBlock, liveness::LocalSet>) {
+    let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
+    let node_id = source.item_id();
+    let analysis = MaybeStorageLive::new(mir);
+    let storage_live =
+        dataflow::do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+                              |bd, p| &bd.mir().local_decls[p]);
+
+    let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
+    ignored.visit_mir(mir);
+
     let mut set = liveness::LocalSet::new_empty(mir.local_decls.len());
-    let result = liveness::liveness_of_locals(mir);
-    liveness::dump_mir(tcx, "generator_liveness", source, mir, &result);
+    let liveness = liveness::liveness_of_locals(mir);
+    liveness::dump_mir(tcx, "generator_liveness", source, mir, &liveness);
+
+    let mut storage_liveness_map = HashMap::new();
 
     for (block, data) in mir.basic_blocks().iter_enumerated() {
         if let TerminatorKind::Yield { .. } = data.terminator().kind {
-            set.union(&result.outs[block]);
+            let loc = Location {
+                block: block,
+                statement_index: data.statements.len(),
+            };
+
+            let storage_liveness = state_for_location(loc, &analysis, &storage_live);
+
+            storage_liveness_map.insert(block, storage_liveness.clone());
+
+            let mut live_locals = storage_liveness;
+
+            // Mark locals without storage statements as always having live storage
+            live_locals.union(&ignored.0);
+
+            // Locals live are live at this point only if they are used across suspension points
+            // and their storage is live
+            live_locals.intersect(&liveness.outs[block]);
+
+            // Add the locals life at this suspension point to the set of locals which live across
+            // any suspension points
+            set.union(&live_locals);
         }
     }
 
     // The generator argument is ignored
     set.remove(&self_arg());
 
-    set
+    (set, storage_liveness_map)
 }
 
 fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             source: MirSource,
                             interior: GeneratorInterior<'tcx>,
                             mir: &mut Mir<'tcx>)
-    -> (HashMap<Local, (Ty<'tcx>, usize)>, GeneratorLayout<'tcx>)
+    -> (HashMap<Local, (Ty<'tcx>, usize)>,
+        GeneratorLayout<'tcx>,
+        HashMap<BasicBlock, liveness::LocalSet>)
 {
     // Use a liveness analysis to compute locals which are live across a suspension point
-    let live_locals = locals_live_across_suspend_points(tcx, mir, source);
+    let (live_locals, storage_liveness) = locals_live_across_suspend_points(tcx, mir, source);
 
     // Erase regions from the types passed in from typeck so we can compare them with
     // MIR types
@@ -381,12 +437,31 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         fields: vars
     };
 
-    (remap, layout)
+    (remap, layout, storage_liveness)
 }
 
-fn insert_entry_point<'tcx>(mir: &mut Mir<'tcx>,
-                            block: BasicBlockData<'tcx>) {
-    mir.basic_blocks_mut().raw.insert(0, block);
+fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           mir: &mut Mir<'tcx>,
+                           cases: Vec<(u32, BasicBlock)>,
+                           transform: &TransformVisitor<'a, 'tcx>) {
+    let return_block = insert_return_block(mir);
+
+    let switch = TerminatorKind::SwitchInt {
+        discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
+        switch_ty: tcx.types.u32,
+        values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::<Vec<_>>()),
+        targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
+    };
+
+    let source_info = source_info(mir);
+    mir.basic_blocks_mut().raw.insert(0, BasicBlockData {
+        statements: Vec::new(),
+        terminator: Some(Terminator {
+            source_info,
+            kind: switch,
+        }),
+        is_cleanup: false,
+    });
 
     let blocks = mir.basic_blocks_mut().iter_mut();
 
@@ -458,46 +533,16 @@ fn create_generator_drop_shim<'a, 'tcx>(
                 drop_clean: BasicBlock) -> Mir<'tcx> {
     let mut mir = mir.clone();
 
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
+    let source_info = source_info(&mir);
 
-    let return_block = BasicBlock::new(mir.basic_blocks().len());
-    mir.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: TerminatorKind::Return,
-        }),
-        is_cleanup: false,
-    });
-
-    let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(_, u), &s)| {
-        u.map(|d| (s, d))
-    }).collect();
+    let mut cases = create_cases(&mut mir, transform, |point| point.drop);
 
     cases.insert(0, (0, drop_clean));
 
-    // The poisoned state 1 falls through to the default case which is just to return
+    // The returned state (1) and the poisoned state (2) falls through to
+    // the default case which is just to return
 
-    let switch = TerminatorKind::SwitchInt {
-        discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
-        switch_ty: tcx.types.u32,
-        values: Cow::from(cases.iter().map(|&(i, _)| {
-                ConstInt::U32(i)
-            }).collect::<Vec<_>>()),
-        targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
-    };
-
-    insert_entry_point(&mut mir, BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: switch,
-        }),
-        is_cleanup: false,
-    });
+    insert_switch(tcx, &mut mir, cases, &transform);
 
     for block in mir.basic_blocks_mut() {
         let kind = &mut block.terminator_mut().kind;
@@ -507,11 +552,6 @@ fn create_generator_drop_shim<'a, 'tcx>(
     }
 
     // Replace the return variable
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
-
     mir.return_ty = tcx.mk_nil();
     mir.local_decls[RETURN_POINTER] = LocalDecl {
         mutability: Mutability::Mut,
@@ -548,8 +588,23 @@ fn create_generator_drop_shim<'a, 'tcx>(
     mir
 }
 
-fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        mir: &mut Mir<'tcx>) {
+fn insert_return_block<'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
+    let return_block = BasicBlock::new(mir.basic_blocks().len());
+    let source_info = source_info(mir);
+    mir.basic_blocks_mut().push(BasicBlockData {
+        statements: Vec::new(),
+        terminator: Some(Terminator {
+            source_info,
+            kind: TerminatorKind::Return,
+        }),
+        is_cleanup: false,
+    });
+    return_block
+}
+
+fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                mir: &mut Mir<'tcx>,
+                                message: AssertMessage<'tcx>) -> BasicBlock {
     let assert_block = BasicBlock::new(mir.basic_blocks().len());
     let term = TerminatorKind::Assert {
         cond: Operand::Constant(box Constant {
@@ -563,16 +618,12 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             },
         }),
         expected: true,
-        msg: AssertMessage::GeneratorResumedAfterReturn,
+        msg: message,
         target: assert_block,
         cleanup: None,
     };
 
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
-
+    let source_info = source_info(mir);
     mir.basic_blocks_mut().push(BasicBlockData {
         statements: Vec::new(),
         terminator: Some(Terminator {
@@ -581,11 +632,13 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }),
         is_cleanup: false,
     });
+
+    assert_block
 }
 
 fn create_generator_resume_function<'a, 'tcx>(
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
-        mut transform: TransformVisitor<'a, 'tcx>,
+        transform: TransformVisitor<'a, 'tcx>,
         def_id: DefId,
         source: MirSource,
         mir: &mut Mir<'tcx>) {
@@ -597,61 +650,16 @@ fn create_generator_resume_function<'a, 'tcx>(
         }
     }
 
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
-
-    let poisoned_block = BasicBlock::new(mir.basic_blocks().len());
-
-    let term = TerminatorKind::Assert {
-        cond: Operand::Constant(box Constant {
-            span: mir.span,
-            ty: tcx.types.bool,
-            literal: Literal::Value {
-                value: tcx.mk_const(ty::Const {
-                    val: ConstVal::Bool(false),
-                    ty: tcx.types.bool
-                }),
-            },
-        }),
-        expected: true,
-        msg: AssertMessage::GeneratorResumedAfterPanic,
-        target: transform.return_block,
-        cleanup: None,
-    };
-
-    mir.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: term,
-        }),
-        is_cleanup: false,
-    });
-
-    transform.bb_targets.insert((poisoned_block, None), 1);
+    let mut cases = create_cases(mir, &transform, |point| Some(point.resume));
 
-    let switch = TerminatorKind::SwitchInt {
-        discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
-        switch_ty: tcx.types.u32,
-        values: Cow::from(transform.bb_targets.values().map(|&i| {
-                ConstInt::U32(i)
-            }).collect::<Vec<_>>()),
-        targets: transform.bb_targets.keys()
-            .map(|&(k, _)| k)
-            .chain(once(transform.return_block))
-            .collect(),
-    };
+    // Jump to the entry point on the 0 state
+    cases.insert(0, (0, BasicBlock::new(0)));
+    // Panic when resumed on the returned (1) state
+    cases.insert(1, (1, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterReturn)));
+    // Panic when resumed on the poisoned (2) state
+    cases.insert(2, (2, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterPanic)));
 
-    insert_entry_point(mir, BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: switch,
-        }),
-        is_cleanup: false,
-    });
+    insert_switch(tcx, mir, cases, &transform);
 
     make_generator_state_argument_indirect(tcx, def_id, mir);
 
@@ -664,21 +672,15 @@ fn create_generator_resume_function<'a, 'tcx>(
     dump_mir(tcx, None, "generator_resume", &0, source, mir);
 }
 
-fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
-    let source_info = SourceInfo {
+fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo {
+    SourceInfo {
         span: mir.span,
         scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
+    }
+}
 
-    let return_block = BasicBlock::new(mir.basic_blocks().len());
-    mir.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: TerminatorKind::Return,
-        }),
-        is_cleanup: false,
-    });
+fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
+    let return_block = insert_return_block(mir);
 
     // Create a block to destroy an unresumed generators. This can only destroy upvars.
     let drop_clean = BasicBlock::new(mir.basic_blocks().len());
@@ -687,6 +689,7 @@ fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
         target: return_block,
         unwind: None,
     };
+    let source_info = source_info(mir);
     mir.basic_blocks_mut().push(BasicBlockData {
         statements: Vec::new(),
         terminator: Some(Terminator {
@@ -699,6 +702,46 @@ fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
     drop_clean
 }
 
+fn create_cases<'a, 'tcx, F>(mir: &mut Mir<'tcx>,
+                          transform: &TransformVisitor<'a, 'tcx>,
+                          target: F) -> Vec<(u32, BasicBlock)>
+    where F: Fn(&SuspensionPoint) -> Option<BasicBlock> {
+    let source_info = source_info(mir);
+
+    transform.suspension_points.iter().filter_map(|point| {
+        // Find the target for this suspension point, if applicable
+        target(point).map(|target| {
+            let block = BasicBlock::new(mir.basic_blocks().len());
+            let mut statements = Vec::new();
+
+            // Create StorageLive instructions for locals with live storage
+            for i in 0..(mir.local_decls.len()) {
+                let l = Local::new(i);
+                if point.storage_liveness.contains(&l) && !transform.remap.contains_key(&l) {
+                    statements.push(Statement {
+                        source_info,
+                        kind: StatementKind::StorageLive(l),
+                    });
+                }
+            }
+
+            // Then jump to the real target
+            mir.basic_blocks_mut().push(BasicBlockData {
+                statements,
+                terminator: Some(Terminator {
+                    source_info,
+                    kind: TerminatorKind::Goto {
+                        target,
+                    },
+                }),
+                is_cleanup: false,
+            });
+
+            (point.state, block)
+        })
+    }).collect()
+}
+
 impl MirPass for StateTransform {
     fn run_pass<'a, 'tcx>(&self,
                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -736,16 +779,11 @@ fn run_pass<'a, 'tcx>(&self,
 
         // Extract locals which are live across suspension point into `layout`
         // `remap` gives a mapping from local indices onto generator struct indices
-        let (remap, layout) = compute_layout(tcx, source, interior, mir);
+        // `storage_liveness` tells us which locals have live storage at suspension points
+        let (remap, layout, storage_liveness) = compute_layout(tcx, source, interior, mir);
 
         let state_field = mir.upvar_decls.len();
 
-        let mut bb_targets = HashMap::new();
-
-        // If we jump to the entry point, we should go to the initial 0 generator state.
-        // FIXME: Could this result in the need for destruction for state 0?
-        bb_targets.insert((BasicBlock::new(0), None), 0);
-
         // Run the transformation which converts Lvalues from Local to generator struct
         // accesses for locals in `remap`.
         // It also rewrites `return x` and `yield y` as writing a new generator state and returning
@@ -755,14 +793,10 @@ fn run_pass<'a, 'tcx>(&self,
             state_adt_ref,
             state_substs,
             remap,
-            bb_target_count: 2,
-            bb_targets,
+            storage_liveness,
+            suspension_points: Vec::new(),
             new_ret_local,
             state_field,
-
-            // For returns we will resume execution at the next added basic block.
-            // This happens in `insert_panic_on_resume_after_return`
-            return_block: BasicBlock::new(mir.basic_blocks().len()),
         };
         transform.visit_mir(mir);
 
@@ -773,9 +807,6 @@ fn run_pass<'a, 'tcx>(&self,
         mir.spread_arg = None;
         mir.generator_layout = Some(layout);
 
-        // Panic if we resumed after returning
-        insert_panic_on_resume_after_return(tcx, mir);
-
         // Insert `drop(generator_struct)` which is used to drop upvars for generators in
         // the unresumed (0) state.
         // This is expanded to a drop ladder in `elaborate_generator_drops`.
index 72e1fc34789540b7e055f4f4ae66da7ff69521ba..68140011e7ec3843136fa75f8c601f57ccd5e0a3 100644 (file)
@@ -13,6 +13,7 @@
 use back::linker::LinkerInfo;
 use back::symbol_export::ExportedSymbols;
 use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
+use rustc::dep_graph::DepGraph;
 use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
 use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
                              AllPasses, Sanitizer};
@@ -807,6 +808,7 @@ pub fn start_async_translation(sess: &Session,
 }
 
 fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
+                                              dep_graph: &DepGraph,
                                               compiled_modules: &CompiledModules,
                                               crate_output: &OutputFilenames) {
     if sess.opts.incremental.is_none() {
@@ -826,7 +828,11 @@ fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
             files.push((OutputType::Bitcode, path));
         }
 
-        save_trans_partition(sess, &module.name, module.symbol_name_hash, &files);
+        save_trans_partition(sess,
+                             dep_graph,
+                             &module.name,
+                             module.symbol_name_hash,
+                             &files);
     }
 }
 
@@ -1822,7 +1828,7 @@ pub struct OngoingCrateTranslation {
 }
 
 impl OngoingCrateTranslation {
-    pub fn join(self, sess: &Session) -> CrateTranslation {
+    pub fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
         self.shared_emitter_main.check(sess, true);
         let compiled_modules = match self.future.join() {
             Ok(compiled_modules) => compiled_modules,
@@ -1838,6 +1844,7 @@ pub fn join(self, sess: &Session) -> CrateTranslation {
         }
 
         copy_module_artifacts_into_incr_comp_cache(sess,
+                                                   dep_graph,
                                                    &compiled_modules,
                                                    &self.output_filenames);
         produce_final_output_artifacts(sess,
index 6062ac96ada787624dd189a60c0c0699c824db3b..ac3d575b64882de9516d892a213abd16fb46e293 100644 (file)
@@ -98,15 +98,6 @@ fn lang_items(tcx: TyCtxt) -> Vec<(ast::NodeId, Vec<ty::Variance>)> {
     let all = vec![
         (lang_items.phantom_data(), vec![ty::Covariant]),
         (lang_items.unsafe_cell_type(), vec![ty::Invariant]),
-
-        // Deprecated:
-        (lang_items.covariant_type(), vec![ty::Covariant]),
-        (lang_items.contravariant_type(), vec![ty::Contravariant]),
-        (lang_items.invariant_type(), vec![ty::Invariant]),
-        (lang_items.covariant_lifetime(), vec![ty::Covariant]),
-        (lang_items.contravariant_lifetime(), vec![ty::Contravariant]),
-        (lang_items.invariant_lifetime(), vec![ty::Invariant]),
-
         ];
 
     all.into_iter() // iterating over (Option<DefId>, Variance)
index d7ce5e262ce381b07cd0f412da0dff4b4ad80704..fd0167be2b98f4e57680b52f32ad9c48e4a7ae1b 100644 (file)
@@ -11,7 +11,6 @@
 use rustc_lint;
 use rustc_driver::{driver, target_features, abort_on_err};
 use rustc_driver::pretty::ReplaceBodyWithLoop;
-use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config};
 use rustc::hir::def_id::DefId;
 use rustc::hir::def::Def;
@@ -144,11 +143,9 @@ pub fn run_core(search_paths: SearchPaths,
                                                                false,
                                                                Some(codemap.clone()));
 
-    let dep_graph = DepGraph::new(false);
-    let _ignore = dep_graph.in_ignore();
     let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
-        sessopts, &dep_graph, cpath, diagnostic_handler, codemap
+        sessopts, cpath, diagnostic_handler, codemap,
     );
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
index 49d4bd2324033dbaeb3c3d327aee8c6afd96e7eb..500b75ec659a19236460c0c3f0fd9af508a39aee 100644 (file)
 
 use serialize::json::{ToJson, Json, as_json};
 use syntax::{abi, ast};
-use syntax::feature_gate::UnstableFeatures;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
 use rustc::hir;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc::session::config::nightly_options::is_nightly_build;
 use rustc_data_structures::flock;
 
 use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability, Span};
@@ -1764,9 +1762,13 @@ fn render_markdown(w: &mut fmt::Formatter,
                    prefix: &str,
                    scx: &SharedContext)
                    -> fmt::Result {
-    let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
     // We only emit warnings if the user has opted-in to Pulldown rendering.
     let output = if render_type == RenderType::Pulldown {
+        // Save the state of USED_ID_MAP so it only gets updated once even
+        // though we're rendering twice.
+        let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
+        let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
+        USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
         let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
         let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
         differences.retain(|s| {
@@ -1787,7 +1789,7 @@ fn render_markdown(w: &mut fmt::Formatter,
 
         pulldown_output
     } else {
-        hoedown_output
+        format!("{}", Markdown(md_text, RenderType::Hoedown))
     };
 
     write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
@@ -2192,14 +2194,9 @@ fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
 
 fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                  f: &clean::Function) -> fmt::Result {
-    // FIXME(#24111): remove when `const_fn` is stabilized
-    let vis_constness = match UnstableFeatures::from_environment() {
-        UnstableFeatures::Allow => f.constness,
-        _ => hir::Constness::NotConst
-    };
     let name_len = format!("{}{}{}{:#}fn {}{:#}",
                            VisSpace(&it.visibility),
-                           ConstnessSpace(vis_constness),
+                           ConstnessSpace(f.constness),
                            UnsafetySpace(f.unsafety),
                            AbiSpace(f.abi),
                            it.name.as_ref().unwrap(),
@@ -2209,7 +2206,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     write!(w, "{vis}{constness}{unsafety}{abi}fn \
                {name}{generics}{decl}{where_clause}</pre>",
            vis = VisSpace(&it.visibility),
-           constness = ConstnessSpace(vis_constness),
+           constness = ConstnessSpace(f.constness),
            unsafety = UnsafetySpace(f.unsafety),
            abi = AbiSpace(f.abi),
            name = it.name.as_ref().unwrap(),
@@ -2591,14 +2588,8 @@ fn method(w: &mut fmt::Formatter,
                 href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
             }
         };
-        // FIXME(#24111): remove when `const_fn` is stabilized
-        let vis_constness = if is_nightly_build() {
-            constness
-        } else {
-            hir::Constness::NotConst
-        };
         let mut head_len = format!("{}{}{:#}fn {}{:#}",
-                                   ConstnessSpace(vis_constness),
+                                   ConstnessSpace(constness),
                                    UnsafetySpace(unsafety),
                                    AbiSpace(abi),
                                    name,
@@ -2611,7 +2602,7 @@ fn method(w: &mut fmt::Formatter,
         };
         write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
                    {generics}{decl}{where_clause}",
-               ConstnessSpace(vis_constness),
+               ConstnessSpace(constness),
                UnsafetySpace(unsafety),
                AbiSpace(abi),
                href = href,
index 9b76a713b1769541561b0727fd74b2d3c463b6b9..95c0f5f5d63645a0834fee8d0e7bd07290a4ac83 100644 (file)
@@ -22,7 +22,6 @@
 
 use testing;
 use rustc_lint;
-use rustc::dep_graph::DepGraph;
 use rustc::hir;
 use rustc::hir::intravisit;
 use rustc::session::{self, CompileIncomplete, config};
@@ -83,11 +82,9 @@ pub fn run(input: &str,
     let handler =
         errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
 
-    let dep_graph = DepGraph::new(false);
-    let _ignore = dep_graph.in_ignore();
     let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
-        sessopts, &dep_graph, Some(input_path.clone()), handler, codemap.clone()
+        sessopts, Some(input_path.clone()), handler, codemap.clone(),
     );
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
@@ -100,7 +97,14 @@ pub fn run(input: &str,
     let krate = ReplaceBodyWithLoop::new().fold_crate(krate);
     let driver::ExpansionResult { defs, mut hir_forest, .. } = {
         phase_2_configure_and_expand(
-            &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
+            &sess,
+            &cstore,
+            krate,
+            None,
+            "rustdoc-test",
+            None,
+            MakeGlobMap::No,
+            |_| Ok(()),
         ).expect("phase_2_configure_and_expand aborted in rustdoc!")
     };
 
@@ -120,8 +124,6 @@ pub fn run(input: &str,
                                        render_type);
 
     {
-        let dep_graph = DepGraph::new(false);
-        let _ignore = dep_graph.in_ignore();
         let map = hir::map::map_crate(&mut hir_forest, defs);
         let krate = map.krate();
         let mut hir_collector = HirCollector {
@@ -237,10 +239,9 @@ fn drop(&mut self) {
     // Compile the code
     let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
 
-    let dep_graph = DepGraph::new(false);
     let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
-        sessopts, &dep_graph, None, diagnostic_handler, codemap
+        sessopts, None, diagnostic_handler, codemap,
     );
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
index a438b4afdd0c9f37679de65a647725e5bb9b3710..2a916b819cca32290a091321bc65d66ba533a262 100644 (file)
@@ -560,14 +560,26 @@ pub fn write(&mut self, write: bool) -> &mut OpenOptions {
     ///
     /// One maybe obvious note when using append-mode: make sure that all data
     /// that belongs together is written to the file in one operation. This
-    /// can be done by concatenating strings before passing them to `write()`,
+    /// can be done by concatenating strings before passing them to [`write()`],
     /// or using a buffered writer (with a buffer of adequate size),
-    /// and calling `flush()` when the message is complete.
+    /// and calling [`flush()`] when the message is complete.
     ///
     /// If a file is opened with both read and append access, beware that after
     /// opening, and after every write, the position for reading may be set at the
     /// end of the file. So, before writing, save the current position (using
-    /// `seek(SeekFrom::Current(0))`, and restore it before the next read.
+    /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`, and restore it before the next read.
+    ///
+    /// ## Note
+    ///
+    /// This function doesn't create the file if it doesn't exist. Use the [`create`]
+    /// method to do so.
+    ///
+    /// [`write()`]: ../../std/fs/struct.File.html#method.write
+    /// [`flush()`]: ../../std/fs/struct.File.html#method.flush
+    /// [`seek`]: ../../std/fs/struct.File.html#method.seek
+    /// [`SeekFrom`]: ../../std/io/enum.SeekFrom.html
+    /// [`Current`]: ../../std/io/enum.SeekFrom.html#variant.Current
+    /// [`create`]: #method.create
     ///
     /// # Examples
     ///
@@ -605,9 +617,12 @@ pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
     /// This option indicates whether a new file will be created if the file
     /// does not yet already exist.
     ///
-    /// In order for the file to be created, `write` or `append` access must
+    /// In order for the file to be created, [`write`] or [`append`] access must
     /// be used.
     ///
+    /// [`write`]: #method.write
+    /// [`append`]: #method.append
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -630,12 +645,15 @@ pub fn create(&mut self, create: bool) -> &mut OpenOptions {
     /// whether a file exists and creating a new one, the file may have been
     /// created by another process (a TOCTOU race condition / attack).
     ///
-    /// If `.create_new(true)` is set, `.create()` and `.truncate()` are
+    /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
     /// ignored.
     ///
     /// The file must be opened with write or append access in order to create
     /// a new file.
     ///
+    /// [`.create()`]: #method.create
+    /// [`.truncate()`]: #method.truncate
+    ///
     /// # Examples
     ///
     /// ```no_run
index 5467eff202b02847cd45ca92966ffbd7ce6df08e..943a83a95fb2333eba161c9e8fed1be74c391a04 100644 (file)
@@ -167,7 +167,7 @@ pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
     /// connection request.
     ///
     /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
-    #[unstable(feature = "tcpstream_connect_timeout", issue = "43079")]
+    #[stable(feature = "tcpstream_connect_timeout", since = "1.22.0")]
     pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
         net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream)
     }
index 35001833383c0253da750d37385d77e52cb42a0c..a8a242846d7cedb6522ec40e27a501d485adb573 100644 (file)
 /// {
 ///     let mut socket = UdpSocket::bind("127.0.0.1:34254")?;
 ///
-///     // read from the socket
+///     // Receives a single datagram message on the socket. If `buf` is too small to hold
+///     // the message, it will be cut off.
 ///     let mut buf = [0; 10];
 ///     let (amt, src) = socket.recv_from(&mut buf)?;
 ///
-///     // send a reply to the socket we received data from
+///     // Redeclare `buf` as slice of the received data and send reverse data back to origin.
 ///     let buf = &mut buf[..amt];
 ///     buf.reverse();
 ///     socket.send_to(buf, &src)?;
@@ -103,8 +104,12 @@ pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
         super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
     }
 
-    /// Receives data from the socket. On success, returns the number of bytes
-    /// read and the address from whence the data came.
+    /// Receives a single datagram message on the socket. On success, returns the number
+    /// of bytes read and the origin.
+    ///
+    /// The function must be called with valid byte array `buf` of sufficient size to
+    /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+    /// excess bytes may be discarded.
     ///
     /// # Examples
     ///
@@ -115,19 +120,25 @@ pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
     /// let mut buf = [0; 10];
     /// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf)
     ///                                         .expect("Didn't receive data");
+    /// let filled_buf = &mut buf[..number_of_bytes];
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
         self.0.recv_from(buf)
     }
 
-    /// Receives data from the socket, without removing it from the queue.
+    /// Receives a single datagram message on the socket, without removing it from the
+    /// queue. On success, returns the number of bytes read and the origin.
+    ///
+    /// The function must be called with valid byte array `buf` of sufficient size to
+    /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+    /// excess bytes may be discarded.
     ///
     /// Successive calls return the same data. This is accomplished by passing
     /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
     ///
-    /// On success, returns the number of bytes peeked and the address from
-    /// whence the data came.
+    /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+    /// synchronize IO events on one or more sockets.
     ///
     /// # Examples
     ///
@@ -138,6 +149,7 @@ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
     /// let mut buf = [0; 10];
     /// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf)
     ///                                         .expect("Didn't receive data");
+    /// let filled_buf = &mut buf[..number_of_bytes];
     /// ```
     #[stable(feature = "peek", since = "1.18.0")]
     pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
@@ -586,8 +598,11 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
     /// receive data from the specified address.
     ///
     /// If `addr` yields multiple addresses, `connect` will be attempted with
-    /// each of the addresses until a connection is successful. If none of
-    /// the addresses are able to be connected, the error returned from the
+    /// each of the addresses until the underlying OS function returns no
+    /// error. Note that usually, a successful `connect` call does not specify
+    /// that there is a remote server listening on the port, rather, such an
+    /// error would only be detected after the first send. If the OS returns an
+    /// error for each of the specified addresses, the error returned from the
     /// last connection attempt (the last address) is returned.
     ///
     /// # Examples
@@ -602,20 +617,10 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
     /// socket.connect("127.0.0.1:8080").expect("connect function failed");
     /// ```
     ///
-    /// Create a UDP socket bound to `127.0.0.1:3400` and connect the socket to
-    /// `127.0.0.1:8080`. If that connection fails, then the UDP socket will
-    /// connect to `127.0.0.1:8081`:
-    ///
-    /// ```no_run
-    /// use std::net::{SocketAddr, UdpSocket};
-    ///
-    /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
-    /// let connect_addrs = [
-    ///     SocketAddr::from(([127, 0, 0, 1], 8080)),
-    ///     SocketAddr::from(([127, 0, 0, 1], 8081)),
-    /// ];
-    /// socket.connect(&connect_addrs[..]).expect("connect function failed");
-    /// ```
+    /// Unlike in the TCP case, passing an array of addresses to the `connect`
+    /// function of a UDP socket is not a useful thing to do: The OS will be
+    /// unable to determine whether something is listening on the remote
+    /// address without the application sending data.
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
         super::each_addr(addr, |addr| self.0.connect(addr))
@@ -642,8 +647,12 @@ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.send(buf)
     }
 
-    /// Receives data on the socket from the remote address to which it is
-    /// connected.
+    /// Receives a single datagram message on the socket from the remote address to
+    /// which it is connected. On success, returns the number of bytes read.
+    ///
+    /// The function must be called with valid byte array `buf` of sufficient size to
+    /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+    /// excess bytes may be discarded.
     ///
     /// The [`connect`] method will connect this socket to a remote address. This
     /// method will fail if the socket is not connected.
@@ -659,7 +668,7 @@ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
     /// socket.connect("127.0.0.1:8080").expect("connect function failed");
     /// let mut buf = [0; 10];
     /// match socket.recv(&mut buf) {
-    ///     Ok(received) => println!("received {} bytes", received),
+    ///     Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
     ///     Err(e) => println!("recv function failed: {:?}", e),
     /// }
     /// ```
@@ -668,13 +677,25 @@ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
         self.0.recv(buf)
     }
 
-    /// Receives data on the socket from the remote address to which it is
-    /// connected, without removing that data from the queue. On success,
-    /// returns the number of bytes peeked.
+    /// Receives single datagram on the socket from the remote address to which it is
+    /// connected, without removing the message from input queue. On success, returns
+    /// the number of bytes peeked.
+    ///
+    /// The function must be called with valid byte array `buf` of sufficient size to
+    /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+    /// excess bytes may be discarded.
     ///
     /// Successive calls return the same data. This is accomplished by passing
     /// `MSG_PEEK` as a flag to the underlying `recv` system call.
     ///
+    /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+    /// synchronize IO events on one or more sockets.
+    ///
+    /// The [`connect`] method will connect this socket to a remote address. This
+    /// method will fail if the socket is not connected.
+    ///
+    /// [`connect`]: #method.connect
+    ///
     /// # Errors
     ///
     /// This method will fail if the socket is not connected. The `connect` method
index 72eed549f62a0b4e4f019051d440018007814428..b460bd90f173558f10ef3080b48c995529dc7cb5 100644 (file)
@@ -27,7 +27,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use sys::windows_ext as windows;
 
-#[cfg(any(dox, target_os = "linux"))]
+#[cfg(any(dox, target_os = "linux", target_os = "l4re"))]
 #[doc(cfg(target_os = "linux"))]
 pub mod linux;
 
index fe0427d4e5f9c0c86325450db4dc344e04e059c1..95439640f7cc5c5000fbf98091a29cdf84b733a7 100644 (file)
@@ -21,6 +21,7 @@
                                        target_arch = "s390x")),
           all(target_os = "android", any(target_arch = "aarch64",
                                          target_arch = "arm")),
+          all(target_os = "l4re", target_arch = "x86_64"),
           all(target_os = "fuchsia", target_arch = "aarch64")))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
 #[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
@@ -30,6 +31,7 @@
                                            target_arch = "s390x")),
               all(target_os = "android", any(target_arch = "aarch64",
                                              target_arch = "arm")),
+              all(target_os = "l4re", target_arch = "x86_64"),
               all(target_os = "fuchsia", target_arch = "aarch64"))))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
index b2c0e285f0663b2d856a06ef415ac87624696ecb..c4aad8d86f8b1f5e4b6fba452c4eb64e9476cf6d 100644 (file)
@@ -16,6 +16,8 @@
 use sys::{cvt, syscall};
 use time::Duration;
 
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
 pub struct Thread {
     id: usize,
 }
index 810d2d40c05f44f07b19b02fd133189a3dd83172..72169773df596ee977e384d37513e7515ecbe17b 100644 (file)
@@ -65,6 +65,7 @@ fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
           target_os = "solaris",
           target_os = "emscripten",
           target_os = "haiku",
+          target_os = "l4re",
           target_os = "fuchsia"))]
 mod imp {
     use os::unix::prelude::*;
index b9ea573b323d2ea8b63071ae76a69db31aa460e0..89a44b976578363f1d439d87cf0c0420c4dbd0d4 100644 (file)
@@ -38,10 +38,16 @@ pub const fn new() -> Condvar {
         Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) }
     }
 
-    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
+    #[cfg(any(target_os = "macos",
+              target_os = "ios",
+              target_os = "l4re",
+              target_os = "android"))]
     pub unsafe fn init(&mut self) {}
 
-    #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
+    #[cfg(not(any(target_os = "macos",
+                  target_os = "ios",
+                  target_os = "l4re",
+                  target_os = "android")))]
     pub unsafe fn init(&mut self) {
         use mem;
         let mut attr: libc::pthread_condattr_t = mem::uninitialized();
index eff3a8c2a34a4422f240f21641b3b5d9be053155..3d9a06bedd57cc74898803dc17764547c7e5ad6d 100644 (file)
@@ -182,3 +182,14 @@ pub mod os {
     pub const EXE_SUFFIX: &'static str = "";
     pub const EXE_EXTENSION: &'static str = "";
 }
+
+#[cfg(target_os = "l4re")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "l4re";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
index f50b093acc8482c068bdcd768463c1a61cfe83d2..5dafc3251e7551e10f6c68573b479a16cd2efbf6 100644 (file)
@@ -144,6 +144,7 @@ unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
                   target_os = "solaris",
                   target_os = "emscripten",
                   target_os = "fuchsia",
+                  target_os = "l4re",
                   target_os = "haiku")))]
     pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
@@ -155,6 +156,7 @@ pub fn set_cloexec(&self) -> io::Result<()> {
               target_os = "solaris",
               target_os = "emscripten",
               target_os = "fuchsia",
+              target_os = "l4re",
               target_os = "haiku"))]
     pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
index f94af4913324ff7e7b68c26230f712d640f799fa..13112fc1fa5904e6d6b4f8bfcda702893b2c056b 100644 (file)
 use sys::{cvt, cvt_r};
 use sys_common::{AsInner, FromInner};
 
-#[cfg(any(target_os = "linux", target_os = "emscripten"))]
+#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
 use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64};
 #[cfg(target_os = "android")]
 use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64,
            dirent as dirent64, open as open64};
 #[cfg(not(any(target_os = "linux",
               target_os = "emscripten",
+              target_os = "l4re",
               target_os = "android")))]
 use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
            ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
 #[cfg(not(any(target_os = "linux",
               target_os = "emscripten",
               target_os = "solaris",
+              target_os = "l4re",
               target_os = "fuchsia")))]
 use libc::{readdir_r as readdir64_r};
 
@@ -316,6 +318,7 @@ pub fn file_type(&self) -> io::Result<FileType> {
               target_os = "android",
               target_os = "solaris",
               target_os = "haiku",
+              target_os = "l4re",
               target_os = "fuchsia"))]
     pub fn ino(&self) -> u64 {
         self.entry.d_ino as u64
@@ -346,6 +349,7 @@ fn name_bytes(&self) -> &[u8] {
     #[cfg(any(target_os = "android",
               target_os = "linux",
               target_os = "emscripten",
+              target_os = "l4re",
               target_os = "haiku"))]
     fn name_bytes(&self) -> &[u8] {
         unsafe {
diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs
new file mode 100644 (file)
index 0000000..2121848
--- /dev/null
@@ -0,0 +1,441 @@
+// Copyright 2016-2017 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.
+
+macro_rules! unimpl {
+    () => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));)
+}
+
+pub mod net {
+    #![allow(warnings)]
+    use fmt;
+    use io;
+    use libc;
+    use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+    use sys_common::{AsInner, FromInner, IntoInner};
+    use sys::fd::FileDesc;
+    use time::Duration;
+
+
+    pub extern crate libc as netc;
+
+    pub struct Socket(FileDesc);
+    impl Socket {
+        pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result<Socket> {
+            unimpl!();
+        }
+
+        pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result<Socket> {
+            unimpl!();
+        }
+
+        pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> {
+            unimpl!();
+        }
+
+        pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t)
+                  -> io::Result<Socket> {
+            unimpl!();
+        }
+
+        pub fn duplicate(&self) -> io::Result<Socket> {
+            unimpl!();
+        }
+
+        pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn timeout(&self, _: libc::c_int) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn nodelay(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+            unimpl!();
+        }
+    }
+
+    impl AsInner<libc::c_int> for Socket {
+        fn as_inner(&self) -> &libc::c_int { self.0.as_inner() }
+    }
+
+    impl FromInner<libc::c_int> for Socket {
+        fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) }
+    }
+
+    impl IntoInner<libc::c_int> for Socket {
+        fn into_inner(self) -> libc::c_int { self.0.into_raw() }
+    }
+
+    pub struct TcpStream {
+        inner: Socket,
+    }
+
+    impl TcpStream {
+        pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
+            unimpl!();
+        }
+
+        pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+            unimpl!();
+        }
+
+        pub fn socket(&self) -> &Socket { &self.inner }
+
+        pub fn into_socket(self) -> Socket { self.inner }
+
+        pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn duplicate(&self) -> io::Result<TcpStream> {
+            unimpl!();
+        }
+
+        pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn nodelay(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn ttl(&self) -> io::Result<u32> {
+            unimpl!();
+        }
+
+        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+            unimpl!();
+        }
+
+        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+    }
+
+    impl FromInner<Socket> for TcpStream {
+        fn from_inner(socket: Socket) -> TcpStream {
+            TcpStream { inner: socket }
+        }
+    }
+
+    impl fmt::Debug for TcpStream {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "No networking support available on L4Re")
+        }
+    }
+
+    pub struct TcpListener {
+        inner: Socket,
+    }
+
+    impl TcpListener {
+        pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
+            unimpl!();
+        }
+
+        pub fn socket(&self) -> &Socket { &self.inner }
+
+        pub fn into_socket(self) -> Socket { self.inner }
+
+        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn duplicate(&self) -> io::Result<TcpListener> {
+            unimpl!();
+        }
+
+        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn ttl(&self) -> io::Result<u32> {
+            unimpl!();
+        }
+
+        pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn only_v6(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+            unimpl!();
+        }
+
+        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+    }
+
+    impl FromInner<Socket> for TcpListener {
+        fn from_inner(socket: Socket) -> TcpListener {
+            TcpListener { inner: socket }
+        }
+    }
+
+    impl fmt::Debug for TcpListener {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "No networking support available on L4Re.")
+        }
+    }
+
+    pub struct UdpSocket {
+        inner: Socket,
+    }
+
+    impl UdpSocket {
+        pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
+            unimpl!();
+        }
+
+        pub fn socket(&self) -> &Socket { &self.inner }
+
+        pub fn into_socket(self) -> Socket { self.inner }
+
+        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn duplicate(&self) -> io::Result<UdpSocket> {
+            unimpl!();
+        }
+
+        pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn broadcast(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+            unimpl!();
+        }
+
+        pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+                             -> io::Result<()> {
+                                 unimpl!();
+        }
+
+        pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+                             -> io::Result<()> {
+                                 unimpl!();
+        }
+
+        pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+                              -> io::Result<()> {
+                                  unimpl!();
+        }
+
+        pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+                              -> io::Result<()> {
+                                  unimpl!();
+        }
+
+        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn ttl(&self) -> io::Result<u32> {
+            unimpl!();
+        }
+
+        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+            unimpl!();
+        }
+
+        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
+            unimpl!();
+        }
+    }
+
+    impl FromInner<Socket> for UdpSocket {
+        fn from_inner(socket: Socket) -> UdpSocket {
+            UdpSocket { inner: socket }
+        }
+    }
+
+    impl fmt::Debug for UdpSocket {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "No networking support on L4Re available.")
+        }
+    }
+
+    pub struct LookupHost {
+        original: *mut libc::addrinfo,
+        cur: *mut libc::addrinfo,
+    }
+
+    impl Iterator for LookupHost {
+        type Item = SocketAddr;
+        fn next(&mut self) -> Option<SocketAddr> {
+            None
+        }
+    }
+
+    unsafe impl Sync for LookupHost {}
+    unsafe impl Send for LookupHost {}
+
+    pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
+        unimpl!();
+    }
+}
+
index 4393aedf162a3bf9b0d787a3e8e69d0f207d8e9e..1b3f1000b77bbdf681b31946e1cf482678305e21 100644 (file)
@@ -28,6 +28,7 @@
 #[cfg(all(not(dox), target_os = "solaris"))]   pub use os::solaris as platform;
 #[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform;
 #[cfg(all(not(dox), target_os = "fuchsia"))]   pub use os::fuchsia as platform;
+#[cfg(all(not(dox), target_os = "l4re"))]      pub use os::linux as platform;
 
 #[macro_use]
 pub mod weak;
 pub mod fs;
 pub mod memchr;
 pub mod mutex;
+#[cfg(not(target_os = "l4re"))]
 pub mod net;
+#[cfg(target_os = "l4re")]
+mod l4re;
+#[cfg(target_os = "l4re")]
+pub use self::l4re::net;
 pub mod os;
 pub mod os_str;
 pub mod path;
index 8e41fd009be675db4954e19aae6da513f546913f..5ef98d247105e6e1a36e9f59484bf76f4ac97aff 100644 (file)
 
 extern {
     #[cfg(not(target_os = "dragonfly"))]
-    #[cfg_attr(any(target_os = "linux", target_os = "emscripten", target_os = "fuchsia"),
+    #[cfg_attr(any(target_os = "linux",
+                   target_os = "emscripten",
+                   target_os = "fuchsia",
+                   target_os = "l4re"),
                link_name = "__errno_location")]
     #[cfg_attr(any(target_os = "bitrig",
                    target_os = "netbsd",
@@ -346,10 +349,10 @@ fn _get_next_image_info(team_id: i32, cookie: *mut i32,
     }
 }
 
-#[cfg(target_os = "fuchsia")]
+#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
 pub fn current_exe() -> io::Result<PathBuf> {
     use io::ErrorKind;
-    Err(io::Error::new(ErrorKind::Other, "Not yet implemented on fuchsia"))
+    Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))
 }
 
 pub struct Env {
index ae24021fb6c3a55ffd164def3156b96bc9721bd0..870db8200273eb84e543bbda841519eada1f46b3 100644 (file)
@@ -160,20 +160,22 @@ macro_rules! t {
             t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
         }
 
-        if let Some(u) = self.get_gid() {
-            t!(cvt(libc::setgid(u as gid_t)));
-        }
-        if let Some(u) = self.get_uid() {
-            // When dropping privileges from root, the `setgroups` call
-            // will remove any extraneous groups. If we don't call this,
-            // then even though our uid has dropped, we may still have
-            // groups that enable us to do super-user things. This will
-            // fail if we aren't root, so don't bother checking the
-            // return value, this is just done as an optimistic
-            // privilege dropping function.
-            let _ = libc::setgroups(0, ptr::null());
+        if cfg!(not(any(target_os = "l4re"))) {
+            if let Some(u) = self.get_gid() {
+                t!(cvt(libc::setgid(u as gid_t)));
+            }
+            if let Some(u) = self.get_uid() {
+                // When dropping privileges from root, the `setgroups` call
+                // will remove any extraneous groups. If we don't call this,
+                // then even though our uid has dropped, we may still have
+                // groups that enable us to do super-user things. This will
+                // fail if we aren't root, so don't bother checking the
+                // return value, this is just done as an optimistic
+                // privilege dropping function.
+                let _ = libc::setgroups(0, ptr::null());
 
-            t!(cvt(libc::setuid(u as uid_t)));
+                t!(cvt(libc::setuid(u as uid_t)));
+            }
         }
         if let Some(ref cwd) = *self.get_cwd() {
             t!(cvt(libc::chdir(cwd.as_ptr())));
index 40f1d6a6db15be67ed1664978fa0df604a46591a..6c4a332429646be75c156884d409d8c090c7bdb3 100644 (file)
 
 use sys_common::thread::*;
 
+#[cfg(not(target_os = "l4re"))]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+#[cfg(target_os = "l4re")]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
+
 pub struct Thread {
     id: libc::pthread_t,
 }
@@ -52,6 +57,7 @@ pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
         assert_eq!(libc::pthread_attr_init(&mut attr), 0);
 
         let stack_size = cmp::max(stack, min_stack_size(&attr));
+
         match pthread_attr_setstacksize(&mut attr,
                                         stack_size) {
             0 => {}
@@ -131,6 +137,7 @@ pub fn set_name(name: &CStr) {
     #[cfg(any(target_env = "newlib",
               target_os = "solaris",
               target_os = "haiku",
+              target_os = "l4re",
               target_os = "emscripten"))]
     pub fn set_name(_name: &CStr) {
         // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
@@ -226,7 +233,7 @@ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
     }
 
     #[cfg(any(target_os = "android", target_os = "freebsd",
-              target_os = "linux", target_os = "netbsd"))]
+              target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
     unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
         let mut ret = None;
         let mut attr: libc::pthread_attr_t = ::mem::zeroed();
@@ -328,7 +335,7 @@ pub unsafe fn current() -> Option<usize> {
     }
 
     #[cfg(any(target_os = "android", target_os = "freebsd",
-              target_os = "linux", target_os = "netbsd"))]
+              target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
     pub unsafe fn current() -> Option<usize> {
         let mut ret = None;
         let mut attr: libc::pthread_attr_t = ::mem::zeroed();
index 7dfcc996e18e2e8202b7f6c061800ea005356204..9535ddfe5cada5143c22cee3dbf9a1f9a48ba84a 100644 (file)
@@ -32,6 +32,7 @@
 pub type HANDLE = LPVOID;
 pub type HINSTANCE = HANDLE;
 pub type HMODULE = HINSTANCE;
+pub type HRESULT = LONG;
 pub type BOOL = c_int;
 pub type BYTE = u8;
 pub type BOOLEAN = BYTE;
@@ -197,6 +198,8 @@ fn clone(&self) -> Self { *self }
 pub const ERROR_IO_PENDING: DWORD = 997;
 pub const ERROR_TIMEOUT: DWORD = 0x5B4;
 
+pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
+
 pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
 
 pub const FACILITY_NT_BIT: DWORD = 0x1000_0000;
@@ -1163,8 +1166,8 @@ pub fn select(nfds: c_int,
                   timeout: *const timeval) -> c_int;
 }
 
-// Functions that aren't available on Windows XP, but we still use them and just
-// provide some form of a fallback implementation.
+// Functions that aren't available on every version of Windows that we support,
+// but we still use them and just provide some form of a fallback implementation.
 compat_fn! {
     kernel32:
 
@@ -1182,6 +1185,10 @@ pub fn GetFinalPathNameByHandleW(_hFile: HANDLE,
     pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL {
         SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
     }
+    pub fn SetThreadDescription(hThread: HANDLE,
+                                lpThreadDescription: LPCWSTR) -> HRESULT {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
+    }
     pub fn SetFileInformationByHandle(_hFile: HANDLE,
                     _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
                     _lpFileInformation: LPVOID,
index 2cdd86e88b0a074eb87125792b9f888aeb9eaaa3..c47baaa2434025fe4476fd8ac4b6dc3431c31dad 100644 (file)
 use sys_common::thread::*;
 use time::Duration;
 
+use super::to_u16s;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
 pub struct Thread {
     handle: Handle
 }
@@ -53,11 +57,12 @@ extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
         }
     }
 
-    pub fn set_name(_name: &CStr) {
-        // Windows threads are nameless
-        // The names in MSVC debugger are obtained using a "magic" exception,
-        // which requires a use of MS C++ extensions.
-        // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+    pub fn set_name(name: &CStr) {
+        if let Ok(utf8) = name.to_str() {
+            if let Ok(utf16) = to_u16s(utf8) {
+                unsafe { c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr()); };
+            };
+        };
     }
 
     pub fn join(self) {
index 30241819bd51201e0c71fbefda327a979705bcf2..d7654ce9300b377d124000a0c1de02dd92673a64 100644 (file)
 pub mod util;
 pub mod wtf8;
 
-#[cfg(target_os = "redox")]
+#[cfg(any(target_os = "redox", target_os = "l4re"))]
 pub use sys::net;
 
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "l4re")))]
 pub mod net;
 
 #[cfg(feature = "backtrace")]
index 1ca39ff9d4a1ce296117d6357987550c38e39d37..19dc841b9b5024961abb1eea38c84d22d1fc6693 100644 (file)
 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
           target_os = "ios", target_os = "macos",
           target_os = "openbsd", target_os = "netbsd",
-          target_os = "solaris", target_os = "haiku"))]
+          target_os = "solaris", target_os = "haiku", target_os = "l4re"))]
 use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
 #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
               target_os = "ios", target_os = "macos",
               target_os = "openbsd", target_os = "netbsd",
-              target_os = "solaris", target_os = "haiku")))]
+              target_os = "solaris", target_os = "haiku", target_os = "l4re")))]
 use sys::net::netc::IPV6_ADD_MEMBERSHIP;
 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
           target_os = "ios", target_os = "macos",
           target_os = "openbsd", target_os = "netbsd",
-          target_os = "solaris", target_os = "haiku"))]
+          target_os = "solaris", target_os = "haiku", target_os = "l4re"))]
 use sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
 #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
               target_os = "ios", target_os = "macos",
               target_os = "openbsd", target_os = "netbsd",
-              target_os = "solaris", target_os = "haiku")))]
+              target_os = "solaris", target_os = "haiku", target_os = "l4re")))]
 use sys::net::netc::IPV6_DROP_MEMBERSHIP;
 
 #[cfg(any(target_os = "linux", target_os = "android",
index 3ee160da5fa5b7876ab1a2c957b77c9cc3aa75f8..87fb34a9dec06459f95806377a451db8bbc27648 100644 (file)
@@ -8,9 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use env;
 use alloc::boxed::FnBox;
 use libc;
+use sync::atomic::{self, Ordering};
 use sys::stack_overflow;
+use sys::thread as imp;
 
 pub unsafe fn start_thread(main: *mut libc::c_void) {
     // Next, set up our stack overflow handler which may get triggered if we run
@@ -20,3 +23,18 @@ pub unsafe fn start_thread(main: *mut libc::c_void) {
     // Finally, let's run some code.
     Box::from_raw(main as *mut Box<FnBox()>)()
 }
+
+pub fn min_stack() -> usize {
+    static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+    match MIN.load(Ordering::SeqCst) {
+        0 => {}
+        n => return n - 1,
+    }
+    let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
+    let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE);
+
+    // 0 is our sentinel value, so ensure that we'll never see 0 after
+    // initialization has run
+    MIN.store(amt + 1, Ordering::SeqCst);
+    amt
+}
index daa0c15920b666703f323463a8952a5e753d937e..a391c7cc6ef0c959c2e25eaf0bddf175cbb59cec 100644 (file)
@@ -8,27 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use env;
 use fmt;
 use io::prelude::*;
-use sync::atomic::{self, Ordering};
 use sys::stdio::Stderr;
 use thread;
 
-pub fn min_stack() -> usize {
-    static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
-    match MIN.load(Ordering::SeqCst) {
-        0 => {}
-        n => return n - 1,
-    }
-    let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
-    let amt = amt.unwrap_or(2 * 1024 * 1024);
-    // 0 is our sentinel value, so ensure that we'll never see 0 after
-    // initialization has run
-    MIN.store(amt + 1, Ordering::SeqCst);
-    amt
-}
-
 pub fn dumb_print(args: fmt::Arguments) {
     let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
 }
index 4912ff93abdb389c19fc458398234220fd0c4b35..ca01eaefcaef4c8ac7ebb4a7b453d3e2f4390429 100644 (file)
 use sys::thread as imp;
 use sys_common::mutex;
 use sys_common::thread_info;
-use sys_common::util;
+use sys_common::thread;
 use sys_common::{AsInner, IntoInner};
 use time::Duration;
 
@@ -374,7 +374,7 @@ pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
     {
         let Builder { name, stack_size } = self;
 
-        let stack_size = stack_size.unwrap_or_else(util::min_stack);
+        let stack_size = stack_size.unwrap_or_else(thread::min_stack);
 
         let my_thread = Thread::new(name);
         let their_thread = my_thread.clone();
index 3301a7388c55bb04005cfe5c055dbe21cacb0a8f..cd1a7e7b794ba16578b910363f981734eebb08ef 100644 (file)
@@ -481,6 +481,12 @@ fn dummy_arg(span: Span) -> Arg {
     Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum TokenExpectType {
+    Expect,
+    NoExpect,
+}
+
 impl<'a> Parser<'a> {
     pub fn new(sess: &'a ParseSess,
                tokens: TokenStream,
@@ -797,6 +803,23 @@ fn expect_and(&mut self) -> PResult<'a, ()> {
         }
     }
 
+    /// Expect and consume an `|`. If `||` is seen, replace it with a single
+    /// `|` and continue. If an `|` is not seen, signal an error.
+    fn expect_or(&mut self) -> PResult<'a, ()> {
+        self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or)));
+        match self.token {
+            token::BinOp(token::Or) => {
+                self.bump();
+                Ok(())
+            }
+            token::OrOr => {
+                let span = self.span.with_lo(self.span.lo() + BytePos(1));
+                Ok(self.bump_with(token::BinOp(token::Or), span))
+            }
+            _ => self.unexpected()
+        }
+    }
+
     pub fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
         match suffix {
             None => {/* everything ok */}
@@ -946,6 +969,7 @@ pub fn eat_to_tokens(&mut self, kets: &[&token::Token]) {
 
         self.parse_seq_to_before_tokens(kets,
                                         SeqSep::none(),
+                                        TokenExpectType::Expect,
                                         |p| Ok(p.parse_token_tree()),
                                         |mut e| handler.cancel(&mut e));
     }
@@ -975,13 +999,14 @@ pub fn parse_seq_to_before_end<T, F>(&mut self,
                                          -> Vec<T>
         where F: FnMut(&mut Parser<'a>) -> PResult<'a,  T>
     {
-        self.parse_seq_to_before_tokens(&[ket], sep, f, |mut e| e.emit())
+        self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f, |mut e| e.emit())
     }
 
     // `fe` is an error handler.
     fn parse_seq_to_before_tokens<T, F, Fe>(&mut self,
                                             kets: &[&token::Token],
                                             sep: SeqSep,
+                                            expect: TokenExpectType,
                                             mut f: F,
                                             mut fe: Fe)
                                             -> Vec<T>
@@ -1005,7 +1030,12 @@ fn parse_seq_to_before_tokens<T, F, Fe>(&mut self,
                     }
                 }
             }
-            if sep.trailing_sep_allowed && kets.iter().any(|k| self.check(k)) {
+            if sep.trailing_sep_allowed && kets.iter().any(|k| {
+                match expect {
+                    TokenExpectType::Expect => self.check(k),
+                    TokenExpectType::NoExpect => self.token == **k,
+                }
+            }) {
                 break;
             }
 
@@ -4694,12 +4724,14 @@ fn parse_fn_block_decl(&mut self) -> PResult<'a, P<FnDecl>> {
                 Vec::new()
             } else {
                 self.expect(&token::BinOp(token::Or))?;
-                let args = self.parse_seq_to_before_end(
-                    &token::BinOp(token::Or),
+                let args = self.parse_seq_to_before_tokens(
+                    &[&token::BinOp(token::Or), &token::OrOr],
                     SeqSep::trailing_allowed(token::Comma),
-                    |p| p.parse_fn_block_arg()
+                    TokenExpectType::NoExpect,
+                    |p| p.parse_fn_block_arg(),
+                    |mut e| e.emit()
                 );
-                self.expect(&token::BinOp(token::Or))?;
+                self.expect_or()?;
                 args
             }
         };
index cba5c812b07ce94b46dc8aa9b21fb8781b94680f..27fbca19dcc4ca3a0211eb262ae3885df99ceb19 100644 (file)
@@ -434,6 +434,12 @@ fn from(span: Span) -> MultiSpan {
     }
 }
 
+impl From<Vec<Span>> for MultiSpan {
+    fn from(spans: Vec<Span>) -> MultiSpan {
+        MultiSpan::from_spans(spans)
+    }
+}
+
 pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
 
 /// Identifies an offset of a multi-byte character in a FileMap
index 9c8cfc0ab208c9fdbeafb5cd5effaf77230030c4..1941d1bc7be1b6c3bc9a61090af46bbdd68cf24d 100644 (file)
@@ -30,8 +30,8 @@ fn main() {
 //         StorageLive(_2);
 //         _2 = &'10_1rs _1;
 //         _0 = ();
-//         StorageDead(_2);
 //         EndRegion('10_1rs);
+//         StorageDead(_2);
 //         StorageDead(_1);
 //         return;
 //     }
index 6a4e209a14b7fe360cc7a34528c66f359cf4ddb5..d8dd4aeadf495008f1d21bb6f010c899ddc9b955 100644 (file)
@@ -46,8 +46,8 @@ fn main() {
 //     bb2: {
 //         _0 = ();
 //         StorageDead(_5);
-//         StorageDead(_3);
 //         EndRegion('23_1rs);
+//         StorageDead(_3);
 //         StorageDead(_2);
 //         return;
 //     }
@@ -56,10 +56,10 @@ fn main() {
 //         StorageLive(_7);
 //         _7 = &'23_3rs _2;
 //         _1 = ();
-//         StorageDead(_7);
 //         EndRegion('23_3rs);
-//         StorageDead(_3);
+//         StorageDead(_7);
 //         EndRegion('23_1rs);
+//         StorageDead(_3);
 //         StorageDead(_2);
 //         goto -> bb1;
 //     }
index cb1d45e37c83405f3497ba5503d543f66b50fef3..e404af838cef44a8247ee2823907998df0c98fed 100644 (file)
@@ -49,8 +49,8 @@ fn main() {
 //     bb2: {
 //         _0 = ();
 //         StorageDead(_5);
-//         StorageDead(_3);
 //         EndRegion('26_1rs);
+//         StorageDead(_3);
 //         StorageDead(_1);
 //         return;
 //     }
@@ -60,10 +60,10 @@ fn main() {
 //         StorageLive(_7);
 //         _7 = &'26_3rs _1;
 //         _2 = ();
-//         StorageDead(_7);
 //         EndRegion('26_3rs);
-//         StorageDead(_3);
+//         StorageDead(_7);
 //         EndRegion('26_1rs);
+//         StorageDead(_3);
 //         goto -> bb1;
 //     }
 // END rustc.node4.SimplifyCfg-qualify-consts.after.mir
index b714b6bc55b2408360f6ae7605a362bb01ab1c23..d51c627d14b2380314dbf6dbe8b0f8670954ddcf 100644 (file)
@@ -53,10 +53,10 @@ fn foo(i: i32) {
 //         StorageLive(_6);
 //         _6 = &'26_4rs _2;
 //         _0 = ();
-//         StorageDead(_6);
 //         EndRegion('26_4rs);
-//         StorageDead(_3);
+//         StorageDead(_6);
 //         EndRegion('26_2rs);
+//         StorageDead(_3);
 //         StorageDead(_2);
 //         drop(_1) -> bb4;
 //     }
index a4c53675b9c3a19218492438244b28ec01f11a6e..6299ec3815cd1625f3573e77c327f0e923944d6c 100644 (file)
@@ -44,8 +44,8 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         _2 = const foo(_3) -> [return: bb1, unwind: bb3];
 //     }
 //     bb1: {
-//         StorageDead(_3);
 //         EndRegion('14s);
+//         StorageDead(_3);
 //         _0 = ();
 //         drop(_1) -> bb4;
 //     }
index daa94769430df7930cd3735ce064c4d22c54a239..13ab3e4f2dd2a0c5dc0b2c99597de93a8b566ce8 100644 (file)
@@ -44,8 +44,8 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         _2 = const foo(_3) -> [return: bb1, unwind: bb3];
 //     }
 //     bb1: {
-//         StorageDead(_3);
 //         EndRegion('19s);
+//         StorageDead(_3);
 //         _0 = ();
 //         drop(_1) -> bb4;
 //     }
@@ -75,8 +75,8 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         _3 = ((*_2).0: i32);
 //         _0 = _3;
 //         StorageDead(_3);
-//         StorageDead(_2);
 //         EndRegion('15_0rs);
+//         StorageDead(_2);
 //         return;
 //     }
 // END rustc.node22.SimplifyCfg-qualify-consts.after.mir
index 9feacd04fe0fabdb312b4661731fb6b74a44562c..826d3749167d30c2b2d182250420c68701a2883c 100644 (file)
@@ -84,8 +84,8 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         _3 = ((*_2).0: i32);
 //         _0 = _3;
 //         StorageDead(_3);
-//         StorageDead(_2);
 //         EndRegion('15_0rs);
+//         StorageDead(_2);
 //         drop(_1) -> bb1;
 //     }
 //     bb1: {
index 30dda7a4062601b428b2fe3cc66c3d66f6299694..6438484fcfae41a1651271b39b1086b3a676353b 100644 (file)
@@ -50,8 +50,8 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //    bb1: {
 //        StorageDead(_4);
 //        _0 = ();
-//        StorageDead(_2);
 //        EndRegion('21_1rs);
+//        StorageDead(_2);
 //        drop(_1) -> bb4;
 //    }
 //    bb2: {
index bbfdc0e77a8d6842f5f9865001c71b8c04aea935..59d5d934391e94b49719cd99c587d44ed851aa08 100644 (file)
@@ -42,7 +42,7 @@ fn main() {
 //     let mut _0: ();
 //     let mut _1: bool;
 //     let _2: i32;
-//     let mut _4: &'13_0rs i32;
+//     let mut _4: &'33_0rs i32;
 //     let mut _3: ();
 //     let mut _5: !;
 //     let mut _6: ();
@@ -67,15 +67,15 @@ fn main() {
 //    bb2: {
 //        _0 = ();
 //        StorageDead(_7);
+//        EndRegion('33_0rs);
 //        StorageDead(_4);
-//        EndRegion('13_0rs);
 //        StorageDead(_2);
 //        StorageDead(_1);
 //        return;
 //    }
 //
 //    bb3: {
-//        _4 = &'13_0rs _2;
+//        _4 = &'33_0rs _2;
 //        _6 = ();
 //        StorageDead(_7);
 //        _1 = const true;
@@ -83,3 +83,4 @@ fn main() {
 //        goto -> bb1;
 //    }
 // }
+// END rustc.node4.SimplifyCfg-qualify-consts.after.mir
diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs
new file mode 100644 (file)
index 0000000..8f9dd79
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions
+// ignore-tidy-linelength
+
+// This test models a scenario with a cyclic reference. Rust obviously
+// needs to handle such cases.
+//
+// The interesting part about this test is that such case shows that
+// one cannot generally force all references to be dead before you hit
+// their EndRegion; at least, not without breaking the more important
+// property that all borrowed storage locations have their regions
+// ended strictly before their StorageDeads. (This test was inspired
+// by discussion on Issue #43481.)
+
+use std::cell::Cell;
+
+struct S<'a> {
+    r: Cell<Option<&'a S<'a>>>,
+}
+
+fn main() {
+    loop {
+        let x = S { r: Cell::new(None) };
+        x.r.set(Some(&x));
+        if query() { break; }
+        x.r.set(Some(&x));
+    }
+}
+
+fn query() -> bool { true }
+
+// END RUST SOURCE
+// START rustc.node16.SimplifyCfg-qualify-consts.after.mir
+// fn main() -> () {
+//     let mut _0: ();
+//     scope 1 {
+//         let _2: S<'35_0rs>;
+//     }
+//     let mut _1: ();
+//     let mut _3: std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>;
+//     let mut _4: std::option::Option<&'35_0rs S<'35_0rs>>;
+//     let mut _5: ();
+//     let mut _6: &'16s std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>;
+//     let mut _7: std::option::Option<&'35_0rs S<'35_0rs>>;
+//     let mut _8: &'35_0rs S<'35_0rs>;
+//     let mut _9: &'35_0rs S<'35_0rs>;
+//     let mut _10: ();
+//     let mut _11: bool;
+//     let mut _12: !;
+//     let mut _13: ();
+//     let mut _14: &'33s std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>;
+//     let mut _15: std::option::Option<&'35_0rs S<'35_0rs>>;
+//     let mut _16: &'35_0rs S<'35_0rs>;
+//     let mut _17: &'35_0rs S<'35_0rs>;
+//     bb0: {
+//         goto -> bb1;
+//     }
+//     bb1: {
+//         StorageLive(_2);
+//         StorageLive(_3);
+//         StorageLive(_4);
+//         _4 = std::option::Option<&'35_0rs S<'35_0rs>>::None;
+//         _3 = const <std::cell::Cell<T>>::new(_4) -> bb2;
+//     }
+//     bb2: {
+//         StorageDead(_4);
+//         _2 = S<'35_0rs> { r: _3 };
+//         StorageDead(_3);
+//         StorageLive(_6);
+//         _6 = &'16s (_2.0: std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>);
+//         StorageLive(_7);
+//         StorageLive(_8);
+//         StorageLive(_9);
+//         _9 = &'35_0rs _2;
+//         _8 = &'35_0rs (*_9);
+//         _7 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(_8,);
+//         StorageDead(_8);
+//         _5 = const <std::cell::Cell<T>>::set(_6, _7) -> bb3;
+//     }
+//     bb3: {
+//         EndRegion('16s);
+//         StorageDead(_7);
+//         StorageDead(_6);
+//         StorageDead(_9);
+//         StorageLive(_11);
+//         _11 = const query() -> bb4;
+//     }
+//     bb4: {
+//         switchInt(_11) -> [0u8: bb6, otherwise: bb5];
+//     }
+//     bb5: {
+//         _0 = ();
+//         StorageDead(_11);
+//         EndRegion('35_0rs);
+//         StorageDead(_2);
+//         return;
+//     }
+//     bb6: {
+//         _10 = ();
+//         StorageDead(_11);
+//         StorageLive(_14);
+//         _14 = &'33s (_2.0: std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>);
+//         StorageLive(_15);
+//         StorageLive(_16);
+//         StorageLive(_17);
+//         _17 = &'35_0rs _2;
+//         _16 = &'35_0rs (*_17);
+//         _15 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(_16,);
+//         StorageDead(_16);
+//         _13 = const <std::cell::Cell<T>>::set(_14, _15) -> bb7;
+//     }
+//     bb7: {
+//         EndRegion('33s);
+//         StorageDead(_15);
+//         StorageDead(_14);
+//         StorageDead(_17);
+//         _1 = ();
+//         EndRegion('35_0rs);
+//         StorageDead(_2);
+//         goto -> bb1;
+//     }
+// }
+// END rustc.node16.SimplifyCfg-qualify-consts.after.mir
diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs
new file mode 100644 (file)
index 0000000..1f9ad98
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions
+// ignore-tidy-linelength
+
+// A scenario with significant destruction code extents (which have
+// suffix "dce" in current `-Z identify_regions` rendering).
+
+#![feature(generic_param_attrs)]
+#![feature(dropck_eyepatch)]
+
+fn main() {
+    // Since the second param to `D1` is may_dangle, it is legal for
+    // the region of that parameter to end before the drop code for D1
+    // is executed.
+    (D1(&S1("ex1"), &S1("dang1"))).0;
+}
+
+#[derive(Debug)]
+struct S1(&'static str);
+
+#[derive(Debug)]
+struct D1<'a, 'b>(&'a S1, &'b S1);
+
+// The `#[may_dangle]` means that references of type `&'b _` may be
+// invalid during the execution of this destructor; i.e. in this case
+// the destructor code is not allowed to read or write `*self.1`, while
+// it can read/write `*self.0`.
+unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
+    fn drop(&mut self) {
+        println!("D1({:?}, _)", self.0);
+    }
+}
+
+// Notes on the MIR output below:
+//
+// 1. The `EndRegion('10s)` is allowed to precede the `drop(_3)`
+//    solely because of the #[may_dangle] mentioned above.
+//
+// 2. Regarding the occurrence of `EndRegion('12ds)` *after* `StorageDead(_6)`
+//    (where we have borrows `&'12ds _6`): Eventually:
+//
+//    i. this code should be rejected (by mir-borrowck), or
+//
+//    ii. the MIR code generation should be changed so that the
+//        EndRegion('12ds)` precedes `StorageDead(_6)` in the
+//        control-flow.  (Note: arielb1 views drop+storagedead as one
+//        unit, and does not see this option as a useful avenue to
+//        explore.), or
+//
+//    iii. the presence of EndRegion should be made irrelevant by a
+//        transformation encoding the effects of rvalue-promotion.
+//        This may be the simplest and most-likely option; note in
+//        particular that `StorageDead(_6)` goes away below in
+//        rustc.node4.QualifyAndPromoteConstants.after.mir
+
+// END RUST SOURCE
+
+// START rustc.node4.QualifyAndPromoteConstants.before.mir
+// fn main() -> () {
+//     let mut _0: ();
+//     let mut _1: &'12ds S1;
+//     let mut _2: &'12ds S1;
+//     let mut _3: D1<'12ds, '10s>;
+//     let mut _4: &'12ds S1;
+//     let mut _5: &'12ds S1;
+//     let mut _6: S1;
+//     let mut _7: &'10s S1;
+//     let mut _8: &'10s S1;
+//     let mut _9: S1;
+//
+//     bb0: {
+//         StorageLive(_2);
+//         StorageLive(_3);
+//         StorageLive(_4);
+//         StorageLive(_5);
+//         StorageLive(_6);
+//         _6 = S1::{{constructor}}(const "ex1",);
+//         _5 = &'12ds _6;
+//         _4 = &'12ds (*_5);
+//         StorageLive(_7);
+//         StorageLive(_8);
+//         StorageLive(_9);
+//         _9 = S1::{{constructor}}(const "dang1",);
+//         _8 = &'10s _9;
+//         _7 = &'10s (*_8);
+//         _3 = D1<'12ds, '10s>::{{constructor}}(_4, _7);
+//         EndRegion('10s);
+//         StorageDead(_7);
+//         StorageDead(_4);
+//         _2 = (_3.0: &'12ds S1);
+//         _1 = _2;
+//         StorageDead(_2);
+//         drop(_3) -> bb1;
+//     }
+//
+//     bb1: {
+//         StorageDead(_3);
+//         StorageDead(_8);
+//         StorageDead(_9);
+//         StorageDead(_5);
+//         StorageDead(_6);
+//         EndRegion('12ds);
+//         _0 = ();
+//         return;
+//     }
+// }
+// END rustc.node4.QualifyAndPromoteConstants.before.mir
+
+// START rustc.node4.QualifyAndPromoteConstants.after.mir
+// fn main() -> () {
+//     let mut _0: ();
+//     let mut _1: &'12ds S1;
+//     let mut _2: &'12ds S1;
+//     let mut _3: D1<'12ds, '10s>;
+//     let mut _4: &'12ds S1;
+//     let mut _5: &'12ds S1;
+//     let mut _6: S1;
+//     let mut _7: &'10s S1;
+//     let mut _8: &'10s S1;
+//     let mut _9: S1;
+//
+//     bb0: {
+//         StorageLive(_2);
+//         StorageLive(_3);
+//         StorageLive(_4);
+//         StorageLive(_5);
+//         _5 = promoted1;
+//         _4 = &'12ds (*_5);
+//         StorageLive(_7);
+//         StorageLive(_8);
+//         _8 = promoted0;
+//         _7 = &'10s (*_8);
+//         _3 = D1<'12ds, '10s>::{{constructor}}(_4, _7);
+//         EndRegion('10s);
+//         StorageDead(_7);
+//         StorageDead(_4);
+//         _2 = (_3.0: &'12ds S1);
+//         _1 = _2;
+//         StorageDead(_2);
+//         drop(_3) -> bb1;
+//     }
+//
+//     bb1: {
+//         StorageDead(_3);
+//         StorageDead(_8);
+//         StorageDead(_5);
+//         EndRegion('12ds);
+//         _0 = ();
+//         return;
+//     }
+// }
+// END rustc.node4.QualifyAndPromoteConstants.after.mir
index 842bc8374b6fb4a40adae0afa45c5cc25ebc7186..ec044225b83e8b2f7bd5d92d55774ab28d5850b5 100644 (file)
@@ -68,8 +68,8 @@ fn main() {
 //         _5 = (*_4);
 //         _0 = _5;
 //         StorageDead(_5);
-//         StorageDead(_4);
 //         EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 })));
+//         StorageDead(_4);
 //         StorageDead(_3);
 //         return;
 //     }
index 4bebc74ae460bfcd6eb011c0e871984e2bf33ec6..ff0c781d1e3bb805db9e87279fe1073de399e34d 100644 (file)
@@ -54,8 +54,8 @@ fn main() {
 //         _5 = &ReErased mut (*_3);
 //         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(9)))]);
 //         _4 = _5 as *mut i32 (Misc);
-//         StorageDead(_5);
 //         EndRegion(ReScope(Node(ItemLocalId(9))));
+//         StorageDead(_5);
 //         Validate(Release, [_0: bool, _4: *mut i32]);
 //         _0 = const write_42(_4) -> bb1;
 //     }
index 2e3fb785748f3f5345aa01515a11f17b1272fc44..461df49b468f94dca3cfc47f0ced18404da9b32a 100644 (file)
@@ -58,9 +58,8 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
     opts.maybe_sysroot = Some(sysroot);
 
     let descriptions = Registry::new(&rustc::DIAGNOSTICS);
-    let dep_graph = DepGraph::new(opts.build_dep_graph());
     let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
-    let sess = build_session(opts, &dep_graph, None, descriptions);
+    let sess = build_session(opts, None, descriptions);
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     (sess, cstore)
diff --git a/src/test/run-pass/closure-returning-closure.rs b/src/test/run-pass/closure-returning-closure.rs
new file mode 100644 (file)
index 0000000..2c00f77
--- /dev/null
@@ -0,0 +1,14 @@
+// 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.
+
+fn main() {
+    let f = |_||x, y| x+y;
+    assert_eq!(f(())(1, 2), 3);
+}
diff --git a/src/test/run-pass/generator/match-bindings.rs b/src/test/run-pass/generator/match-bindings.rs
new file mode 100644 (file)
index 0000000..9c6b057
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+enum Enum {
+    A(String),
+    B
+}
+
+fn main() {
+    || {
+        loop {
+            if let true = true {
+                match Enum::A(String::new()) {
+                    Enum::A(_var) => {}
+                    Enum::B => {}
+                }
+            }
+            yield;
+        }
+    };
+}
\ No newline at end of file
diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs
new file mode 100644 (file)
index 0000000..c323681
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> '
+/// foo
+pub const fn bar() -> usize {
+    2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method"]' 'const fn new()'
+pub struct Foo(usize);
+
+impl Foo {
+    pub const fn new() -> Foo { Foo(0) }
+}
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr
new file mode 100644 (file)
index 0000000..b159e14
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-4.rs:12:13
+   |
+11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+   |                     ---                 --- these references are declared with different lifetimes...
+12 |     z.push((x,y));
+   |             ^ ...but data flows into `z` here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-4.rs:12:15
+   |
+11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+   |                         ---                  --- these references are declared with different lifetimes...
+12 |     z.push((x,y));
+   |               ^ ...but data flows into `z` here
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs
new file mode 100644 (file)
index 0000000..606e611
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+struct Ref<'a, 'b> {
+    a: &'a u32,
+    b: &'b u32,
+}
+
+fn foo(mut x: Ref) {
+    x.a = x.b;
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr
new file mode 100644 (file)
index 0000000..689a1ac
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:11
+   |
+15 | fn foo(mut x: Ref) {
+   |               ---
+   |               |
+   |               this type was declared with multiple lifetimes...
+16 |     x.a = x.b;
+   |           ^^^ ...but data with one lifetime flows into the other here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs
new file mode 100644 (file)
index 0000000..4933dbb
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 }
+
+fn foo(mut y: Ref, x: &u32) {
+    y.b = x;
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
new file mode 100644 (file)
index 0000000..40f026b
--- /dev/null
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:11
+   |
+13 | fn foo(mut y: Ref, x: &u32) {
+   |               ---     ---- these two types are declared with different lifetimes...
+14 |     y.b = x;
+   |           ^ ...but data from `x` flows into `y` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs
new file mode 100644 (file)
index 0000000..9220c34
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
+  y.push(z);
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr
new file mode 100644 (file)
index 0000000..adfc4dc
--- /dev/null
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:10
+   |
+10 | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
+   |                               ---      --- these two types are declared with different lifetimes...
+11 |   y.push(z);
+   |          ^ ...but data from `z` flows into `y` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs
new file mode 100644 (file)
index 0000000..78a6ad5
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+fn foo(x:Box<Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
+  y.push(z);
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr
new file mode 100644 (file)
index 0000000..ce766b2
--- /dev/null
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:10
+   |
+10 | fn foo(x:Box<Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
+   |                 ---  --- these two types are declared with different lifetimes...
+11 |   y.push(z);
+   |          ^ ...but data from `z` flows into `y` here
+
+error: aborting due to previous error
+
index e759e0bc13ac1eac340d4956e06f88a36f9d84ac..e57c105008ade1a337ba612173813ca5ccb11b6c 100644 (file)
@@ -8,5 +8,5 @@ license = "MIT/Apache-2.0"
 clap = "2.25.0"
 
 [dependencies.mdbook]
-version = "0.0.22"
+version = "0.0.25"
 default-features = false
index 41e88aa245f42e55efc94f0a3581bb30671be8cf..a0c3e811a7aa2cc5b69c177f6e08ef11db258672 100644 (file)
 extern crate clap;
 
 use std::env;
-use std::error::Error;
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 
 use clap::{App, ArgMatches, SubCommand, AppSettings};
 
 use mdbook::MDBook;
+use mdbook::errors::Result;
 
 fn main() {
     let d_message = "-d, --dest-dir=[dest-dir]
@@ -49,34 +49,21 @@ fn main() {
         ::std::process::exit(101);
     }
 }
-
 // Build command implementation
-fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
-    let book = build_mdbook_struct(args);
+pub fn build(args: &ArgMatches) -> Result<()> {
+    let book_dir = get_book_dir(args);
+    let book = MDBook::new(&book_dir).read_config()?;
 
     let mut book = match args.value_of("dest-dir") {
-        Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
-        None => book
+        Some(dest_dir) => book.with_destination(dest_dir),
+        None => book,
     };
 
-    try!(book.build());
+    book.build()?;
 
     Ok(())
 }
 
-fn build_mdbook_struct(args: &ArgMatches) -> mdbook::MDBook {
-    let book_dir = get_book_dir(args);
-    let mut book = MDBook::new(&book_dir).read_config();
-
-    // By default mdbook will attempt to create non-existent files referenced
-    // from SUMMARY.md files. This is problematic on CI where we mount the
-    // source directory as readonly. To avoid any issues, we'll disabled
-    // mdbook's implicit file creation feature.
-    book.create_missing = false;
-
-    book
-}
-
 fn get_book_dir(args: &ArgMatches) -> PathBuf {
     if let Some(dir) = args.value_of("dir") {
         // Check if path is relative from current dir, or absolute...