From cbafac5ba188f118d895bb075060081be3aa2800 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 8 Feb 2017 20:01:57 -0700 Subject: [PATCH 01/66] Fix compilation on Redox --- src/libstd/sys/redox/mod.rs | 2 +- src/libstd/sys/redox/net/tcp.rs | 4 ++++ src/libstd/sys/redox/net/udp.rs | 8 ++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index 5982bdd6549ca..31c40ea58b1de 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -13,7 +13,7 @@ use io::{self, ErrorKind}; pub mod args; -#[cfg(any(not(cargobuild), feature = "backtrace"))] +#[cfg(feature = "backtrace")] pub mod backtrace; pub mod condvar; pub mod env; diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs index a3f202ccd97cb..936097d7fb2a6 100644 --- a/src/libstd/sys/redox/net/tcp.rs +++ b/src/libstd/sys/redox/net/tcp.rs @@ -63,6 +63,10 @@ impl TcpStream { Ok(path_to_local_addr(path.to_str().unwrap_or(""))) } + pub fn peek(&self, _buf: &mut [u8]) -> Result { + Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented")) + } + pub fn shutdown(&self, _how: Shutdown) -> Result<()> { Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented")) } diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs index 36f0819d30884..93ebcc95fd0f8 100644 --- a/src/libstd/sys/redox/net/udp.rs +++ b/src/libstd/sys/redox/net/udp.rs @@ -87,6 +87,14 @@ impl UdpSocket { Ok(path_to_local_addr(path.to_str().unwrap_or(""))) } + pub fn peek(&self, _buf: &mut [u8]) -> Result { + Err(Error::new(ErrorKind::Other, "UdpSocket::peek not implemented")) + } + + pub fn peek_from(&self, _buf: &mut [u8]) -> Result<(usize, SocketAddr)> { + Err(Error::new(ErrorKind::Other, "UdpSocket::peek_from not implemented")) + } + pub fn broadcast(&self) -> Result { Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented")) } From 4be5783748b1c84ca11a22c2a9a0d1cdab10a8e7 Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 11 Feb 2017 20:29:29 +1100 Subject: [PATCH 02/66] Add notes about capacity effects to Vec::truncate() --- src/libcollections/string.rs | 3 +++ src/libcollections/vec.rs | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 4c82e2e2e7e35..6f1c13e31b1c3 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -999,6 +999,9 @@ impl String { /// If `new_len` is greater than the string's current length, this has no /// effect. /// + /// Note that this method has no effect on the allocated capacity + /// of the string + /// /// # Panics /// /// Panics if `new_len` does not lie on a [`char`] boundary. diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index dc0f33d9bc3e0..0530df6863387 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -545,6 +545,9 @@ impl Vec { /// The [`drain`] method can emulate `truncate`, but causes the excess /// elements to be returned instead of dropped. /// + /// Note that this method has no effect on the allocated capacity + /// of the vector. + /// /// # Examples /// /// Truncating a five element vector to two elements: @@ -1089,6 +1092,9 @@ impl Vec { /// Clears the vector, removing all values. /// + /// Note that this method has no effect on the allocated capacity + /// of the vector. + /// /// # Examples /// /// ``` From 6ba7065af18caa34a0da126488c64c46c0ca276c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Feb 2017 14:48:26 +0100 Subject: [PATCH 03/66] enable tools to use test runners programmatically --- src/libtest/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 112bf61cf9722..428365784a32f 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -950,7 +950,7 @@ fn stdout_isatty() -> bool { } #[derive(Clone)] -enum TestEvent { +pub enum TestEvent { TeFiltered(Vec), TeWait(TestDesc, NamePadding), TeResult(TestDesc, TestResult, Vec), @@ -960,7 +960,7 @@ enum TestEvent { pub type MonitorMsg = (TestDesc, TestResult, Vec); -fn run_tests(opts: &TestOpts, tests: Vec, mut callback: F) -> io::Result<()> +pub fn run_tests(opts: &TestOpts, tests: Vec, mut callback: F) -> io::Result<()> where F: FnMut(TestEvent) -> io::Result<()> { use std::collections::HashMap; From 80ac32330f35c5994d5d5f9e17bbe0dd9f1fdee3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Feb 2017 16:02:53 +0100 Subject: [PATCH 04/66] make more types public --- src/libtest/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 428365784a32f..5fdb0aa0641a0 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -106,7 +106,7 @@ impl fmt::Display for TestName { } #[derive(Clone, Copy, PartialEq, Eq)] -enum NamePadding { +pub enum NamePadding { PadNone, PadOnRight, } From 5189c4f8c10d0b8cae1fb66e5b4e0717af30d60d Mon Sep 17 00:00:00 2001 From: Jakob Demler Date: Wed, 15 Feb 2017 12:59:01 +0100 Subject: [PATCH 05/66] custom attributes and error reporting docs for procedural macros --- src/doc/book/src/procedural-macros.md | 70 ++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md index d286c3b7bdc63..ef8b638dc1c60 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/src/procedural-macros.md @@ -209,5 +209,73 @@ Ok so now, let's compile `hello-world`. Executing `cargo run` now yields: Hello, World! My name is FrenchToast Hello, World! My name is Waffles ``` +## Custom Attributes +In some cases it might make sense to allow users some kind of configuration. +For our example the user might want to overwrite the name that is printed in the `hello_world()` method. -We've done it! +This can be achieved with custom attributes: +```rust,ignore +#[derive(HelloWorld)] +#[HelloWorldName = "the best Pancakes"] +struct Pancakes; + +fn main() { + Pancakes::hello_world(); +} +``` + +If we try to compile this though, the compiler will respond with an error: + +``` +error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +``` + +The compiler needs to know that we handle this attribute and to not respond with an error. +This is done in the `hello-world-derive`-crate by adding `attributes` to the `proc_macro_derive` attribute: + +```rust,ignore +#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))] +pub fn hello_world(input: TokenStream) -> TokenStream +``` + +Multiple attributes can be specified that way. + + +## Raising Errors +Let's assume that we do not want to accept `Enums` as input to our custom derive method. + +This condition can be easily checked with the help of `syn`. +But how to we tell the user, that we do not accept `Enums`. +The idiomatic was to report errors in procedural macros is to panic: + +```rust,ignore +fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { + let name = &ast.ident; + // Check if derive(HelloWorld) was specified for a struct + if let syn::Body::Struct(_) = ast.body { + // Yes, this is a struct + quote! { + impl HelloWorld for #name { + fn hello_world() { + println!("Hello, World! My name is {}", stringify!(#name)); + } + } + } + } else { + //Nope. This is an Enum. We cannot handle these! + panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!"); + } +} +``` + +If a user now tries to derive `HelloWorld` from an enum they will be greeted with following, hopefully helpful, error: + +``` +error: custom derive attribute panicked + --> src/main.rs + | + | #[derive(HelloWorld)] + | ^^^^^^^^^^ + | + = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums! +``` From 9a39994ee3a6f825318af9d6ceb23ee3187c7888 Mon Sep 17 00:00:00 2001 From: Jakob Demler Date: Wed, 15 Feb 2017 15:31:52 +0100 Subject: [PATCH 06/66] add bash to error-messages --- src/doc/book/src/procedural-macros.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md index ef8b638dc1c60..e9777f9992f74 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/src/procedural-macros.md @@ -226,7 +226,7 @@ fn main() { If we try to compile this though, the compiler will respond with an error: -``` +```bash error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) ``` @@ -270,7 +270,7 @@ fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { If a user now tries to derive `HelloWorld` from an enum they will be greeted with following, hopefully helpful, error: -``` +```bash error: custom derive attribute panicked --> src/main.rs | From 8685adb26b0ec6a0b4fad2cb7765fae3b9f2e25c Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Mon, 13 Feb 2017 03:00:06 +0100 Subject: [PATCH 07/66] book: binary prefixed are defined by IEC and not in SI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Binary prefixes (such as Gi for ‘gibi-’ in GiB) are defined by International Electrotechnical Commission (IEC) and not in the International System of Units (SI). --- src/doc/book/src/the-stack-and-the-heap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/src/the-stack-and-the-heap.md b/src/doc/book/src/the-stack-and-the-heap.md index b9b3b801eae58..6866505df1310 100644 --- a/src/doc/book/src/the-stack-and-the-heap.md +++ b/src/doc/book/src/the-stack-and-the-heap.md @@ -86,7 +86,7 @@ to a large number, representing how much RAM your computer has. For example, if you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That number comes from 230, the number of bytes in a gigabyte. [^gigabyte] -[^gigabyte]: ‘Gigabyte’ can mean two things: 10^9, or 2^30. The SI standard resolved this by stating that ‘gigabyte’ is 10^9, and ‘gibibyte’ is 2^30. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here. +[^gigabyte]: ‘Gigabyte’ can mean two things: 109, or 230. The IEC standard resolved this by stating that ‘gigabyte’ is 109, and ‘gibibyte’ is 230. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here. This memory is kind of like a giant array: addresses start at zero and go up to the final number. So here’s a diagram of our first stack frame: From 97451996e69a0bb8d98cfe77bd904d8033419ab9 Mon Sep 17 00:00:00 2001 From: Jakob Demler Date: Wed, 15 Feb 2017 21:21:31 +0100 Subject: [PATCH 08/66] fixed whitespace issues --- src/doc/book/src/procedural-macros.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md index e9777f9992f74..468a8f904a45a 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/src/procedural-macros.md @@ -209,7 +209,9 @@ Ok so now, let's compile `hello-world`. Executing `cargo run` now yields: Hello, World! My name is FrenchToast Hello, World! My name is Waffles ``` + ## Custom Attributes + In some cases it might make sense to allow users some kind of configuration. For our example the user might want to overwrite the name that is printed in the `hello_world()` method. @@ -240,8 +242,8 @@ pub fn hello_world(input: TokenStream) -> TokenStream Multiple attributes can be specified that way. - ## Raising Errors + Let's assume that we do not want to accept `Enums` as input to our custom derive method. This condition can be easily checked with the help of `syn`. From 0e45a5ed3f79338656b19a41172d3a7761586ebc Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 16 Feb 2017 20:52:56 +0200 Subject: [PATCH 09/66] [rustbuild] add a way to run command after failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a simple way to workaround the debugging issues caused by the rustc wrapper used in the bootstrap process. Namely, it uses some obscure environment variables and you can’t just copy the failed command and run it in the shell or debugger to examine the failure more closely. With `--on-fail` its possible to run an arbitrary command within exactly the same environment under which rustc failed. Theres’s multiple ways to use this new flag: $ python x.py build --stage=1 --on-fail=env would print a list of environment variables and the failed command, so a few copy-pastes and you now can run the same rust in your shell outside the bootstrap system. $ python x.py build --stage=1 --on-fail=bash Is a more useful variation of the command above in that it launches a whole shell with environment already in place! All that’s left to do is copy-paste the command just above the shell prompt! Fixes #38686 Fixes #38221 --- src/bootstrap/bin/rustc.rs | 18 +++++++++++++++--- src/bootstrap/flags.rs | 3 +++ src/bootstrap/lib.rs | 4 ++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 90fd31ecbdd73..bf1da57607d5f 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -68,6 +68,7 @@ fn main() { }; let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); + let mut on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of)); let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); @@ -212,9 +213,20 @@ fn main() { } // Actually run the compiler! - std::process::exit(match exec_cmd(&mut cmd) { - Ok(s) => s.code().unwrap_or(0xfe), - Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), + std::process::exit(if let Some(ref mut on_fail) = on_fail { + match cmd.status() { + Ok(s) if s.success() => 0, + _ => { + println!("\nDid not run successfully:\n{:?}\n-------------", cmd); + exec_cmd(on_fail).expect("could not run the backup command"); + 1 + } + } + } else { + std::process::exit(match exec_cmd(&mut cmd) { + Ok(s) => s.code().unwrap_or(0xfe), + Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), + }) }) } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c5bbfd89b2787..b55f3d710ca7b 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -28,6 +28,7 @@ use step; /// Deserialized version of all flags for this compile. pub struct Flags { pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose + pub on_fail: Option, pub stage: Option, pub keep_stage: Option, pub build: String, @@ -81,6 +82,7 @@ impl Flags { opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); + opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optopt("", "stage", "stage to build", "N"); opts.optopt("", "keep-stage", "stage to keep without recompiling", "N"); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); @@ -283,6 +285,7 @@ To learn more about a subcommand, run `./x.py -h` Flags { verbose: m.opt_count("v"), stage: stage, + on_fail: m.opt_str("on-fail"), keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()), build: m.opt_str("build").unwrap_or_else(|| { env::var("BUILD").unwrap() diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 7bd611eb53e3c..a28cb24a8166f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -499,6 +499,10 @@ impl Build { cargo.env("RUSTC_INCREMENTAL", incr_dir); } + if let Some(ref on_fail) = self.flags.on_fail { + cargo.env("RUSTC_ON_FAIL", on_fail); + } + let verbose = cmp::max(self.config.verbose, self.flags.verbose); cargo.env("RUSTC_VERBOSE", format!("{}", verbose)); From b2ac1c9c6b595f39c79e13bc4e0a0411441c7543 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 16 Feb 2017 09:18:18 -0800 Subject: [PATCH 10/66] Additional docs for Vec, String, and slice trait impls --- src/libcollections/string.rs | 42 ++++++++++++++++++++++++++++++++++++ src/libcollections/vec.rs | 2 ++ src/libcore/slice.rs | 2 ++ src/libcore/str/mod.rs | 14 ++++++++++++ 4 files changed, 60 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 4c82e2e2e7e35..a1e6c7fe6fe54 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1629,6 +1629,43 @@ impl hash::Hash for String { } } +/// Implements the `+` operator for concatenating two strings. +/// +/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if +/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on +/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by +/// repeated concatenation. +/// +/// The string on the right-hand side is only borrowed; its contents are copied into the returned +/// `String`. +/// +/// # Examples +/// +/// Concatenating two `String`s takes the first by value and borrows the second: +/// +/// ``` +/// let a = String::from("hello"); +/// let b = String::from(" world"); +/// let c = a + &b; +/// // `a` is moved and can no longer be used here. +/// ``` +/// +/// If you want to keep using the first `String`, you can clone it and append to the clone instead: +/// +/// ``` +/// let a = String::from("hello"); +/// let b = String::from(" world"); +/// let c = a.clone() + &b; +/// // `a` is still valid here. +/// ``` +/// +/// Concatenating `&str` slices can be done by converting the first to a `String`: +/// +/// ``` +/// let a = "hello"; +/// let b = " world"; +/// let c = a.to_string() + b; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Add<&'a str> for String { type Output = String; @@ -1640,6 +1677,11 @@ impl<'a> Add<&'a str> for String { } } +/// Implements the `+=` operator for appending to a `String`. +/// +/// This has the same behavior as the [`push_str()`] method. +/// +/// [`push_str()`]: struct.String.html#method.push_str #[stable(feature = "stringaddassign", since = "1.12.0")] impl<'a> AddAssign<&'a str> for String { #[inline] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 9e3f117f9b20e..bc7f562452d3b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1776,6 +1776,7 @@ array_impls! { 30 31 32 } +/// Implements comparison of vectors, lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Vec { #[inline] @@ -1787,6 +1788,7 @@ impl PartialOrd for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for Vec {} +/// Implements ordering of vectors, lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Vec { #[inline] diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 3e0b842557353..0331c5d4ba401 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -2202,6 +2202,7 @@ impl PartialEq<[B]> for [A] where A: PartialEq { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for [T] {} +/// Implements comparison of vectors lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for [T] { fn cmp(&self, other: &[T]) -> Ordering { @@ -2209,6 +2210,7 @@ impl Ord for [T] { } } +/// Implements comparison of vectors lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for [T] { fn partial_cmp(&self, other: &[T]) -> Option { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 49a6b1b5fceb7..925cd84154a2e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1366,6 +1366,13 @@ mod traits { use ops; use str::eq_slice; + /// Implements ordering of strings. + /// + /// Strings are ordered lexicographically by their byte values. This orders Unicode code + /// points based on their positions in the code charts. This is not necessarily the same as + /// "alphabetical" order, which varies by language and locale. Sorting strings according to + /// culturally-accepted standards requires locale-specific data that is outside the scope of + /// the `str` type. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for str { #[inline] @@ -1387,6 +1394,13 @@ mod traits { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for str {} + /// Implements comparison operations on strings. + /// + /// Strings are compared lexicographically by their byte values. This compares Unicode code + /// points based on their positions in the code charts. This is not necessarily the same as + /// "alphabetical" order, which varies by language and locale. Comparing strings according to + /// culturally-accepted standards requires locale-specific data that is outside the scope of + /// the `str` type. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for str { #[inline] From 047a215b4d9cf762d3704ee02b76467897bbbe21 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 15 Feb 2017 22:47:11 +0100 Subject: [PATCH 11/66] Set rustdoc --test files' path relative to the current directory --- src/librustdoc/test.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1c37067d7f69d..c7000ee1e40e7 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -12,7 +12,7 @@ use std::env; use std::ffi::OsString; use std::io::prelude::*; use std::io; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::panic::{self, AssertUnwindSafe}; use std::process::Command; use std::rc::Rc; @@ -485,7 +485,15 @@ impl Collector { pub fn get_filename(&self) -> String { if let Some(ref codemap) = self.codemap { - codemap.span_to_filename(self.position) + let filename = codemap.span_to_filename(self.position); + if let Ok(cur_dir) = env::current_dir() { + if let Ok(path) = Path::new(&filename).strip_prefix(&cur_dir) { + if let Some(path) = path.to_str() { + return path.to_owned(); + } + } + } + filename } else if let Some(ref filename) = self.filename { filename.clone() } else { From 2e756e22b3d5ffcb9cf8b199796ecb35cfc7b415 Mon Sep 17 00:00:00 2001 From: Shawn Walker-Salas Date: Thu, 16 Feb 2017 21:19:43 -0800 Subject: [PATCH 12/66] add solaris sparcv9 support * Update bootstrap to recognize the cputype 'sparcv9' (used on Solaris) * Change to never use -fomit-frame-pointer on Solaris or for sparc * Adds rust target sparcv9-sun-solaris Fixes #39901 --- src/bootstrap/bootstrap.py | 2 ++ src/libcompiler_builtins/build.rs | 10 +++++- src/librustc_back/target/mod.rs | 1 + .../target/sparcv9_sun_solaris.rs | 35 +++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/librustc_back/target/sparcv9_sun_solaris.rs diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index ee3f663dbd552..127369a4b776c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -416,6 +416,8 @@ def build_triple(self): ostype += 'abi64' elif cputype in {'powerpc', 'ppc', 'ppc64'}: cputype = 'powerpc' + elif cputype == 'sparcv9': + pass elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}: cputype = 'x86_64' else: diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs index 5360bbdeacd6a..16ecf88256670 100644 --- a/src/libcompiler_builtins/build.rs +++ b/src/libcompiler_builtins/build.rs @@ -92,7 +92,15 @@ fn main() { // compiler-rt's build system already cfg.flag("-fno-builtin"); cfg.flag("-fvisibility=hidden"); - cfg.flag("-fomit-frame-pointer"); + // Accepted practice on Solaris is to never omit frame pointer so that + // system observability tools work as expected. In addition, at least + // on Solaris, -fomit-frame-pointer on sparcv9 appears to generate + // references to data outside of the current stack frame. A search of + // the gcc bug database provides a variety of issues surrounding + // -fomit-frame-pointer on non-x86 platforms. + if !target.contains("solaris") && !target.contains("sparc") { + cfg.flag("-fomit-frame-pointer"); + } cfg.flag("-ffreestanding"); cfg.define("VISIBILITY_HIDDEN", None); } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 1d5d1e3ab2fc7..0c179469448fe 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -200,6 +200,7 @@ supported_targets! { ("armv7s-apple-ios", armv7s_apple_ios), ("x86_64-sun-solaris", x86_64_sun_solaris), + ("sparcv9-sun-solaris", sparcv9_sun_solaris), ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), ("i686-pc-windows-gnu", i686_pc_windows_gnu), diff --git a/src/librustc_back/target/sparcv9_sun_solaris.rs b/src/librustc_back/target/sparcv9_sun_solaris.rs new file mode 100644 index 0000000000000..c88e5a402f2f5 --- /dev/null +++ b/src/librustc_back/target/sparcv9_sun_solaris.rs @@ -0,0 +1,35 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::solaris_base::opts(); + base.pre_link_args.push("-m64".to_string()); + // llvm calls this "v9" + base.cpu = "v9".to_string(); + base.max_atomic_width = Some(64); + + Ok(Target { + llvm_target: "sparcv9-sun-solaris".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), + // Use "sparc64" instead of "sparcv9" here, since the former is already + // used widely in the source base. If we ever needed ABI + // differentiation from the sparc64, we could, but that would probably + // just be confusing. + arch: "sparc64".to_string(), + target_os: "solaris".to_string(), + target_env: "".to_string(), + target_vendor: "sun".to_string(), + options: base, + }) +} From 038a166e092ab5497dcb8e6785949a954d692cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Feb 2017 23:00:03 -0800 Subject: [PATCH 13/66] Properly display note/expected details --- src/librustc/infer/error_reporting.rs | 53 ++++++++++--------- .../compile-fail/default_ty_param_conflict.rs | 2 - .../default_ty_param_conflict_cross_crate.rs | 2 - src/test/compile-fail/issue-35869.rs | 4 ++ src/test/ui/mismatched_types/E0053.stderr | 3 ++ .../trait-impl-fn-incompatibility.stderr | 3 ++ 6 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 939f214407ef7..2601ff4af43c1 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -562,40 +562,41 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { values: Option>, terr: &TypeError<'tcx>) { - let expected_found = match values { - None => None, - Some(values) => match self.values_str(&values) { - Some((expected, found)) => Some((expected, found)), - None => { - // Derived error. Cancel the emitter. - self.tcx.sess.diagnostic().cancel(diag); - return - } + let (expected_found, is_simple_error) = match values { + None => (None, false), + Some(values) => { + let is_simple_error = match values { + ValuePairs::Types(exp_found) => { + exp_found.expected.is_primitive() && exp_found.found.is_primitive() + } + _ => false, + }; + let vals = match self.values_str(&values) { + Some((expected, found)) => Some((expected, found)), + None => { + // Derived error. Cancel the emitter. + self.tcx.sess.diagnostic().cancel(diag); + return + } + }; + (vals, is_simple_error) } }; let span = cause.span; if let Some((expected, found)) = expected_found { - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false - }; - - if !is_simple_error { - if expected == found { - if let &TypeError::Sorts(ref values) = terr { - diag.note_expected_found_extra( - &"type", &expected, &found, - &format!(" ({})", values.expected.sort_string(self.tcx)), - &format!(" ({})", values.found.sort_string(self.tcx))); - } else { - diag.note_expected_found(&"type", &expected, &found); - } - } else { + match (terr, is_simple_error, expected == found) { + (&TypeError::Sorts(ref values), false, true) => { + diag.note_expected_found_extra( + &"type", &expected, &found, + &format!(" ({})", values.expected.sort_string(self.tcx)), + &format!(" ({})", values.found.sort_string(self.tcx))); + } + (_, false, _) => { diag.note_expected_found(&"type", &expected, &found); } + _ => (), } } diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs index 4702b504f157d..8cde239ca6edf 100644 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ b/src/test/compile-fail/default_ty_param_conflict.rs @@ -23,8 +23,6 @@ fn main() { // Here, F is instantiated with $0=uint let x = foo(); //~^ ERROR: mismatched types - //~| expected type `usize` - //~| found type `isize` //~| NOTE: conflicting type parameter defaults `usize` and `isize` //~| NOTE: conflicting type parameter defaults `usize` and `isize` //~| NOTE: ...that was applied to an unconstrained type variable here diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs index b608c6c99be89..e5b035e50aa93 100644 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs @@ -29,6 +29,4 @@ fn main() { //~| NOTE: conflicting type parameter defaults `bool` and `char` //~| a second default is defined on `default_param_test::bleh` //~| NOTE: ...that was applied to an unconstrained type variable here - //~| expected type `bool` - //~| found type `char` } diff --git a/src/test/compile-fail/issue-35869.rs b/src/test/compile-fail/issue-35869.rs index 8b7fc80bdb6b7..d1d6390cce35b 100644 --- a/src/test/compile-fail/issue-35869.rs +++ b/src/test/compile-fail/issue-35869.rs @@ -23,15 +23,19 @@ impl Foo for Bar { fn foo(_: fn(u16) -> ()) {} //~^ ERROR method `foo` has an incompatible type for trait //~| NOTE expected u8 + //~| NOTE expected type `fn(fn(u8))` fn bar(_: Option) {} //~^ ERROR method `bar` has an incompatible type for trait //~| NOTE expected u8 + //~| NOTE expected type `fn(std::option::Option)` fn baz(_: (u16, u16)) {} //~^ ERROR method `baz` has an incompatible type for trait //~| NOTE expected u8 + //~| NOTE expected type `fn((u8, u16))` fn qux() -> u16 { 5u16 } //~^ ERROR method `qux` has an incompatible type for trait //~| NOTE expected u8 + //~| NOTE expected type `fn() -> u8` } fn main() {} diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr index b6e3d663e36bd..d9871b8970c5c 100644 --- a/src/test/ui/mismatched_types/E0053.stderr +++ b/src/test/ui/mismatched_types/E0053.stderr @@ -6,6 +6,9 @@ error[E0053]: method `foo` has an incompatible type for trait ... 19 | fn foo(x: i16) { } | ^^^ expected u16, found i16 + | + = note: expected type `fn(u16)` + found type `fn(i16)` error[E0053]: method `bar` has an incompatible type for trait --> $DIR/E0053.rs:22:12 diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index 991197c2afba3..349432f64bbc2 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -6,6 +6,9 @@ error[E0053]: method `foo` has an incompatible type for trait ... 21 | fn foo(x: i16) { } | ^^^ expected u16, found i16 + | + = note: expected type `fn(u16)` + found type `fn(i16)` error[E0053]: method `bar` has an incompatible type for trait --> $DIR/trait-impl-fn-incompatibility.rs:22:28 From 609133098bfbeae69fb9c65ca5438c411d27dfd6 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 17 Feb 2017 11:26:22 -0800 Subject: [PATCH 14/66] Follow rename of mx_handle_wait Magenta syscalls The mx_handle_wait_* syscalls in Magenta were renamed to mx_object_wait. The syscall is used in the Magenta/Fuchsia implementation of std::process, to wait on child processes. In addition, this patch enables the use of the system provided libbacktrace library on Fuchsia targets. Symbolization is not yet working, but at least it allows printing hex addresses in a backtrace and makes building succeed when the backtrace feature is not disabled. --- src/libstd/build.rs | 4 ++++ src/libstd/sys/unix/process/magenta.rs | 2 +- src/libstd/sys/unix/process/process_fuchsia.rs | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 0fca374f6e6d1..038dea77f3ead 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -59,6 +59,10 @@ fn main() { println!("cargo:rustc-link-lib=userenv"); println!("cargo:rustc-link-lib=shell32"); } else if target.contains("fuchsia") { + // use system-provided libbacktrace + if cfg!(feature = "backtrace") { + println!("cargo:rustc-link-lib=backtrace"); + } println!("cargo:rustc-link-lib=magenta"); println!("cargo:rustc-link-lib=mxio"); println!("cargo:rustc-link-lib=launchpad"); // for std::process diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs index a81bedcad22ff..08a827ce08142 100644 --- a/src/libstd/sys/unix/process/magenta.rs +++ b/src/libstd/sys/unix/process/magenta.rs @@ -111,7 +111,7 @@ extern { pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t, out: *const mx_handle_t) -> mx_handle_t; - pub fn mx_handle_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t, + pub fn mx_object_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t, pending: *mut mx_signals_t) -> mx_status_t; pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void, diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 0bb2e0c1a83d4..608e44ca9e86e 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -151,7 +151,7 @@ impl Process { let mut avail: mx_size_t = 0; unsafe { - mx_cvt(mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED, + mx_cvt(mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED, MX_TIME_INFINITE, ptr::null_mut()))?; mx_cvt(mx_object_get_info(self.handle.raw(), MX_INFO_PROCESS, &mut proc_info as *mut _ as *mut libc::c_void, @@ -174,7 +174,7 @@ impl Process { let mut avail: mx_size_t = 0; unsafe { - let status = mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED, + let status = mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED, 0, ptr::null_mut()); match status { 0 => { }, // Success From 5205e2f8b8094a5f3d0205593820391dfe481808 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 15 Feb 2017 14:52:27 -0800 Subject: [PATCH 15/66] Normalize labeled and unlabeled breaks --- src/librustc/cfg/construct.rs | 15 +-- src/librustc/hir/intravisit.rs | 20 +-- src/librustc/hir/lowering.rs | 115 ++++++++++++------ src/librustc/hir/mod.rs | 9 +- src/librustc/hir/print.rs | 12 +- src/librustc/middle/liveness.rs | 25 +--- .../calculate_svh/svh_visitor.rs | 6 +- src/librustc_mir/build/scope.rs | 22 ++-- src/librustc_mir/hair/cx/expr.rs | 4 +- src/librustc_mir/hair/mod.rs | 4 +- src/librustc_passes/loops.rs | 23 ++-- src/librustc_typeck/check/mod.rs | 14 +-- src/test/run-pass/loop-break-value.rs | 8 -- 13 files changed, 138 insertions(+), 139 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 595059332895d..bc3da13ccf82d 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -579,17 +579,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn find_scope(&self, expr: &hir::Expr, - label: Option) -> LoopScope { - match label { - None => *self.loop_scopes.last().unwrap(), - Some(label) => { - for l in &self.loop_scopes { - if l.loop_id == label.loop_id { - return *l; - } - } - span_bug!(expr.span, "no loop scope for id {}", label.loop_id); + label: hir::Label) -> LoopScope { + for l in &self.loop_scopes { + if l.loop_id == label.loop_id { + return *l; } } + span_bug!(expr.span, "no loop scope for id {}", label.loop_id); } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 1df6761506993..03b59aaf319c6 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1006,18 +1006,18 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprPath(ref qpath) => { visitor.visit_qpath(qpath, expression.id, expression.span); } - ExprBreak(None, ref opt_expr) => { + ExprBreak(label, ref opt_expr) => { + label.ident.map(|ident| { + visitor.visit_def_mention(Def::Label(label.loop_id)); + visitor.visit_name(ident.span, ident.node.name); + }); walk_list!(visitor, visit_expr, opt_expr); } - ExprBreak(Some(label), ref opt_expr) => { - visitor.visit_def_mention(Def::Label(label.loop_id)); - visitor.visit_name(label.span, label.name); - walk_list!(visitor, visit_expr, opt_expr); - } - ExprAgain(None) => {} - ExprAgain(Some(label)) => { - visitor.visit_def_mention(Def::Label(label.loop_id)); - visitor.visit_name(label.span, label.name); + ExprAgain(label) => { + label.ident.map(|ident| { + visitor.visit_def_mention(Def::Label(label.loop_id)); + visitor.visit_name(ident.span, ident.node.name); + }); } ExprRet(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8a4acb3d03880..d6f99327d4fa2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -50,6 +50,7 @@ use util::nodemap::{DefIdMap, NodeMap, FxHashMap}; use std::collections::BTreeMap; use std::iter; +use std::mem; use syntax::attr; use syntax::ast::*; @@ -79,6 +80,8 @@ pub struct LoweringContext<'a> { impl_items: BTreeMap, bodies: FxHashMap, + loop_scopes: Vec, + type_def_lifetime_params: DefIdMap, } @@ -112,6 +115,7 @@ pub fn lower_crate(sess: &Session, trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), bodies: FxHashMap(), + loop_scopes: Vec::new(), type_def_lifetime_params: DefIdMap(), }.lower_crate(krate) } @@ -244,6 +248,27 @@ impl<'a> LoweringContext<'a> { span } + fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let len = self.loop_scopes.len(); + self.loop_scopes.push(loop_id); + let result = f(self); + assert_eq!(len + 1, self.loop_scopes.len(), + "Loop scopes should be added and removed in stack order"); + self.loop_scopes.pop().unwrap(); + result + } + + fn with_new_loop_scopes(&mut self, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new()); + let result = f(self); + mem::replace(&mut self.loop_scopes, loop_scopes); + result + } + fn with_parent_def(&mut self, parent_id: NodeId, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { @@ -271,17 +296,23 @@ impl<'a> LoweringContext<'a> { o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name)) } - fn lower_label(&mut self, id: NodeId, label: Option>) -> Option { - label.map(|sp_ident| { - hir::Label { - span: sp_ident.span, - name: sp_ident.node.name, + fn lower_label(&mut self, label: Option<(NodeId, Spanned)>) -> hir::Label { + match label { + Some((id, label_ident)) => hir::Label { + ident: Some(label_ident), loop_id: match self.expect_full_def(id) { Def::Label(loop_id) => loop_id, _ => DUMMY_NODE_ID } + }, + None => hir::Label { + ident: None, + loop_id: match self.loop_scopes.last() { + Some(innermost_loop_id) => *innermost_loop_id, + _ => DUMMY_NODE_ID + } } - }) + } } fn lower_attrs(&mut self, attrs: &Vec) -> hir::HirVec { @@ -992,15 +1023,17 @@ impl<'a> LoweringContext<'a> { self.record_body(value, None)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - let body = self.lower_block(body); - let body = self.expr_block(body, ThinVec::new()); - let body_id = self.record_body(body, Some(decl)); - hir::ItemFn(self.lower_fn_decl(decl), - self.lower_unsafety(unsafety), - self.lower_constness(constness), - abi, - self.lower_generics(generics), - body_id) + self.with_new_loop_scopes(|this| { + let body = this.lower_block(body); + let body = this.expr_block(body, ThinVec::new()); + let body_id = this.record_body(body, Some(decl)); + hir::ItemFn(this.lower_fn_decl(decl), + this.lower_unsafety(unsafety), + this.lower_constness(constness), + abi, + this.lower_generics(generics), + body_id) + }) } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), @@ -1562,13 +1595,17 @@ impl<'a> LoweringContext<'a> { hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt) } ExprKind::While(ref cond, ref body, opt_ident) => { - hir::ExprWhile(P(self.lower_expr(cond)), self.lower_block(body), - self.lower_opt_sp_ident(opt_ident)) + self.with_loop_scope(e.id, |this| + hir::ExprWhile( + P(this.lower_expr(cond)), + this.lower_block(body), + this.lower_opt_sp_ident(opt_ident))) } ExprKind::Loop(ref body, opt_ident) => { - hir::ExprLoop(self.lower_block(body), - self.lower_opt_sp_ident(opt_ident), - hir::LoopSource::Loop) + self.with_loop_scope(e.id, |this| + hir::ExprLoop(this.lower_block(body), + this.lower_opt_sp_ident(opt_ident), + hir::LoopSource::Loop)) } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), @@ -1576,12 +1613,14 @@ impl<'a> LoweringContext<'a> { hir::MatchSource::Normal) } ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_parent_def(e.id, |this| { - let expr = this.lower_expr(body); - hir::ExprClosure(this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl), - this.record_body(expr, Some(decl)), - fn_decl_span) + self.with_new_loop_scopes(|this| { + this.with_parent_def(e.id, |this| { + let expr = this.lower_expr(body); + hir::ExprClosure(this.lower_capture_clause(capture_clause), + this.lower_fn_decl(decl), + this.record_body(expr, Some(decl)), + fn_decl_span) + }) }) } ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)), @@ -1660,10 +1699,13 @@ impl<'a> LoweringContext<'a> { hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) } ExprKind::Break(opt_ident, ref opt_expr) => { - hir::ExprBreak(self.lower_label(e.id, opt_ident), + hir::ExprBreak( + self.lower_label(opt_ident.map(|ident| (e.id, ident))), opt_expr.as_ref().map(|x| P(self.lower_expr(x)))) } - ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_label(e.id, opt_ident)), + ExprKind::Continue(opt_ident) => + hir::ExprAgain( + self.lower_label(opt_ident.map(|ident| (e.id, ident)))), ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))), ExprKind::InlineAsm(ref asm) => { let hir_asm = hir::InlineAsm { @@ -1804,9 +1846,14 @@ impl<'a> LoweringContext<'a> { // } // } + let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( + this.lower_block(body), + this.expr_break(e.span, ThinVec::new()), + P(this.lower_expr(sub_expr)), + )); + // ` => ` let pat_arm = { - let body = self.lower_block(body); let body_expr = P(self.expr_block(body, ThinVec::new())); let pat = self.lower_pat(pat); self.arm(hir_vec![pat], body_expr) @@ -1815,13 +1862,11 @@ impl<'a> LoweringContext<'a> { // `_ => break` let break_arm = { let pat_under = self.pat_wild(e.span); - let break_expr = self.expr_break(e.span, ThinVec::new()); self.arm(hir_vec![pat_under], break_expr) }; // `match { ... }` let arms = hir_vec![pat_arm, break_arm]; - let sub_expr = P(self.lower_expr(sub_expr)); let match_expr = self.expr(e.span, hir::ExprMatch(sub_expr, arms, @@ -1863,7 +1908,7 @@ impl<'a> LoweringContext<'a> { // `::std::option::Option::Some() => ` let pat_arm = { - let body_block = self.lower_block(body); + let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); let pat = self.lower_pat(pat); let some_pat = self.pat_some(e.span, pat); @@ -1873,7 +1918,8 @@ impl<'a> LoweringContext<'a> { // `::std::option::Option::None => break` let break_arm = { - let break_expr = self.expr_break(e.span, ThinVec::new()); + let break_expr = self.with_loop_scope(e.id, |this| + this.expr_break(e.span, ThinVec::new())); let pat = self.pat_none(e.span); self.arm(hir_vec![pat], break_expr) }; @@ -2151,7 +2197,8 @@ impl<'a> LoweringContext<'a> { } fn expr_break(&mut self, span: Span, attrs: ThinVec) -> P { - P(self.expr(span, hir::ExprBreak(None, None), attrs)) + let expr_break = hir::ExprBreak(self.lower_label(None), None); + P(self.expr(span, expr_break, attrs)) } fn expr_call(&mut self, span: Span, e: P, args: hir::HirVec) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4ebe416e1bfe6..fc5282d1af2f2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -36,7 +36,7 @@ use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; use syntax_pos::{Span, ExpnId, DUMMY_SP}; use syntax::codemap::{self, Spanned}; use syntax::abi::Abi; -use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect}; +use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; @@ -959,9 +959,9 @@ pub enum Expr_ { /// A referencing operation (`&a` or `&mut a`) ExprAddrOf(Mutability, P), /// A `break`, with an optional label to break - ExprBreak(Option