From 6ba7065af18caa34a0da126488c64c46c0ca276c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Feb 2017 14:48:26 +0100 Subject: [PATCH 01/33] 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 02/33] 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 03/33] 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 04/33] 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 05/33] 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 06/33] 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 b2ac1c9c6b595f39c79e13bc4e0a0411441c7543 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 16 Feb 2017 09:18:18 -0800 Subject: [PATCH 07/33] 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 2e756e22b3d5ffcb9cf8b199796ecb35cfc7b415 Mon Sep 17 00:00:00 2001 From: Shawn Walker-Salas Date: Thu, 16 Feb 2017 21:19:43 -0800 Subject: [PATCH 08/33] 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 09/33] 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 10/33] 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 22f91ca8365155fc2576e2cc2daac506773b40d8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Feb 2017 12:46:44 -0500 Subject: [PATCH 11/33] move the `FreeRegionMap` into `TypeckTables` --- src/librustc/middle/free_region.rs | 6 ++- src/librustc/ty/context.rs | 25 +++------ src/librustc_borrowck/borrowck/mod.rs | 51 +++++++------------ src/librustc_data_structures/lib.rs | 1 + .../transitive_relation.rs | 33 +++++++++++- src/librustc_typeck/check/regionck.rs | 12 +++-- src/librustc_typeck/check/writeback.rs | 9 ++++ 7 files changed, 79 insertions(+), 58 deletions(-) diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index bd35bfc9829a5..cdb081ab40098 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -19,7 +19,7 @@ use ty::{self, TyCtxt, FreeRegion, Region}; use ty::wf::ImpliedBound; use rustc_data_structures::transitive_relation::TransitiveRelation; -#[derive(Clone)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct FreeRegionMap { // Stores the relation `a < b`, where `a` and `b` are regions. relation: TransitiveRelation @@ -30,6 +30,10 @@ impl FreeRegionMap { FreeRegionMap { relation: TransitiveRelation::new() } } + pub fn is_empty(&self) -> bool { + self.relation.is_empty() + } + pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self, implied_bounds: &[ImpliedBound<'tcx>]) { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 19bb8a63aa277..33fb997a14e70 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -242,6 +242,11 @@ pub struct TypeckTables<'tcx> { /// Lints for the body of this fn generated by typeck. pub lints: lint::LintTable, + + /// Stores the free-region relationships that were deduced from + /// its where clauses and parameter types. These are then + /// read-again by borrowck. + pub free_region_map: FreeRegionMap, } impl<'tcx> TypeckTables<'tcx> { @@ -259,6 +264,7 @@ impl<'tcx> TypeckTables<'tcx> { fru_field_types: NodeMap(), cast_kinds: NodeMap(), lints: lint::LintTable::new(), + free_region_map: FreeRegionMap::new(), } } @@ -406,14 +412,6 @@ pub struct GlobalCtxt<'tcx> { pub region_maps: RegionMaps, - // For each fn declared in the local crate, type check stores the - // free-region relationships that were deduced from its where - // clauses and parameter types. These are then read-again by - // borrowck. (They are not used during trans, and hence are not - // serialized or needed for cross-crate fns.) - free_region_maps: RefCell>, - // FIXME: jroesch make this a refcell - pub tables: RefCell>>, /// Maps from a trait item to the trait item "descriptor" @@ -706,16 +704,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { interned } - pub fn store_free_region_map(self, id: NodeId, map: FreeRegionMap) { - if self.free_region_maps.borrow_mut().insert(id, map).is_some() { - bug!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", id) - } - } - - pub fn free_region_map(self, id: NodeId) -> FreeRegionMap { - self.free_region_maps.borrow()[&id].clone() - } - pub fn lift>(self, value: &T) -> Option { value.lift_to_tcx(self) } @@ -762,7 +750,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { types: common_types, named_region_map: named_region_map, region_maps: region_maps, - free_region_maps: RefCell::new(FxHashMap()), item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())), variance_computed: Cell::new(false), sess: s, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 46179b31d5cb4..06133de07576e 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -32,14 +32,12 @@ use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; -use rustc::middle::free_region::FreeRegionMap; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; use std::fmt; -use std::mem; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; @@ -72,9 +70,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { - self.with_temp_region_map(id, |this| { - borrowck_fn(this, fk, fd, b, s, id, fk.attrs()) - }); + borrowck_fn(self, fk, fd, b, s, id, fk.attrs()) } FnKind::Closure(..) => { @@ -105,7 +101,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut bccx = BorrowckCtxt { tcx: tcx, - free_region_map: FreeRegionMap::new(), + tables: None, stats: BorrowStats { loaned_paths_same: 0, loaned_paths_imm: 0, @@ -167,12 +163,15 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, attributes: &[ast::Attribute]) { debug!("borrowck_fn(id={})", id); + assert!(this.tables.is_none()); + let owner_def_id = this.tcx.hir.local_def_id(this.tcx.hir.body_owner(body_id)); + let tables = this.tcx.item_tables(owner_def_id); + this.tables = Some(tables); + let body = this.tcx.hir.body(body_id); if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) { - this.with_temp_region_map(id, |this| { - mir::borrowck_mir(this, id, attributes) - }); + mir::borrowck_mir(this, id, attributes); } let cfg = cfg::CFG::new(this.tcx, &body.value); @@ -191,6 +190,8 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body); + this.tables = None; + intravisit::walk_fn(this, fk, decl, body_id, sp, id); } @@ -248,7 +249,7 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let mut bccx = BorrowckCtxt { tcx: tcx, - free_region_map: FreeRegionMap::new(), + tables: None, stats: BorrowStats { loaned_paths_same: 0, loaned_paths_imm: 0, @@ -267,17 +268,9 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( pub struct BorrowckCtxt<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - // Hacky. As we visit various fns, we have to load up the - // free-region map for each one. This map is computed by during - // typeck for each fn item and stored -- closures just use the map - // from the fn item that encloses them. Since we walk the fns in - // order, we basically just overwrite this field as we enter a fn - // item and restore it afterwards in a stack-like fashion. Then - // the borrow checking code can assume that `free_region_map` is - // always the correct map for the current fn. Feels like it'd be - // better to just recompute this, rather than store it, but it's a - // bit of a pain to factor that code out at the moment. - free_region_map: FreeRegionMap, + // tables for the current thing we are checking; set to + // Some in `borrowck_fn` and cleared later + tables: Option<&'a ty::TypeckTables<'tcx>>, // Statistics: stats: BorrowStats @@ -574,19 +567,13 @@ pub enum MovedValueUseKind { // Misc impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { - fn with_temp_region_map(&mut self, id: ast::NodeId, f: F) - where F: for <'b> FnOnce(&'b mut BorrowckCtxt<'a, 'tcx>) - { - let new_free_region_map = self.tcx.free_region_map(id); - let old_free_region_map = mem::replace(&mut self.free_region_map, new_free_region_map); - f(self); - self.free_region_map = old_free_region_map; - } - - pub fn is_subregion_of(&self, r_sub: &'tcx ty::Region, r_sup: &'tcx ty::Region) + pub fn is_subregion_of(&self, + r_sub: &'tcx ty::Region, + r_sup: &'tcx ty::Region) -> bool { - self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) + self.tables.unwrap().free_region_map + .is_subregion_of(self.tcx, r_sub, r_sup) } pub fn report(&self, err: BckError<'tcx>) { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index cf6bf1cf1d483..3dce4398f3b91 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -28,6 +28,7 @@ #![feature(shared)] #![feature(collections_range)] #![feature(collections_bound)] +#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(nonzero)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index e09e260afc8d9..2bce7faf08cec 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,6 +9,7 @@ // except according to those terms. use bitvec::BitMatrix; +use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use std::cell::RefCell; use std::fmt::Debug; use std::mem; @@ -36,10 +37,10 @@ pub struct TransitiveRelation { closure: RefCell>, } -#[derive(Clone, PartialEq, PartialOrd)] +#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)] struct Index(usize); -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] struct Edge { source: Index, target: Index, @@ -54,6 +55,10 @@ impl TransitiveRelation { } } + pub fn is_empty(&self) -> bool { + self.edges.is_empty() + } + fn index(&self, a: &T) -> Option { self.elements.iter().position(|e| *e == *a).map(Index) } @@ -305,6 +310,30 @@ fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { } } +impl Encodable for TransitiveRelation + where T: Encodable + Debug + PartialEq +{ + fn encode(&self, s: &mut E) -> Result<(), E::Error> { + s.emit_struct("TransitiveRelation", 2, |s| { + s.emit_struct_field("elements", 0, |s| self.elements.encode(s))?; + s.emit_struct_field("edges", 1, |s| self.edges.encode(s))?; + Ok(()) + }) + } +} + +impl Decodable for TransitiveRelation + where T: Decodable + Debug + PartialEq +{ + fn decode(d: &mut D) -> Result { + d.read_struct("TransitiveRelation", 2, |d| { + let elements = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?; + let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?; + Ok(TransitiveRelation { elements, edges, closure: RefCell::new(None) }) + }) + } +} + #[test] fn test_one_step() { let mut relation = TransitiveRelation::new(); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d84e9d3fd3731..7f7e27f45ff96 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -122,6 +122,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcx.visit_region_obligations(id); } rcx.resolve_regions_and_report_errors(); + + assert!(self.tables.borrow().free_region_map.is_empty()); + self.tables.borrow_mut().free_region_map = rcx.free_region_map; } /// Region checking during the WF phase for items. `wf_tys` are the @@ -156,10 +159,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcx.resolve_regions_and_report_errors(); - // For the top-level fn, store the free-region-map. We don't store - // any map for closures; they just share the same map as the - // function that created them. - self.tcx.store_free_region_map(fn_id, rcx.free_region_map); + // In this mode, we also copy the free-region-map into the + // tables of the enclosing fcx. In the other regionck modes + // (e.g., `regionck_item`), we don't have an enclosing tables. + assert!(self.tables.borrow().free_region_map.is_empty()); + self.tables.borrow_mut().free_region_map = rcx.free_region_map; } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 28156dd616b3a..aba7c2fcc9455 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -54,6 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_type_nodes(); wbcx.visit_cast_types(); wbcx.visit_lints(); + wbcx.visit_free_region_map(); let tables = self.tcx.alloc_tables(wbcx.tables); self.tcx.tables.borrow_mut().insert(item_def_id, tables); @@ -316,6 +317,14 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints); } + fn visit_free_region_map(&mut self) { + if self.fcx.writeback_errors.get() { + return + } + + self.tables.free_region_map = self.fcx.tables.borrow().free_region_map.clone(); + } + fn visit_anon_types(&self) { if self.fcx.writeback_errors.get() { return From 5c391d7eda317b2f7f0283321292f75b3707aff9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 15 Feb 2017 05:17:30 -0500 Subject: [PATCH 12/33] add `visit_all_bodies_in_krate` helper --- src/librustc/dep_graph/mod.rs | 1 + src/librustc/dep_graph/visit.rs | 10 ++++++++++ src/librustc/ty/mod.rs | 11 +++++++++++ 3 files changed, 22 insertions(+) diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index e365cea6d0e5e..7331756f35b8e 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -25,5 +25,6 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; +pub use self::visit::visit_all_bodies_in_krate; pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index f0a81fd1cfd33..f807437750d01 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -74,3 +74,13 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> }; krate.visit_all_item_likes(&mut tracking_visitor) } + +pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C) + where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), +{ + let krate = tcx.hir.krate(); + for body_id in krate.bodies.keys().cloned() { + let body_owner_def_id = tcx.hir.body_owner_def_id(body_id); + callback(body_owner_def_id, body_id); + } +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 411e14531fab3..a699f316511b7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2674,6 +2674,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor); } + /// Invokes `callback` for each body in the krate. This will + /// create a read edge from `DepNode::Krate` to the current task; + /// it is meant to be run in the context of some global task like + /// `BorrowckCrate`. The callback would then create a task like + /// `BorrowckBody(DefId)` to process each individual item. + pub fn visit_all_bodies_in_krate(self, callback: C) + where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), + { + dep_graph::visit_all_bodies_in_krate(self.global_tcx(), callback) + } + /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` /// with the name of the crate containing the impl. pub fn span_of_impl(self, impl_did: DefId) -> Result { From 252c8d7c4350b607640f2e7e65c370be08e37374 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 05:23:25 -0500 Subject: [PATCH 13/33] rewrite `borrowck_fn` to only use the body-id --- src/librustc_borrowck/borrowck/fragments.rs | 5 ++-- src/librustc_borrowck/borrowck/mod.rs | 31 +++++++++------------ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index dbab3bca52b4e..c0f681680a967 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -27,7 +27,7 @@ use rustc::middle::mem_categorization as mc; use std::mem; use std::rc::Rc; use syntax::ast; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::DUMMY_SP; #[derive(PartialEq, Eq, PartialOrd, Ord)] enum Fragment { @@ -200,7 +200,6 @@ impl FragmentSets { pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - sp: Span, id: ast::NodeId) { let span_err = tcx.hir.attrs(id).iter() .any(|a| a.check_name("rustc_move_fragments")); @@ -208,6 +207,8 @@ pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>, if !span_err && !print { return; } + let sp = tcx.hir.span(id); + let instrument_all_paths = |kind, vec_rc: &Vec| { for (i, mpi) in vec_rc.iter().enumerate() { let lp = || this.path_loan_path(*mpi); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 06133de07576e..07e654c3880cd 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -70,11 +70,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { - borrowck_fn(self, fk, fd, b, s, id, fk.attrs()) + borrowck_fn(self, b); + intravisit::walk_fn(self, fk, fd, b, s, id); } FnKind::Closure(..) => { - borrowck_fn(self, fk, fd, b, s, id, fk.attrs()); + borrowck_fn(self, b); + intravisit::walk_fn(self, fk, fd, b, s, id); } } } @@ -154,24 +156,20 @@ pub struct AnalysisData<'a, 'tcx: 'a> { pub move_data: move_data::FlowedMoveData<'a, 'tcx>, } -fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, - fk: FnKind<'tcx>, - decl: &'tcx hir::FnDecl, - body_id: hir::BodyId, - sp: Span, - id: ast::NodeId, - attributes: &[ast::Attribute]) { - debug!("borrowck_fn(id={})", id); +fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, body_id: hir::BodyId) { + debug!("borrowck_fn(body_id={:?})", body_id); assert!(this.tables.is_none()); - let owner_def_id = this.tcx.hir.local_def_id(this.tcx.hir.body_owner(body_id)); + let owner_id = this.tcx.hir.body_owner(body_id); + let owner_def_id = this.tcx.hir.local_def_id(owner_id); + let attributes = this.tcx.get_attrs(owner_def_id); let tables = this.tcx.item_tables(owner_def_id); this.tables = Some(tables); let body = this.tcx.hir.body(body_id); - if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) { - mir::borrowck_mir(this, id, attributes); + if this.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") { + mir::borrowck_mir(this, owner_id, &attributes); } let cfg = cfg::CFG::new(this.tcx, &body.value); @@ -182,17 +180,14 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, move_data::fragments::instrument_move_fragments(&flowed_moves.move_data, this.tcx, - sp, - id); + owner_id); move_data::fragments::build_unfragmented_map(this, &flowed_moves.move_data, - id); + owner_id); check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body); this.tables = None; - - intravisit::walk_fn(this, fk, decl, body_id, sp, id); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, From 5f5946a3d9a1488d8aaf7976bf6cdf0bbbc0b7a3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 05:47:01 -0500 Subject: [PATCH 14/33] remove the borrowck stats --- src/librustc_borrowck/borrowck/mod.rs | 41 --------------------------- 1 file changed, 41 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 07e654c3880cd..2011cbe416f18 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -104,33 +104,9 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut bccx = BorrowckCtxt { tcx: tcx, tables: None, - stats: BorrowStats { - loaned_paths_same: 0, - loaned_paths_imm: 0, - stable_paths: 0, - guaranteed_paths: 0 - } }; tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); - - if tcx.sess.borrowck_stats() { - println!("--- borrowck stats ---"); - println!("paths requiring guarantees: {}", - bccx.stats.guaranteed_paths); - println!("paths requiring loans : {}", - make_stat(&bccx, bccx.stats.loaned_paths_same)); - println!("paths requiring imm loans : {}", - make_stat(&bccx, bccx.stats.loaned_paths_imm)); - println!("stable paths : {}", - make_stat(&bccx, bccx.stats.stable_paths)); - } - - fn make_stat(bccx: &BorrowckCtxt, stat: usize) -> String { - let total = bccx.stats.guaranteed_paths as f64; - let perc = if total == 0.0 { 0.0 } else { stat as f64 * 100.0 / total }; - format!("{} ({:.0}%)", stat, perc) - } } fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::Item) { @@ -245,12 +221,6 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let mut bccx = BorrowckCtxt { tcx: tcx, tables: None, - stats: BorrowStats { - loaned_paths_same: 0, - loaned_paths_imm: 0, - stable_paths: 0, - guaranteed_paths: 0 - } }; let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body); @@ -266,17 +236,6 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { // tables for the current thing we are checking; set to // Some in `borrowck_fn` and cleared later tables: Option<&'a ty::TypeckTables<'tcx>>, - - // Statistics: - stats: BorrowStats -} - -#[derive(Clone)] -struct BorrowStats { - loaned_paths_same: usize, - loaned_paths_imm: usize, - stable_paths: usize, - guaranteed_paths: usize } /////////////////////////////////////////////////////////////////////////// From b347a23b32ec46c580ce5aa1bbeeccd5142ae9f2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 05:59:48 -0500 Subject: [PATCH 15/33] make `borrowck_fn` and friends create `bccx` --- .../borrowck/gather_loans/mod.rs | 8 +- src/librustc_borrowck/borrowck/mod.rs | 73 +++++++++---------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 1783ca74a2592..b31b54a25415a 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -547,9 +547,15 @@ impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> { } } -pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, body: hir::BodyId) { +pub fn gather_loans_in_static_initializer<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + body: hir::BodyId) { debug!("gather_loans_in_static_initializer(expr={:?})", body); + let bccx = &BorrowckCtxt { + tcx: tcx, + tables: None + }; + let mut sicx = StaticInitializerCtxt { bccx: bccx, body_id: body diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 2011cbe416f18..9c29cd375ff51 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -70,31 +70,43 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { - borrowck_fn(self, b); + borrowck_fn(self.tcx, b); intravisit::walk_fn(self, fk, fd, b, s, id); } FnKind::Closure(..) => { - borrowck_fn(self, b); + borrowck_fn(self.tcx, b); intravisit::walk_fn(self, fk, fd, b, s, id); } } } fn visit_item(&mut self, item: &'tcx hir::Item) { - borrowck_item(self, item); + // Gather loans for items. Note that we don't need + // to check loans for single expressions. The check + // loan step is intended for things that have a data + // flow dependent conditions. + match item.node { + hir::ItemStatic(.., ex) | + hir::ItemConst(_, ex) => { + gather_loans::gather_loans_in_static_initializer(self.tcx, ex); + } + _ => { } + } + + intravisit::walk_item(self, item); } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node { - gather_loans::gather_loans_in_static_initializer(self, expr); + gather_loans::gather_loans_in_static_initializer(self.tcx, expr); } intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { if let hir::ImplItemKind::Const(_, expr) = ii.node { - gather_loans::gather_loans_in_static_initializer(self, expr); + gather_loans::gather_loans_in_static_initializer(self.tcx, expr); } intravisit::walk_impl_item(self, ii); } @@ -109,22 +121,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); } -fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::Item) { - // Gather loans for items. Note that we don't need - // to check loans for single expressions. The check - // loan step is intended for things that have a data - // flow dependent conditions. - match item.node { - hir::ItemStatic(.., ex) | - hir::ItemConst(_, ex) => { - gather_loans::gather_loans_in_static_initializer(this, ex); - } - _ => { } - } - - intravisit::walk_item(this, item); -} - /// Collection of conclusions determined via borrow checker analyses. pub struct AnalysisData<'a, 'tcx: 'a> { pub all_loans: Vec>, @@ -132,38 +128,39 @@ pub struct AnalysisData<'a, 'tcx: 'a> { pub move_data: move_data::FlowedMoveData<'a, 'tcx>, } -fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, body_id: hir::BodyId) { +fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { debug!("borrowck_fn(body_id={:?})", body_id); - assert!(this.tables.is_none()); - let owner_id = this.tcx.hir.body_owner(body_id); - let owner_def_id = this.tcx.hir.local_def_id(owner_id); - let attributes = this.tcx.get_attrs(owner_def_id); - let tables = this.tcx.item_tables(owner_def_id); - this.tables = Some(tables); + let owner_id = tcx.hir.body_owner(body_id); + let owner_def_id = tcx.hir.local_def_id(owner_id); + let attributes = tcx.get_attrs(owner_def_id); + let tables = tcx.item_tables(owner_def_id); + + let mut bccx = &mut BorrowckCtxt { + tcx: tcx, + tables: Some(tables), + }; - let body = this.tcx.hir.body(body_id); + let body = bccx.tcx.hir.body(body_id); - if this.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") { - mir::borrowck_mir(this, owner_id, &attributes); + if bccx.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") { + mir::borrowck_mir(bccx, owner_id, &attributes); } - let cfg = cfg::CFG::new(this.tcx, &body.value); + let cfg = cfg::CFG::new(bccx.tcx, &body.value); let AnalysisData { all_loans, loans: loan_dfcx, move_data: flowed_moves } = - build_borrowck_dataflow_data(this, &cfg, body_id); + build_borrowck_dataflow_data(bccx, &cfg, body_id); move_data::fragments::instrument_move_fragments(&flowed_moves.move_data, - this.tcx, + bccx.tcx, owner_id); - move_data::fragments::build_unfragmented_map(this, + move_data::fragments::build_unfragmented_map(bccx, &flowed_moves.move_data, owner_id); - check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body); - - this.tables = None; + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, From ec648a1ab3b2f3523f2243ebf051cb39f4053902 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sat, 18 Feb 2017 16:39:55 -0500 Subject: [PATCH 16/33] Fix indentation of error message So I just encountered this error for the first time. It's unclear what it means, why I encountered it, or how to fix it. But worst of all, it has a random newline and weird indentation! This commit fixes that last bit. --- src/librustc/ty/inhabitedness/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 24ca476e5ff79..77c863a012318 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -187,7 +187,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { // which contains a Foo<((T, T), (T, T))> // which contains a Foo<(((T, T), (T, T)), ((T, T), (T, T)))> // etc. - let error = format!("reached recursion limit while checking + let error = format!("reached recursion limit while checking \ inhabitedness of `{}`", self); tcx.sess.fatal(&error); } From 9334c39c6defaba1b7aa29627a13463079d378c4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 06:52:16 -0500 Subject: [PATCH 17/33] remove special-case code for statics and just use `borrowck_fn` Fixes #38520 --- src/librustc/cfg/construct.rs | 20 +++---- src/librustc/cfg/mod.rs | 2 +- .../borrowck/gather_loans/mod.rs | 53 ------------------- src/librustc_borrowck/borrowck/mod.rs | 8 +-- src/librustc_driver/lib.rs | 1 + src/librustc_driver/pretty.rs | 23 +++++--- src/librustc_lint/builtin.rs | 2 +- src/test/compile-fail/E0017.rs | 3 +- src/test/compile-fail/E0388.rs | 2 +- .../move-in-static-initializer-issue-38520.rs | 28 ++++++++++ src/test/compile-fail/issue-18118.rs | 2 +- 11 files changed, 61 insertions(+), 83 deletions(-) create mode 100644 src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 595059332895d..5e6566b5fcf54 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -32,7 +32,7 @@ struct LoopScope { } pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: &hir::Expr) -> CFG { + body: &hir::Body) -> CFG { let mut graph = graph::Graph::new(); let entry = graph.add_node(CFGNodeData::Entry); @@ -43,26 +43,18 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let fn_exit = graph.add_node(CFGNodeData::Exit); let body_exit; - // Find the function this expression is from. - let mut node_id = body.id; - loop { - let node = tcx.hir.get(node_id); - if hir::map::blocks::FnLikeNode::from_node(node).is_some() { - break; - } - let parent = tcx.hir.get_parent_node(node_id); - assert!(node_id != parent); - node_id = parent; - } + // Find the tables for this body. + let owner_def_id = tcx.hir.local_def_id(tcx.hir.body_owner(body.id())); + let tables = tcx.item_tables(owner_def_id); let mut cfg_builder = CFGBuilder { tcx: tcx, - tables: tcx.item_tables(tcx.hir.local_def_id(node_id)), + tables: tables, graph: graph, fn_exit: fn_exit, loop_scopes: Vec::new() }; - body_exit = cfg_builder.expr(body, entry); + body_exit = cfg_builder.expr(&body.value, entry); cfg_builder.add_contained_edge(body_exit, fn_exit); let CFGBuilder {graph, ..} = cfg_builder; CFG {graph: graph, diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index 43434b884c8d4..1473dbb1676f3 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -59,7 +59,7 @@ pub type CFGEdge = graph::Edge; impl CFG { pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: &hir::Expr) -> CFG { + body: &hir::Body) -> CFG { construct::construct(tcx, body) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index b31b54a25415a..28b6c7a13f171 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -28,9 +28,6 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax_pos::Span; use rustc::hir; -use rustc::hir::Expr; -use rustc::hir::intravisit; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use self::restrictions::RestrictionResult; @@ -514,53 +511,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } } -/// Context used while gathering loans on static initializers -/// -/// This visitor walks static initializer's expressions and makes -/// sure the loans being taken are sound. -struct StaticInitializerCtxt<'a, 'tcx: 'a> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - body_id: hir::BodyId, -} - -impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &'tcx Expr) { - if let hir::ExprAddrOf(mutbl, ref base) = ex.node { - let infcx = self.bccx.tcx.borrowck_fake_infer_ctxt(self.body_id); - let mc = mc::MemCategorizationContext::new(&infcx); - let base_cmt = mc.cat_expr(&base).unwrap(); - let borrow_kind = ty::BorrowKind::from_mutbl(mutbl); - // Check that we don't allow borrows of unsafe static items. - let err = check_aliasability(self.bccx, ex.span, - BorrowViolation(euv::AddrOf), - base_cmt, borrow_kind).is_err(); - if err { - return; // reported an error, no sense in reporting more. - } - } - - intravisit::walk_expr(self, ex); - } -} - -pub fn gather_loans_in_static_initializer<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: hir::BodyId) { - debug!("gather_loans_in_static_initializer(expr={:?})", body); - - let bccx = &BorrowckCtxt { - tcx: tcx, - tables: None - }; - - let mut sicx = StaticInitializerCtxt { - bccx: bccx, - body_id: body - }; - - let body = sicx.bccx.tcx.hir.body(body); - sicx.visit_body(body); -} diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 9c29cd375ff51..613f28138a519 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -89,7 +89,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { match item.node { hir::ItemStatic(.., ex) | hir::ItemConst(_, ex) => { - gather_loans::gather_loans_in_static_initializer(self.tcx, ex); + borrowck_fn(self.tcx, ex); } _ => { } } @@ -99,14 +99,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node { - gather_loans::gather_loans_in_static_initializer(self.tcx, expr); + borrowck_fn(self.tcx, expr); } intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { if let hir::ImplItemKind::Const(_, expr) = ii.node { - gather_loans::gather_loans_in_static_initializer(self.tcx, expr); + borrowck_fn(self.tcx, expr); } intravisit::walk_impl_item(self, ii); } @@ -147,7 +147,7 @@ fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { mir::borrowck_mir(bccx, owner_id, &attributes); } - let cfg = cfg::CFG::new(bccx.tcx, &body.value); + let cfg = cfg::CFG::new(bccx.tcx, &body); let AnalysisData { all_loans, loans: loan_dfcx, move_data: flowed_moves } = diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7fd4fa44ca45d..9810f121ef2c1 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -24,6 +24,7 @@ #![deny(warnings)] #![feature(box_syntax)] +#![feature(loop_break_value)] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 21fe13997b787..54b4ae61ebe43 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -718,13 +718,24 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, mode: PpFlowGraphMode, mut out: W) -> io::Result<()> { - let cfg = match code { - blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr), - blocks::Code::FnLike(fn_like) => { - let body = tcx.hir.body(fn_like.body()); - cfg::CFG::new(tcx, &body.value) - }, + let body_id = match code { + blocks::Code::Expr(expr) => { + // Find the function this expression is from. + let mut node_id = expr.id; + loop { + let node = tcx.hir.get(node_id); + if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) { + break n.body(); + } + let parent = tcx.hir.get_parent_node(node_id); + assert!(node_id != parent); + node_id = parent; + } + } + blocks::Code::FnLike(fn_like) => fn_like.body(), }; + let body = tcx.hir.body(body_id); + let cfg = cfg::CFG::new(tcx, &body); let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let lcfg = LabelledCFG { hir_map: &tcx.hir, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1592d17817641..c363810c50d2f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -712,7 +712,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // to have behaviour like the above, rather than // e.g. accidentally recurring after an assert. - let cfg = cfg::CFG::new(cx.tcx, &body.value); + let cfg = cfg::CFG::new(cx.tcx, &body); let mut work_queue = vec![cfg.entry]; let mut reached_exit_without_self_call = false; diff --git a/src/test/compile-fail/E0017.rs b/src/test/compile-fail/E0017.rs index 44d2f158d20bb..c6bec6090f242 100644 --- a/src/test/compile-fail/E0017.rs +++ b/src/test/compile-fail/E0017.rs @@ -19,8 +19,7 @@ static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| NOTE statics require immutable values //~| ERROR E0017 //~| NOTE statics require immutable values - //~| ERROR E0388 - //~| NOTE cannot write data in a static definition + //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 //~| NOTE statics require immutable values //~| ERROR E0017 diff --git a/src/test/compile-fail/E0388.rs b/src/test/compile-fail/E0388.rs index 13f2c23d8c4a9..2c88039d373e5 100644 --- a/src/test/compile-fail/E0388.rs +++ b/src/test/compile-fail/E0388.rs @@ -15,7 +15,7 @@ const CR: &'static mut i32 = &mut C; //~ ERROR E0017 //~| ERROR E0017 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| ERROR E0017 - //~| ERROR E0388 + //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 //~| ERROR E0017 diff --git a/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs new file mode 100644 index 0000000000000..3c1980e5b366c --- /dev/null +++ b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs @@ -0,0 +1,28 @@ +// Copyright 2012 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. + +// Regression test for #38520. Check that moves of `Foo` are not +// permitted as `Foo` is not copy (even in a static/const +// initializer). + +#![feature(const_fn)] + +struct Foo(usize); + +const fn get(x: Foo) -> usize { + x.0 +} + +const X: Foo = Foo(22); +static Y: usize = get(*&X); //~ ERROR E0507 +const Z: usize = get(*&X); //~ ERROR E0507 + +fn main() { +} diff --git a/src/test/compile-fail/issue-18118.rs b/src/test/compile-fail/issue-18118.rs index 3afb34f037bcc..35e57dffb6c45 100644 --- a/src/test/compile-fail/issue-18118.rs +++ b/src/test/compile-fail/issue-18118.rs @@ -13,6 +13,6 @@ pub fn main() { //~^ ERROR blocks in constants are limited to items and tail expressions let p = 3; //~^ ERROR blocks in constants are limited to items and tail expressions - &p + &p //~ ERROR `p` does not live long enough }; } From cde3c15ff5b9216d5428c4d9f665051fdfb58c4f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 07:07:02 -0500 Subject: [PATCH 18/33] use `visit_all_bodies_in_krate` for borrowck instead of item-likes --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc_borrowck/borrowck/mod.rs | 67 ++++----------------------- 2 files changed, 10 insertions(+), 59 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 006de1c06e2d9..4e81ec231afdf 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -90,6 +90,7 @@ pub enum DepNode { // things read/modify that MIR. Mir(D), + BorrowCheckKrate, BorrowCheck(D), RvalueCheck(D), Reachability, @@ -176,6 +177,7 @@ impl DepNode { match *self { Krate => Some(Krate), + BorrowCheckKrate => Some(BorrowCheckKrate), CollectLanguageItems => Some(CollectLanguageItems), CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 613f28138a519..f0381dd1b70bf 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -45,7 +45,7 @@ use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; -use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; +use rustc::hir::intravisit::{self, Visitor}; pub mod check_loans; @@ -60,65 +60,14 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; -impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir) - } - - fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl, - b: hir::BodyId, s: Span, id: ast::NodeId) { - match fk { - FnKind::ItemFn(..) | - FnKind::Method(..) => { - borrowck_fn(self.tcx, b); - intravisit::walk_fn(self, fk, fd, b, s, id); - } - - FnKind::Closure(..) => { - borrowck_fn(self.tcx, b); - intravisit::walk_fn(self, fk, fd, b, s, id); - } - } - } - - fn visit_item(&mut self, item: &'tcx hir::Item) { - // Gather loans for items. Note that we don't need - // to check loans for single expressions. The check - // loan step is intended for things that have a data - // flow dependent conditions. - match item.node { - hir::ItemStatic(.., ex) | - hir::ItemConst(_, ex) => { - borrowck_fn(self.tcx, ex); - } - _ => { } - } - - intravisit::walk_item(self, item); - } - - fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { - if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node { - borrowck_fn(self.tcx, expr); - } - intravisit::walk_trait_item(self, ti); - } - - fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { - if let hir::ImplItemKind::Const(_, expr) = ii.node { - borrowck_fn(self.tcx, expr); - } - intravisit::walk_impl_item(self, ii); - } -} - pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut bccx = BorrowckCtxt { - tcx: tcx, - tables: None, - }; - - tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); + tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| { + tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || { + borrowck_fn(tcx, body_id); + }); + }); + }); } /// Collection of conclusions determined via borrow checker analyses. From e49e43a6f2a7f63a8b630ff9b0aada46bf9f51bf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 07:12:21 -0500 Subject: [PATCH 19/33] remove `Option` from the `tables` field --- src/librustc_borrowck/borrowck/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f0381dd1b70bf..f5d6780213b20 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -87,7 +87,7 @@ fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { let mut bccx = &mut BorrowckCtxt { tcx: tcx, - tables: Some(tables), + tables: tables, }; let body = bccx.tcx.hir.body(body_id); @@ -159,17 +159,20 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer. pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: hir::BodyId, + body_id: hir::BodyId, cfg: &cfg::CFG) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>) { + let owner_id = tcx.hir.body_owner(body_id); + let owner_def_id = tcx.hir.local_def_id(owner_id); + let tables = tcx.item_tables(owner_def_id); let mut bccx = BorrowckCtxt { tcx: tcx, - tables: None, + tables: tables, }; - let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body); + let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id); (bccx, dataflow_data) } @@ -181,7 +184,7 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { // tables for the current thing we are checking; set to // Some in `borrowck_fn` and cleared later - tables: Option<&'a ty::TypeckTables<'tcx>>, + tables: &'a ty::TypeckTables<'tcx>, } /////////////////////////////////////////////////////////////////////////// @@ -472,8 +475,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { r_sup: &'tcx ty::Region) -> bool { - self.tables.unwrap().free_region_map - .is_subregion_of(self.tcx, r_sub, r_sup) + self.tables.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) } pub fn report(&self, err: BckError<'tcx>) { From 198208be0e818d99e42281568a2eec305175c6c9 Mon Sep 17 00:00:00 2001 From: Jakob Demler Date: Sun, 19 Feb 2017 18:15:44 +0100 Subject: [PATCH 20/33] Fixed some small issues --- src/doc/book/src/procedural-macros.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md index 468a8f904a45a..e22ef85546bdb 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/src/procedural-macros.md @@ -210,12 +210,15 @@ Hello, World! My name is FrenchToast Hello, World! My name is Waffles ``` +We've done it! + ## 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. +For example, the user might want to overwrite the name that is printed in the `hello_world()` method. This can be achieved with custom attributes: + ```rust,ignore #[derive(HelloWorld)] #[HelloWorldName = "the best Pancakes"] @@ -232,8 +235,8 @@ 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: +The compiler needs to know that we're handling 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))] @@ -244,11 +247,11 @@ 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. +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: +But how do we tell the user, that we do not accept enums? +The idiomatic way to report errors in procedural macros is to panic: ```rust,ignore fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { @@ -257,14 +260,14 @@ fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { if let syn::Body::Struct(_) = ast.body { // Yes, this is a struct quote! { - impl HelloWorld for #name { + 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! + //Nope. This is an Enum. We cannot handle these! panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!"); } } From 7770e9aaa3deb4b77a3c335eaf7ff418d1028fb1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 19 Feb 2017 21:35:40 -0500 Subject: [PATCH 21/33] fix run-pass test that tried to move in const --- src/test/run-pass/const-enum-vec-index.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs index 4af6a6d10d5bf..8b8cbaf978822 100644 --- a/src/test/run-pass/const-enum-vec-index.rs +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[derive(Copy, Clone)] enum E { V1(isize), V0 } const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)]; static C0: E = C[0]; From deb53a395866f6270ff24a8ecb1a01a00331fc44 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Feb 2017 21:18:16 -0500 Subject: [PATCH 22/33] walk the bodies "in order" by traversing the crate Otherwise the errors from borrowck come out in an unpredictable order. --- src/librustc/dep_graph/visit.rs | 28 ++++++++++++++++++++++++--- src/librustc/hir/map/mod.rs | 29 ++++++++++++++++------------ src/test/ui/span/mut-arg-hint.stderr | 16 +++++++-------- 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index f807437750d01..0d10049bc1e4e 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -11,6 +11,7 @@ use hir; use hir::def_id::DefId; use hir::itemlikevisit::ItemLikeVisitor; +use hir::intravisit::{self, NestedVisitorMap, Visitor}; use ty::TyCtxt; use super::dep_node::DepNode; @@ -78,9 +79,30 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C) where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), { + // NB: we use a visitor here rather than walking the keys of the + // hashmap so as to ensure we visit the bodies "in order". + let krate = tcx.hir.krate(); - for body_id in krate.bodies.keys().cloned() { - let body_owner_def_id = tcx.hir.body_owner_def_id(body_id); - callback(body_owner_def_id, body_id); + intravisit::walk_crate(&mut V { tcx, callback }, krate); + + struct V<'a, 'tcx: 'a, C> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + callback: C + } + + impl<'a, 'tcx, C> Visitor<'tcx> for V<'a, 'tcx, C> + where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), + { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.tcx.hir) + } + + fn visit_body(&mut self, body: &'tcx hir::Body) { + let body_id = body.id(); + let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id); + (self.callback)(body_owner_def_id, body_id); + + intravisit::walk_body(self, body); + } } } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 9f31b5b456b9f..093c931ae54c9 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -168,43 +168,48 @@ impl<'hir> MapEntry<'hir> { }) } - fn is_body_owner(self, node_id: NodeId) -> bool { + fn associated_body(self) -> Option { match self { EntryItem(_, item) => { match item.node { ItemConst(_, body) | ItemStatic(.., body) | - ItemFn(_, _, _, _, _, body) => body.node_id == node_id, - _ => false + ItemFn(_, _, _, _, _, body) => Some(body), + _ => None, } } EntryTraitItem(_, item) => { match item.node { TraitItemKind::Const(_, Some(body)) | - TraitItemKind::Method(_, TraitMethod::Provided(body)) => { - body.node_id == node_id - } - _ => false + TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body), + _ => None } } EntryImplItem(_, item) => { match item.node { ImplItemKind::Const(_, body) | - ImplItemKind::Method(_, body) => body.node_id == node_id, - _ => false + ImplItemKind::Method(_, body) => Some(body), + _ => None, } } EntryExpr(_, expr) => { match expr.node { - ExprClosure(.., body, _) => body.node_id == node_id, - _ => false + ExprClosure(.., body, _) => Some(body), + _ => None, } } - _ => false + _ => None + } + } + + fn is_body_owner(self, node_id: NodeId) -> bool { + match self.associated_body() { + Some(b) => b.node_id == node_id, + None => false, } } } diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index e4ed062214715..01364c0714407 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -1,11 +1,3 @@ -error: cannot borrow immutable borrowed content `*a` as mutable - --> $DIR/mut-arg-hint.rs:18:5 - | -17 | pub fn foo<'a>(mut a: &'a String) { - | ---------- use `&'a mut String` here to make mutable -18 | a.push_str("foo"); - | ^ cannot borrow as mutable - error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:13:9 | @@ -14,6 +6,14 @@ error: cannot borrow immutable borrowed content `*a` as mutable 13 | a.push_str("bar"); | ^ cannot borrow as mutable +error: cannot borrow immutable borrowed content `*a` as mutable + --> $DIR/mut-arg-hint.rs:18:5 + | +17 | pub fn foo<'a>(mut a: &'a String) { + | ---------- use `&'a mut String` here to make mutable +18 | a.push_str("foo"); + | ^ cannot borrow as mutable + error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:25:9 | From 538556decf759942bf0dabdbbc689774b5018f38 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Feb 2017 10:35:16 -0500 Subject: [PATCH 23/33] kill the code path for E0388 This was specific to the old special-case handling of statics in borrowck. --- src/librustc_borrowck/borrowck/mod.rs | 12 +++++++----- src/librustc_borrowck/diagnostics.rs | 22 +--------------------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f5d6780213b20..47b614a81ae25 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -801,11 +801,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } mc::AliasableStatic | mc::AliasableStaticMut => { - let mut err = struct_span_err!( - self.tcx.sess, span, E0388, - "{} in a static location", prefix); - err.span_label(span, &format!("cannot write data in a static definition")); - err + // This path cannot occur. It happens when we have an + // `&mut` or assignment to a static. But in the case + // of `static X`, we get a mutability violation first, + // and never get here. In the case of `static mut X`, + // that is unsafe and hence the aliasability error is + // ignored. + span_bug!(span, "aliasability violation for static `{}`", prefix) } mc::AliasableBorrowed => { let mut e = struct_span_err!( diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 88f739d1c74bb..db4a1701e976b 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -287,27 +287,7 @@ https://doc.rust-lang.org/std/cell/ "##, E0388: r##" -A mutable borrow was attempted in a static location. - -Erroneous code example: - -```compile_fail,E0388 -static X: i32 = 1; - -static STATIC_REF: &'static mut i32 = &mut X; -// error: cannot borrow data mutably in a static location - -const CONST_REF: &'static mut i32 = &mut X; -// error: cannot borrow data mutably in a static location -``` - -To fix this error, you have to use constant borrow: - -``` -static X: i32 = 1; - -static STATIC_REF: &'static i32 = &X; -``` +E0388 was removed and is no longer issued. "##, E0389: r##" From f69ce166334e3a7fe7278dc2c2fff28a2eaaecf1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Feb 2017 10:55:40 -0500 Subject: [PATCH 24/33] switch bodies to a btreemap --- src/librustc/hir/lowering.rs | 6 +++--- src/librustc/hir/mod.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8a4acb3d03880..c12de6807b103 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -46,7 +46,7 @@ use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; use hir::def::{Def, PathResolution}; use session::Session; -use util::nodemap::{DefIdMap, NodeMap, FxHashMap}; +use util::nodemap::{DefIdMap, NodeMap}; use std::collections::BTreeMap; use std::iter; @@ -77,7 +77,7 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, - bodies: FxHashMap, + bodies: BTreeMap, type_def_lifetime_params: DefIdMap, } @@ -111,7 +111,7 @@ pub fn lower_crate(sess: &Session, items: BTreeMap::new(), trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), - bodies: FxHashMap(), + bodies: BTreeMap::new(), type_def_lifetime_params: DefIdMap(), }.lower_crate(krate) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4ebe416e1bfe6..6f03073c803c6 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -31,7 +31,7 @@ pub use self::PathParameters::*; use hir::def::Def; use hir::def_id::DefId; -use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; +use util::nodemap::{NodeMap, FxHashSet}; use syntax_pos::{Span, ExpnId, DUMMY_SP}; use syntax::codemap::{self, Spanned}; @@ -409,7 +409,7 @@ pub struct Crate { pub trait_items: BTreeMap, pub impl_items: BTreeMap, - pub bodies: FxHashMap, + pub bodies: BTreeMap, } impl Crate { From fed58f315a0175f3bc4f8f84a23c5062fd69ced6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Feb 2017 12:23:47 -0500 Subject: [PATCH 25/33] store the visit order in the Crate --- src/librustc/dep_graph/visit.rs | 28 ++----------------- src/librustc/hir/lowering.rs | 10 +++++++ src/librustc/hir/mod.rs | 6 ++++ .../calculate_svh/svh_visitor.rs | 1 + 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 0d10049bc1e4e..a34a3591c151d 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -11,7 +11,6 @@ use hir; use hir::def_id::DefId; use hir::itemlikevisit::ItemLikeVisitor; -use hir::intravisit::{self, NestedVisitorMap, Visitor}; use ty::TyCtxt; use super::dep_node::DepNode; @@ -79,30 +78,9 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C) where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), { - // NB: we use a visitor here rather than walking the keys of the - // hashmap so as to ensure we visit the bodies "in order". - let krate = tcx.hir.krate(); - intravisit::walk_crate(&mut V { tcx, callback }, krate); - - struct V<'a, 'tcx: 'a, C> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - callback: C - } - - impl<'a, 'tcx, C> Visitor<'tcx> for V<'a, 'tcx, C> - where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), - { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::All(&self.tcx.hir) - } - - fn visit_body(&mut self, body: &'tcx hir::Body) { - let body_id = body.id(); - let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id); - (self.callback)(body_owner_def_id, body_id); - - intravisit::walk_body(self, body); - } + for &body_id in &krate.body_ids { + let body_owner_def_id = tcx.hir.body_owner_def_id(body_id); + callback(body_owner_def_id, body_id); } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c12de6807b103..77f11c94c2128 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -185,6 +185,7 @@ impl<'a> LoweringContext<'a> { let module = self.lower_mod(&c.module); let attrs = self.lower_attrs(&c.attrs); let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); + let body_ids = body_ids(&self.bodies); hir::Crate { module: module, @@ -195,6 +196,7 @@ impl<'a> LoweringContext<'a> { trait_items: self.trait_items, impl_items: self.impl_items, bodies: self.bodies, + body_ids: body_ids, } } @@ -2408,3 +2410,11 @@ impl<'a> LoweringContext<'a> { } } } + +fn body_ids(bodies: &BTreeMap) -> Vec { + // Sorting by span ensures that we get things in order within a + // file, and also puts the files in a sensible order. + let mut body_ids: Vec<_> = bodies.keys().cloned().collect(); + body_ids.sort_by_key(|b| bodies[b].value.span); + body_ids +} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6f03073c803c6..8715c89c6540d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -410,6 +410,12 @@ pub struct Crate { pub trait_items: BTreeMap, pub impl_items: BTreeMap, pub bodies: BTreeMap, + + /// A list of the body ids written out in the order in which they + /// appear in the crate. If you're going to process all the bodies + /// in the crate, you should iterate over this list rather than the keys + /// of bodies. + pub body_ids: Vec, } impl Crate { diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index c7512f2971b33..40e534e25e998 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -1166,6 +1166,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { trait_items: _, impl_items: _, bodies: _, + body_ids: _, } = *krate; visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); From 58a9dd3f7e851193c732a8f850294d91906edb6b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 Feb 2017 21:12:35 +0100 Subject: [PATCH 26/33] Add missing urls and examples into Barrier structs --- src/libstd/sync/barrier.rs | 76 ++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index fc4fd4ce92b1b..f15e7ff891684 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -14,6 +14,8 @@ use sync::{Mutex, Condvar}; /// A barrier enables multiple threads to synchronize the beginning /// of some computation. /// +/// # Examples +/// /// ``` /// use std::sync::{Arc, Barrier}; /// use std::thread; @@ -50,8 +52,19 @@ struct BarrierState { /// A result returned from wait. /// -/// Currently this opaque structure only has one method, `.is_leader()`. Only +/// Currently this opaque structure only has one method, [`.is_leader()`]. Only /// one thread will receive a result that will return `true` from this function. +/// +/// [`.is_leader()`]: #method.is_leader +/// +/// # Examples +/// +/// ``` +/// use std::sync::Barrier; +/// +/// let barrier = Barrier::new(1); +/// let barrier_wait_result = barrier.wait(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct BarrierWaitResult(bool); @@ -65,8 +78,18 @@ impl fmt::Debug for Barrier { impl Barrier { /// Creates a new barrier that can block a given number of threads. /// - /// A barrier will block `n`-1 threads which call `wait` and then wake up - /// all threads at once when the `n`th thread calls `wait`. + /// A barrier will block `n`-1 threads which call [`wait`] and then wake up + /// all threads at once when the `n`th thread calls [`wait`]. + /// + /// [`wait`]: #method.wait + /// + /// # Examples + /// + /// ``` + /// use std::sync::Barrier; + /// + /// let barrier = Barrier::new(10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(n: usize) -> Barrier { Barrier { @@ -84,10 +107,37 @@ impl Barrier { /// Barriers are re-usable after all threads have rendezvoused once, and can /// be used continuously. /// - /// A single (arbitrary) thread will receive a `BarrierWaitResult` that - /// returns `true` from `is_leader` when returning from this function, and + /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that + /// returns `true` from [`is_leader`] when returning from this function, and /// all other threads will receive a result that will return `false` from - /// `is_leader` + /// [`is_leader`]. + /// + /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html + /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Barrier}; + /// use std::thread; + /// + /// let mut handles = Vec::with_capacity(10); + /// let barrier = Arc::new(Barrier::new(10)); + /// for _ in 0..10 { + /// let c = barrier.clone(); + /// // The same messages will be printed together. + /// // You will NOT see any interleaving. + /// handles.push(thread::spawn(move|| { + /// println!("before wait"); + /// c.wait(); + /// println!("after wait"); + /// })); + /// } + /// // Wait for other threads to finish. + /// for handle in handles { + /// handle.join().unwrap(); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn wait(&self) -> BarrierWaitResult { let mut lock = self.lock.lock().unwrap(); @@ -120,10 +170,22 @@ impl fmt::Debug for BarrierWaitResult { } impl BarrierWaitResult { - /// Returns whether this thread from `wait` is the "leader thread". + /// Returns whether this thread from [`wait`] is the "leader thread". /// /// Only one thread will have `true` returned from their result, all other /// threads will have `false` returned. + /// + /// [`wait`]: struct.Barrier.html#method.wait + /// + /// # Examples + /// + /// ``` + /// use std::sync::Barrier; + /// + /// let barrier = Barrier::new(1); + /// let barrier_wait_result = barrier.wait(); + /// println!("{:?}", barrier_wait_result.is_leader()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_leader(&self) -> bool { self.0 } } From 689dc26b685fb88993e055c4c2155b9a4b2c3797 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 22 Feb 2017 17:13:22 +0300 Subject: [PATCH 27/33] Clarify thread::Builder::stack_size --- src/libstd/thread/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 93e320c45223c..2bc066d3fea55 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -235,7 +235,7 @@ pub use self::local::{LocalKey, LocalKeyState}; pub struct Builder { // A name for the thread-to-be, for identification in panic messages name: Option, - // The size of the stack for the spawned thread + // The size of the stack for the spawned thread in bytes stack_size: Option, } @@ -289,14 +289,17 @@ impl Builder { self } - /// Sets the size of the stack for the new thread. + /// Sets the size of the stack (in bytes) for the new thread. + /// + /// The actual stack size may be greater than this value if + /// the platform specifies minimal stack size. /// /// # Examples /// /// ``` /// use std::thread; /// - /// let builder = thread::Builder::new().stack_size(10); + /// let builder = thread::Builder::new().stack_size(32 * 1024); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stack_size(mut self, size: usize) -> Builder { From 6b8e1756c7f3bf4d94973ef0702e252277d10763 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Wed, 22 Feb 2017 21:18:52 -0800 Subject: [PATCH 28/33] Update std::fmt module docs for landing of #33642. --- src/libcollections/fmt.rs | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index bd74848a01d83..079541235a25e 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -62,7 +62,7 @@ //! //! A format string is required to use all of its arguments, otherwise it is a //! compile-time error. You may refer to the same argument more than once in the -//! format string, although it must always be referred to with the same type. +//! format string. //! //! ## Named parameters //! @@ -89,19 +89,8 @@ //! //! ## Argument types //! -//! Each argument's type is dictated by the format string. It is a requirement -//! that every argument is only ever referred to by one type. For example, this -//! is an invalid format string: -//! -//! ```text -//! {0:x} {0:o} -//! ``` -//! -//! This is invalid because the first argument is both referred to as a -//! hexadecimal as well as an -//! octal. -//! -//! There are various parameters which do require a particular type, however. +//! Each argument's type is dictated by the format string. +//! There are various parameters which require a particular type, however. //! An example is the `{:.*}` syntax, which sets the number of decimal places //! in floating-point types: //! @@ -113,13 +102,7 @@ //! //! If this syntax is used, then the number of characters to print precedes the //! actual object being formatted, and the number of characters must have the -//! type `usize`. Although a `usize` can be printed with `{}`, it is invalid to -//! reference an argument as such. For example this is another invalid format -//! string: -//! -//! ```text -//! {:.*} {0} -//! ``` +//! type `usize`. //! //! ## Formatting traits //! From 84ca464f9c731b07a68cb264ecd37c9aacc2e475 Mon Sep 17 00:00:00 2001 From: Luxko Date: Thu, 23 Feb 2017 01:44:27 -0600 Subject: [PATCH 29/33] Update exception-safety.md Fix variable name typo --- src/doc/nomicon/src/exception-safety.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/nomicon/src/exception-safety.md b/src/doc/nomicon/src/exception-safety.md index 80e72cd5e36c9..0fb98a617688e 100644 --- a/src/doc/nomicon/src/exception-safety.md +++ b/src/doc/nomicon/src/exception-safety.md @@ -93,7 +93,7 @@ uselessly. We would rather have the following: ```text bubble_up(heap, index): let elem = heap[index] - while index != 0 && element < heap[parent(index)]: + while index != 0 && elem < heap[parent(index)]: heap[index] = heap[parent(index)] index = parent(index) heap[index] = elem From 729948f95853e0d7228e02dffca53539ddb0a9e0 Mon Sep 17 00:00:00 2001 From: Luxko Date: Thu, 23 Feb 2017 01:50:16 -0600 Subject: [PATCH 30/33] Update exception-safety.md --- src/doc/nomicon/src/exception-safety.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/nomicon/src/exception-safety.md b/src/doc/nomicon/src/exception-safety.md index 0fb98a617688e..a3cbc6abd69cc 100644 --- a/src/doc/nomicon/src/exception-safety.md +++ b/src/doc/nomicon/src/exception-safety.md @@ -137,7 +137,7 @@ If Rust had `try` and `finally` like in Java, we could do the following: bubble_up(heap, index): let elem = heap[index] try: - while index != 0 && element < heap[parent(index)]: +        while index != 0 && elem < heap[parent(index)]: heap[index] = heap[parent(index)] index = parent(index) finally: From 088b727456dde36954ca0e68de3d783c40ffa426 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Feb 2017 11:43:30 +0100 Subject: [PATCH 31/33] Add missing urls in MutexGuard docs --- src/libstd/sync/mutex.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 0d6ad5e38e98b..97b84d59218ac 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -133,11 +133,13 @@ unsafe impl Sync for Mutex { } /// dropped (falls out of scope), the lock will be unlocked. /// /// The data protected by the mutex can be access through this guard via its -/// `Deref` and `DerefMut` implementations. +/// [`Deref`] and [`DerefMut`] implementations. /// /// This structure is created by the [`lock()`] and [`try_lock()`] methods on /// [`Mutex`]. /// +/// [`Deref`]: ../../std/ops/trait.Deref.html +/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html /// [`lock()`]: struct.Mutex.html#method.lock /// [`try_lock()`]: struct.Mutex.html#method.try_lock /// [`Mutex`]: struct.Mutex.html From 30b0ed0bb6725f73e3b8f4efc36106be42ae1ce8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Feb 2017 07:04:29 -0800 Subject: [PATCH 32/33] rustbuild: Retry downloads by default Don't rely on curl's --retry, it appears to not work for some errors like SSL errors. --- src/bootstrap/bootstrap.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 7ca7ef4bd720c..6b1b8ddf56f2a 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -59,6 +59,16 @@ def delete_if_present(path, verbose): def download(path, url, probably_big, verbose): + for x in range(0, 4): + try: + _download(path, url, probably_big, verbose, True) + return + except RuntimeError: + print("\nspurious failure, trying again") + _download(path, url, probably_big, verbose, False) + + +def _download(path, url, probably_big, verbose, exception): if probably_big or verbose: print("downloading {}".format(url)) # see http://serverfault.com/questions/301128/how-to-download @@ -66,13 +76,16 @@ def download(path, url, probably_big, verbose): run(["PowerShell.exe", "/nologo", "-Command", "(New-Object System.Net.WebClient)" ".DownloadFile('{}', '{}')".format(url, path)], - verbose=verbose) + verbose=verbose, + exception=exception) else: if probably_big or verbose: option = "-#" else: option = "-s" - run(["curl", option, "--retry", "3", "-Sf", "-o", path, url], verbose=verbose) + run(["curl", option, "--retry", "3", "-Sf", "-o", path, url], + verbose=verbose, + exception=exception) def verify(path, sha_path, verbose): @@ -112,7 +125,7 @@ def unpack(tarball, dst, verbose=False, match=None): shutil.move(tp, fp) shutil.rmtree(os.path.join(dst, fname)) -def run(args, verbose=False): +def run(args, verbose=False, exception=False): if verbose: print("running: " + ' '.join(args)) sys.stdout.flush() @@ -122,7 +135,7 @@ def run(args, verbose=False): code = ret.wait() if code != 0: err = "failed to run: " + ' '.join(args) - if verbose: + if verbose or exception: raise RuntimeError(err) sys.exit(err) From 7c52cadfc38671147f8d9dba577c086a1cdba0ec Mon Sep 17 00:00:00 2001 From: Tom Anderson Date: Fri, 24 Feb 2017 11:48:42 +0000 Subject: [PATCH 33/33] Correct another typo in procedural macros chapter of the Book. --- src/doc/book/src/procedural-macros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md index 079324d56d1e6..f194c710284ca 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/src/procedural-macros.md @@ -170,7 +170,7 @@ a representation of our type (which can be either a `struct` or an `enum`). Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html), there is some useful information there. We are able to get the name of the type using `ast.ident`. The `quote!` macro lets us write up the Rust code -that we wish to return and convert it into `Tokens`. `quote!` let's us use some +that we wish to return and convert it into `Tokens`. `quote!` lets us use some really cool templating mechanics; we simply write `#name` and `quote!` will replace it with the variable named `name`. You can even do some repetition similar to regular macros work. You should check out the