From 8a64cf7fb72ca93608be19e13dd83c23168b17d7 Mon Sep 17 00:00:00 2001 From: sinkuu Date: Sat, 25 Feb 2017 22:05:30 +0900 Subject: [PATCH 01/73] Fix suggestion span error with a line containing non-ASCIIs --- src/librustc_errors/lib.rs | 3 ++- src/test/ui/span/suggestion-non-ascii.rs | 16 ++++++++++++++++ src/test/ui/span/suggestion-non-ascii.stderr | 11 +++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/span/suggestion-non-ascii.rs create mode 100644 src/test/ui/span/suggestion-non-ascii.stderr diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d7bd5ed23c2b0..4c889dad8ca50 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -90,7 +90,8 @@ impl CodeSuggestion { hi_opt: Option<&Loc>) { let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize())); if let Some(line) = line_opt { - if line.len() > lo { + if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) { + let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi)); buf.push_str(match hi_opt { Some(hi) => &line[lo..hi], None => &line[lo..], diff --git a/src/test/ui/span/suggestion-non-ascii.rs b/src/test/ui/span/suggestion-non-ascii.rs new file mode 100644 index 0000000000000..67dbe1dc7b566 --- /dev/null +++ b/src/test/ui/span/suggestion-non-ascii.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +fn main() { + let tup = (1,); + println!("☃{}", tup[0]); +} + diff --git a/src/test/ui/span/suggestion-non-ascii.stderr b/src/test/ui/span/suggestion-non-ascii.stderr new file mode 100644 index 0000000000000..385c211f393c6 --- /dev/null +++ b/src/test/ui/span/suggestion-non-ascii.stderr @@ -0,0 +1,11 @@ +error: cannot index a value of type `({integer},)` + --> $DIR/suggestion-non-ascii.rs:14:21 + | +14 | println!("☃{}", tup[0]); + | ^^^^^^ + | +help: to access tuple elements, use tuple indexing syntax as shown + | println!("☃{}", tup.0); + +error: aborting due to previous error + From 53d3c8939e3cf45f9e08fd360d9289e9440b6ece Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 10:57:10 +0100 Subject: [PATCH 02/73] Dont bug! on user error --- src/librustc/infer/region_inference/graphviz.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 95ce8d39ff488..a67049f72852b 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -91,7 +91,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( }; if output_template.is_empty() { - bug!("empty string provided as RUST_REGION_GRAPH"); + panic!("empty string provided as RUST_REGION_GRAPH"); } if output_template.contains('%') { From 54a1c8b1a66ce6dd4f46fc6063612607897b2638 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 10:59:36 +0100 Subject: [PATCH 03/73] Fix indentation in region infer docs --- src/librustc/infer/region_inference/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/region_inference/README.md b/src/librustc/infer/region_inference/README.md index 80da861139b42..4f24b37682eb5 100644 --- a/src/librustc/infer/region_inference/README.md +++ b/src/librustc/infer/region_inference/README.md @@ -122,14 +122,14 @@ every expression, block, and pattern (patterns are considered to relevant bindings). So, for example: fn foo(x: isize, y: isize) { // -+ - // +------------+ // | - // | +-----+ // | - // | +-+ +-+ +-+ // | - // | | | | | | | // | - // v v v v v v v // | - let z = x + y; // | - ... // | - } // -+ + // +------------+ // | + // | +-----+ // | + // | +-+ +-+ +-+ // | + // | | | | | | | // | + // v v v v v v v // | + let z = x + y; // | + ... // | + } // -+ fn bar() { ... } From 2a40918928818bdaa8bdc3780ce5d6449bb69f85 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 11:17:14 +0100 Subject: [PATCH 04/73] Syntax highlighting in region infer docs --- src/librustc/infer/region_inference/README.md | 108 ++++++++++-------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/src/librustc/infer/region_inference/README.md b/src/librustc/infer/region_inference/README.md index 4f24b37682eb5..f5c254a459407 100644 --- a/src/librustc/infer/region_inference/README.md +++ b/src/librustc/infer/region_inference/README.md @@ -121,17 +121,19 @@ every expression, block, and pattern (patterns are considered to "execute" by testing the value they are applied to and creating any relevant bindings). So, for example: - fn foo(x: isize, y: isize) { // -+ - // +------------+ // | - // | +-----+ // | - // | +-+ +-+ +-+ // | - // | | | | | | | // | - // v v v v v v v // | - let z = x + y; // | - ... // | - } // -+ - - fn bar() { ... } +```rust +fn foo(x: isize, y: isize) { // -+ +// +------------+ // | +// | +-----+ // | +// | +-+ +-+ +-+ // | +// | | | | | | | // | +// v v v v v v v // | + let z = x + y; // | + ... // | +} // -+ + +fn bar() { ... } +``` In this example, there is a region for the fn body block as a whole, and then a subregion for the declaration of the local variable. @@ -160,7 +162,9 @@ this, we get a lot of spurious errors around nested calls, in particular when combined with `&mut` functions. For example, a call like this one - self.foo(self.bar()) +```rust +self.foo(self.bar()) +``` where both `foo` and `bar` are `&mut self` functions will always yield an error. @@ -168,20 +172,22 @@ an error. Here is a more involved example (which is safe) so we can see what's going on: - struct Foo { f: usize, g: usize } - ... - fn add(p: &mut usize, v: usize) { - *p += v; - } - ... - fn inc(p: &mut usize) -> usize { - *p += 1; *p - } - fn weird() { - let mut x: Box = box Foo { ... }; - 'a: add(&mut (*x).f, - 'b: inc(&mut (*x).f)) // (..) - } +```rust +struct Foo { f: usize, g: usize } +// ... +fn add(p: &mut usize, v: usize) { + *p += v; +} +// ... +fn inc(p: &mut usize) -> usize { + *p += 1; *p +} +fn weird() { + let mut x: Box = box Foo { ... }; + 'a: add(&mut (*x).f, + 'b: inc(&mut (*x).f)) // (..) +} +``` The important part is the line marked `(..)` which contains a call to `add()`. The first argument is a mutable borrow of the field `f`. The @@ -197,16 +203,18 @@ can see that this error is unnecessary. Let's examine the lifetimes involved with `'a` in detail. We'll break apart all the steps involved in a call expression: - 'a: { - 'a_arg1: let a_temp1: ... = add; - 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; - 'a_arg3: let a_temp3: usize = { - let b_temp1: ... = inc; - let b_temp2: &'b = &'b mut (*x).f; - 'b_call: b_temp1(b_temp2) - }; - 'a_call: a_temp1(a_temp2, a_temp3) // (**) - } +```rust +'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; + 'a_arg3: let a_temp3: usize = { + let b_temp1: ... = inc; + let b_temp2: &'b = &'b mut (*x).f; + 'b_call: b_temp1(b_temp2) + }; + 'a_call: a_temp1(a_temp2, a_temp3) // (**) +} +``` Here we see that the lifetime `'a` includes a number of substatements. In particular, there is this lifetime I've called `'a_call` that @@ -225,19 +233,21 @@ it will not be *dereferenced* during the evaluation of the second argument, it can still be *invalidated* by that evaluation. Consider this similar but unsound example: - struct Foo { f: usize, g: usize } - ... - fn add(p: &mut usize, v: usize) { - *p += v; - } - ... - fn consume(x: Box) -> usize { - x.f + x.g - } - fn weird() { - let mut x: Box = box Foo { ... }; - 'a: add(&mut (*x).f, consume(x)) // (..) - } +```rust +struct Foo { f: usize, g: usize } +// ... +fn add(p: &mut usize, v: usize) { + *p += v; +} +// ... +fn consume(x: Box) -> usize { + x.f + x.g +} +fn weird() { + let mut x: Box = box Foo { ... }; + 'a: add(&mut (*x).f, consume(x)) // (..) +} +``` In this case, the second argument to `add` actually consumes `x`, thus invalidating the first argument. From be49671df9772ee8b82a53c147f8a3cd115fd8f0 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 11:19:48 +0100 Subject: [PATCH 05/73] Improve a bit more --- src/librustc/infer/region_inference/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/infer/region_inference/README.md b/src/librustc/infer/region_inference/README.md index f5c254a459407..b564faf3d0c24 100644 --- a/src/librustc/infer/region_inference/README.md +++ b/src/librustc/infer/region_inference/README.md @@ -183,7 +183,7 @@ fn inc(p: &mut usize) -> usize { *p += 1; *p } fn weird() { - let mut x: Box = box Foo { ... }; + let mut x: Box = box Foo { /* ... */ }; 'a: add(&mut (*x).f, 'b: inc(&mut (*x).f)) // (..) } From 90e94d97f2635af1f976a1c6ad2f1296df05c784 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 11:39:00 +0100 Subject: [PATCH 06/73] Syntax highlight and note about current rust in infer docs --- src/librustc/infer/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/README.md b/src/librustc/infer/README.md index c835189820e51..68e64b8b7bfc8 100644 --- a/src/librustc/infer/README.md +++ b/src/librustc/infer/README.md @@ -152,7 +152,7 @@ course, it depends on the program. The main case which fails today that I would like to support is: -```text +```rust fn foo(x: T, y: T) { ... } fn bar() { @@ -168,6 +168,8 @@ because the type variable `T` is merged with the type variable for `X`, and thus inherits its UB/LB of `@mut int`. This leaves no flexibility for `T` to later adjust to accommodate `@int`. +Note: `@` and `@mut` are replaced with `Rc` and `Rc>` in current Rust. + ### What to do when not all bounds are present In the prior discussion we assumed that A.ub was not top and B.lb was From 234753a5cafcda561cef0e5117bad80205ee92ad Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Tue, 7 Mar 2017 21:49:43 -0500 Subject: [PATCH 07/73] Fix missing backtick typo Fixes rendering of the end of the `Configure and Make` section. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93415adc423f4..79f11144a073d 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ $ ./configure $ make && sudo make install ``` -When using the configure script, the generated config.mk` file may override the +When using the configure script, the generated `config.mk` file may override the `config.toml` file. To go back to the `config.toml` file, delete the generated `config.mk` file. From 319890487a531c38b8afd4cdabcdac2c7dd8dc5b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 7 Mar 2017 16:17:16 +0200 Subject: [PATCH 08/73] Disallow subtyping between T and U in T: Unsize. --- src/librustc/traits/select.rs | 6 ++-- src/test/compile-fail/issue-40288-2.rs | 41 ++++++++++++++++++++++++++ src/test/compile-fail/issue-40288.rs | 30 +++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/issue-40288-2.rs create mode 100644 src/test/compile-fail/issue-40288.rs diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4c4ace0d8baf9..38ea1e4a19b91 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2461,7 +2461,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let new_trait = tcx.mk_dynamic( ty::Binder(tcx.mk_existential_predicates(iter)), r_b); let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, new_trait, target) + self.infcx.eq_types(false, &obligation.cause, new_trait, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2520,7 +2520,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // [T; n] -> [T]. (&ty::TyArray(a, _), &ty::TySlice(b)) => { let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, a, b) + self.infcx.eq_types(false, &obligation.cause, a, b) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); } @@ -2583,7 +2583,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, new_struct, target) + self.infcx.eq_types(false, &obligation.cause, new_struct, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); diff --git a/src/test/compile-fail/issue-40288-2.rs b/src/test/compile-fail/issue-40288-2.rs new file mode 100644 index 0000000000000..c1e8cb8b6defb --- /dev/null +++ b/src/test/compile-fail/issue-40288-2.rs @@ -0,0 +1,41 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn prove_static(_: &'static T) {} + +fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { + let mut out = [x]; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + { + let slice: &mut [_] = &mut out; + slice[0] = y; + } + out[0] +} + +struct Struct { + head: T, + _tail: U +} + +fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { + let mut out = Struct { head: x, _tail: [()] }; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + { + let dst: &mut Struct<_, [()]> = &mut out; + dst.head = y; + } + out.head +} + +fn main() { + prove_static(lifetime_transmute_slice("", &String::from("foo"))); + prove_static(lifetime_transmute_struct("", &String::from("bar"))); +} diff --git a/src/test/compile-fail/issue-40288.rs b/src/test/compile-fail/issue-40288.rs new file mode 100644 index 0000000000000..b5418e85bec78 --- /dev/null +++ b/src/test/compile-fail/issue-40288.rs @@ -0,0 +1,30 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn save_ref<'a>(refr: &'a i32, to: &mut [&'a i32]) { + for val in &mut *to { + *val = refr; + } +} + +fn main() { + let ref init = 0i32; + let ref mut refr = 1i32; + + let mut out = [init]; + + save_ref(&*refr, &mut out); + + // This shouldn't be allowed as `refr` is borrowed + *refr = 3; //~ ERROR cannot assign to `*refr` because it is borrowed + + // Prints 3?! + println!("{:?}", out[0]); +} From 79a7ee8d831d7bacc4d52cd76bbc0dcd15fddfe5 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Wed, 8 Mar 2017 21:17:55 +0100 Subject: [PATCH 09/73] fix UB in repr(packed) tests --- .../extern-fn-with-packed-struct/test.rs | 24 ++++++++++++++++++- src/test/run-pass/packed-struct-vec.rs | 21 +++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/test/run-make/extern-fn-with-packed-struct/test.rs b/src/test/run-make/extern-fn-with-packed-struct/test.rs index c0f55893a3abe..9e81636e36703 100644 --- a/src/test/run-make/extern-fn-with-packed-struct/test.rs +++ b/src/test/run-make/extern-fn-with-packed-struct/test.rs @@ -8,14 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt; + #[repr(packed)] -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone)] struct Foo { a: i8, b: i16, c: i8 } +impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.a == other.a && self.b == other.b && self.c == other.c + } +} + +impl fmt::Debug for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let a = self.a; + let b = self.b; + let c = self.c; + + f.debug_struct("Foo") + .field("a", &a) + .field("b", &b) + .field("c", &c) + .finish() + } +} + #[link(name = "test", kind = "static")] extern { fn foo(f: Foo) -> Foo; diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs index 4b32b881be738..57407b8422371 100644 --- a/src/test/run-pass/packed-struct-vec.rs +++ b/src/test/run-pass/packed-struct-vec.rs @@ -8,15 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt; use std::mem; #[repr(packed)] -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone)] struct Foo { bar: u8, baz: u64 } +impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.bar == other.bar && self.baz == other.baz + } +} + +impl fmt::Debug for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bar = self.bar; + let baz = self.baz; + + f.debug_struct("Foo") + .field("bar", &bar) + .field("baz", &baz) + .finish() + } +} + pub fn main() { let foos = [Foo { bar: 1, baz: 2 }; 10]; From edf5dc66c1ec243bb2a60385b094cde719c0a492 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 8 Mar 2017 21:53:28 -0500 Subject: [PATCH 10/73] Box docs: no allocation is done for ZSTs. --- src/liballoc/boxed.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d0fce70612868..43b0d72186a29 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -225,6 +225,8 @@ impl Drop for IntermediateBox { impl Box { /// Allocates memory on the heap and then places `x` into it. /// + /// This doesn't actually allocate if `T` is zero-sized. + /// /// # Examples /// /// ``` From 74bc7fda8c1cdb8bbf29d9901cbfc31a2e0da86b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 14:36:49 +0200 Subject: [PATCH 11/73] Overhaul coercion to use the lazy InferOk obligations passing. --- src/librustc_typeck/check/autoderef.rs | 14 +- src/librustc_typeck/check/coercion.rs | 194 +++++++++++-------------- 2 files changed, 99 insertions(+), 109 deletions(-) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index ca0ab8f1e8c77..1aab4853a4f64 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -12,6 +12,7 @@ use astconv::AstConv; use super::FnCtxt; +use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; @@ -149,6 +150,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) where I: IntoIterator + { + let fcx = self.fcx; + fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); + } + + pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I) + -> InferOk<'tcx, ()> + where I: IntoIterator { let methods: Vec<_> = self.steps .iter() @@ -176,8 +185,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } } - for obligation in self.obligations { - self.fcx.register_predicate(obligation); + InferOk { + value: (), + obligations: self.obligations } } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 53759cc115d1c..651058728816e 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -64,7 +64,8 @@ use check::FnCtxt; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::infer::{Coercion, InferOk, TypeTrace}; +use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace}; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, @@ -75,9 +76,7 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use syntax::abi; use syntax::feature_gate; -use util::common::indent; -use std::cell::RefCell; use std::collections::VecDeque; use std::ops::Deref; @@ -85,7 +84,6 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, - unsizing_obligations: RefCell>>, } impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { @@ -95,7 +93,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { } } -type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>; +type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>; fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, to_mutbl: hir::Mutability) @@ -108,44 +106,53 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } } +fn identity<'tcx>() -> Adjust<'tcx> { + Adjust::DerefRef { + autoderefs: 0, + autoref: None, + unsize: false, + } +} + +fn success<'tcx>(kind: Adjust<'tcx>, + target: Ty<'tcx>, + obligations: traits::PredicateObligations<'tcx>) + -> CoerceResult<'tcx> { + Ok(InferOk { + value: Adjustment { + kind, + target + }, + obligations + }) +} + impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self { Coerce { fcx: fcx, cause: cause, use_lub: false, - unsizing_obligations: RefCell::new(vec![]), } } - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { self.commit_if_ok(|_| { let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { self.lub(false, trace, &a, &b) - .map(|ok| self.register_infer_ok_obligations(ok)) } else { self.sub(false, trace, &a, &b) - .map(|InferOk { value, obligations }| { - self.fcx.register_predicates(obligations); - value - }) } }) } - /// Unify two types (using sub or lub) and produce a noop coercion. - fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - self.unify(&a, &b).and_then(|ty| self.identity(ty)) - } - - /// Synthesize an identity adjustment. - fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> { - Ok((ty, Adjust::DerefRef { - autoderefs: 0, - autoref: None, - unsize: false, - })) + /// Unify two types (using sub or lub) and produce a specific coercion. + fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>) + -> CoerceResult<'tcx> { + self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| { + success(kind, ty, obligations) + }) } fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> @@ -158,11 +165,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return self.identity(b); + return success(identity(), b, vec![]); } if a.is_never() { - return Ok((b, Adjust::NeverToAny)); + return success(Adjust::NeverToAny, b, vec![]); } // Consider coercing the subtype to a DST @@ -208,7 +215,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify_and_identity(a, b) + self.unify_and(a, b, identity()) } } } @@ -240,7 +247,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; (r_a, mt_a) } - _ => return self.unify_and_identity(a, b), + _ => return self.unify_and(a, b, identity()), }; let span = self.cause.span; @@ -248,7 +255,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let mut first_error = None; let mut r_borrow_var = None; let mut autoderef = self.autoderef(span, a); - let mut success = None; + let mut found = None; for (referent_ty, autoderefs) in autoderef.by_ref() { if autoderefs == 0 { @@ -346,8 +353,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mt_b.mutbl, // [1] above }); match self.unify(derefd_ty_a, b) { - Ok(ty) => { - success = Some((ty, autoderefs)); + Ok(ok) => { + found = Some((ok, autoderefs)); break; } Err(err) => { @@ -363,7 +370,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let (ty, autoderefs) = match success { + let (InferOk { value: ty, mut obligations }, autoderefs) = match found { Some(d) => d, None => { let err = first_error.expect("coerce_borrowed_pointer had no error"); @@ -372,12 +379,6 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } }; - // This commits the obligations to the fulfillcx. After this succeeds, - // this snapshot can't be rolled back. - autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs()); - - // Now apply the autoref. We have to extract the region out of - // the final ref type we got. if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as @@ -391,8 +392,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U - return self.identity(ty); + return success(identity(), ty, obligations); } + + // Now apply the autoref. We have to extract the region out of + // the final ref type we got. let r_borrow = match ty.sty { ty::TyRef(r_borrow, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), @@ -402,11 +406,15 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty, autoderefs, autoref); - Ok((ty, Adjust::DerefRef { + + let pref = LvaluePreference::from_mutbl(mt_b.mutbl); + obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations); + + success(Adjust::DerefRef { autoderefs: autoderefs, autoref: autoref, unsize: false, - })) + }, ty, obligations) } @@ -451,7 +459,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Use a FIFO queue for this custom fulfillment procedure. let mut queue = VecDeque::new(); - let mut leftover_predicates = vec![]; + let mut obligations = vec![]; // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.cause.span, self.body_id); @@ -467,7 +475,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), _ => { - leftover_predicates.push(obligation); + obligations.push(obligation); continue; } }; @@ -495,33 +503,30 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - *self.unsizing_obligations.borrow_mut() = leftover_predicates; - - let adjustment = Adjust::DerefRef { + success(Adjust::DerefRef { autoderefs: if reborrow.is_some() { 1 } else { 0 }, autoref: reborrow, unsize: true, - }; - debug!("Success, coerced with {:?}", adjustment); - Ok((target, adjustment)) + }, target, obligations) } fn coerce_from_safe_fn(&self, a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, - b: Ty<'tcx>) + b: Ty<'tcx>, + to_unsafe: Adjust<'tcx>, + normal: Adjust<'tcx>) -> CoerceResult<'tcx> { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - return self.unify_and_identity(unsafe_a, b) - .map(|(ty, _)| (ty, Adjust::UnsafeFnPointer)); + return self.unify_and(unsafe_a, b, to_unsafe); } _ => {} } } - self.unify_and_identity(a, b) + self.unify_and(a, b, normal) } fn coerce_from_fn_pointer(&self, @@ -536,7 +541,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let b = self.shallow_resolve(b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - self.coerce_from_safe_fn(a, fn_ty_a, b) + self.coerce_from_safe_fn(a, fn_ty_a, b, + Adjust::UnsafeFnPointer, identity()) } fn coerce_from_fn_item(&self, @@ -554,10 +560,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { match b.sty { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); - self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b) - .map(|(ty, _)| (ty, Adjust::ReifyFnPointer)) + self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b, + Adjust::ReifyFnPointer, Adjust::ReifyFnPointer) } - _ => self.unify_and_identity(a, b), + _ => self.unify_and(a, b, identity()), } } @@ -582,7 +588,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { self.cause.span, feature_gate::GateIssue::Language, feature_gate::CLOSURE_TO_FN_COERCION); - return self.unify_and_identity(a, b); + return self.unify_and(a, b, identity()); } // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` @@ -607,10 +613,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let pointer_ty = self.tcx.mk_fn_ptr(converted_sig); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); - self.unify_and_identity(pointer_ty, b) - .map(|(ty, _)| (ty, Adjust::ClosureFnPointer)) + self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer) } - _ => self.unify_and_identity(a, b), + _ => self.unify_and(a, b, identity()), } } @@ -625,7 +630,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.unify_and_identity(a, b); + return self.unify_and(a, b, identity()); } }; @@ -634,50 +639,22 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mutbl_b, ty: mt_a.ty, }); - let (ty, noop) = self.unify_and_identity(a_unsafe, b)?; coerce_mutbls(mt_a.mutbl, mutbl_b)?; - // Although references and unsafe ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. - Ok((ty, - if is_ref { - Adjust::DerefRef { - autoderefs: 1, - autoref: Some(AutoBorrow::RawPtr(mutbl_b)), - unsize: false, - } - } else if mt_a.mutbl != mutbl_b { - Adjust::MutToConstPointer - } else { - noop - })) - } -} - -fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>, - exprs: &E, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> RelateResult<'tcx, Adjustment<'tcx>> - where E: Fn() -> I, - I: IntoIterator -{ - - let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?; - - let fcx = coerce.fcx; - if let Adjust::DerefRef { unsize: true, .. } = adjust { - let mut obligations = coerce.unsizing_obligations.borrow_mut(); - for obligation in obligations.drain(..) { - fcx.register_predicate(obligation); - } + self.unify_and(a_unsafe, b, if is_ref { + Adjust::DerefRef { + autoderefs: 1, + autoref: Some(AutoBorrow::RawPtr(mutbl_b)), + unsize: false, + } + } else if mt_a.mutbl != mutbl_b { + Adjust::MutToConstPointer + } else { + identity() + }) } - - Ok(Adjustment { - kind: adjust, - target: ty - }) } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -694,9 +671,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); - let mut coerce = Coerce::new(self, cause); + let coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { - let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; + let ok = coerce.coerce(&|| Some(expr), source, target)?; + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); match self.tables.borrow().adjustments.get(&expr.id) { @@ -773,9 +751,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty)); + let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty)); match result { - Ok(adjustment) => { + Ok(ok) => { + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { self.write_adjustment(new.id, adjustment); } @@ -816,7 +795,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) { Err(_) => { // Avoid giving strange errors on failed attempts. if let Some(e) = first_error { @@ -828,7 +807,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } } - Ok(adjustment) => { + Ok(ok) => { + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { let mut tables = self.tables.borrow_mut(); for expr in exprs() { From 4eeede3e0f2496994b4c0bbaa59927066d642807 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sat, 4 Mar 2017 14:59:49 +0100 Subject: [PATCH 12/73] fix emscripten test detection --- src/bootstrap/check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index dfe96b51799c0..68b3623a53f25 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -550,7 +550,7 @@ fn find_tests(dir: &Path, let filename = e.file_name().into_string().unwrap(); if (target.contains("windows") && filename.ends_with(".exe")) || (!target.contains("windows") && !filename.contains(".")) || - (target.contains("emscripten") && filename.contains(".js")){ + (target.contains("emscripten") && filename.ends_with(".js")) { dst.push(e.path()); } } From da6e7c8f3aa97602bf1bf67b8389c7d3ef3fe11e Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 9 Mar 2017 13:31:26 +0100 Subject: [PATCH 13/73] Distinguish the ways `CStr::from_bytes_with_nul` can fail --- src/libstd/ffi/c_str.rs | 46 +++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index bc678fcb8385b..bfb0aa6e1a122 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -154,7 +154,28 @@ pub struct NulError(usize, Vec); /// byte was found too early in the slice provided or one wasn't found at all. #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstr_from_bytes", since = "1.10.0")] -pub struct FromBytesWithNulError { _a: () } +pub struct FromBytesWithNulError { + kind: FromBytesWithNulErrorKind, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +enum FromBytesWithNulErrorKind { + InteriorNul(usize), + NotNulTerminated, +} + +impl FromBytesWithNulError { + fn interior_nul(pos: usize) -> FromBytesWithNulError { + FromBytesWithNulError { + kind: FromBytesWithNulErrorKind::InteriorNul(pos), + } + } + fn not_nul_terminated() -> FromBytesWithNulError { + FromBytesWithNulError { + kind: FromBytesWithNulErrorKind::NotNulTerminated, + } + } +} /// An error returned from `CString::into_string` to indicate that a UTF-8 error /// was encountered during the conversion. @@ -458,14 +479,23 @@ impl From for io::Error { #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl Error for FromBytesWithNulError { fn description(&self) -> &str { - "data provided is not null terminated or contains an interior nul byte" + match self.kind { + FromBytesWithNulErrorKind::InteriorNul(..) => + "data provided contains an interior nul byte", + FromBytesWithNulErrorKind::NotNulTerminated => + "data provided is not nul terminated", + } } } #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl fmt::Display for FromBytesWithNulError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) + f.write_str(self.description())?; + if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { + write!(f, " at byte pos {}", pos)?; + } + Ok(()) } } @@ -559,10 +589,14 @@ impl CStr { #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { - if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) { - Err(FromBytesWithNulError { _a: () }) + let nul_pos = memchr::memchr(0, bytes); + if let Some(nul_pos) = nul_pos { + if nul_pos + 1 != bytes.len() { + return Err(FromBytesWithNulError::interior_nul(nul_pos)); + } + Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }) } else { - Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) + Err(FromBytesWithNulError::not_nul_terminated()) } } From 57c989caa1db0b000ff5e9fd2ebb0e6557a3cf30 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sat, 4 Mar 2017 10:07:55 -0500 Subject: [PATCH 14/73] Fix botched member variable rename --- src/tools/build-manifest/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index ceefcc9e0ec46..cbafa9e0bd272 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -218,7 +218,7 @@ impl Builder { self.package("rust-docs", &mut manifest.pkg, TARGETS); self.package("rust-src", &mut manifest.pkg, &["*"]); - if self.channel == "nightly" { + if self.rust_release == "nightly" { self.package("rust-analysis", &mut manifest.pkg, TARGETS); } @@ -271,7 +271,7 @@ impl Builder { target: target.to_string(), }); } - if self.channel == "nightly" { + if self.rust_release == "nightly" { extensions.push(Component { pkg: "rust-analysis".to_string(), target: target.to_string(), From 3e2390ff9cf95d9b35474cfb190b0c88a2b268c0 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Thu, 2 Mar 2017 23:39:15 -0500 Subject: [PATCH 15/73] Restore creating the channel-rust-$channel-date.txt files --- src/tools/build-manifest/src/main.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index cbafa9e0bd272..b9c8a84844465 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -183,15 +183,19 @@ impl Builder { let mut manifest = BTreeMap::new(); manifest.insert("manifest-version".to_string(), toml::Value::String(manifest_version)); - manifest.insert("date".to_string(), toml::Value::String(date)); + manifest.insert("date".to_string(), toml::Value::String(date.clone())); manifest.insert("pkg".to_string(), toml::encode(&pkg)); let manifest = toml::Value::Table(manifest).to_string(); let filename = format!("channel-rust-{}.toml", self.rust_release); self.write_manifest(&manifest, &filename); + let filename = format!("channel-rust-{}-date.txt", self.rust_release); + self.write_date_stamp(&date, &filename); + if self.rust_release != "beta" && self.rust_release != "nightly" { self.write_manifest(&manifest, "channel-rust-stable.toml"); + self.write_date_stamp(&date, "channel-rust-stable-date.txt"); } } @@ -411,4 +415,11 @@ impl Builder { self.hash(&dst); self.sign(&dst); } + + fn write_date_stamp(&self, date: &str, name: &str) { + let dst = self.output.join(name); + t!(t!(File::create(&dst)).write_all(date.as_bytes())); + self.hash(&dst); + self.sign(&dst); + } } From 58ff4f67e3a1d099d3c4cb8ccb554ee9fd0a16cd Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Sun, 5 Mar 2017 16:11:11 +0100 Subject: [PATCH 16/73] rustbuild: expose LLVM_PARALLEL_LINK_JOBS This allows limiting the number of linker jobs to avoid swapping when linking LLVM with debug info. --- src/bootstrap/config.rs | 3 +++ src/bootstrap/config.toml.example | 8 ++++++++ src/bootstrap/native.rs | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 438ce6103d624..87c35e0502ce6 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -59,6 +59,7 @@ pub struct Config { pub llvm_static_stdcpp: bool, pub llvm_link_shared: bool, pub llvm_targets: Option, + pub llvm_link_jobs: Option, // rust codegen options pub rust_optimize: bool, @@ -179,6 +180,7 @@ struct Llvm { version_check: Option, static_libstdcpp: Option, targets: Option, + link_jobs: Option, } #[derive(RustcDecodable, Default, Clone)] @@ -333,6 +335,7 @@ impl Config { set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); config.llvm_targets = llvm.targets.clone(); + config.llvm_link_jobs = llvm.link_jobs; } if let Some(ref rust) = toml.rust { diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 30763e38a336f..776bd729119e2 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -53,6 +53,14 @@ # Rust team and file an issue if you need assistance in porting! #targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" +# Cap the number of parallel linker invocations when compiling LLVM. +# This can be useful when building LLVM with debug info, which significantly +# increases the size of binaries and consequently the memory required by +# each linker process. +# If absent or 0, linker invocations are treated like any other job and +# controlled by rustbuild's -j parameter. +#link-jobs = 0 + # ============================================================================= # General build configuration options # ============================================================================= diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 483f45fdd6218..c13235b9c7680 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -115,6 +115,12 @@ pub fn llvm(build: &Build, target: &str) { cfg.define("LLVM_BUILD_32_BITS", "ON"); } + if let Some(num_linkers) = build.config.llvm_link_jobs { + if num_linkers > 0 { + cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); + } + } + // http://llvm.org/docs/HowToCrossCompileLLVM.html if target != build.config.build { // FIXME: if the llvm root for the build triple is overridden then we From 8062cfb37294082ad5825a105e47e0b7b50a7269 Mon Sep 17 00:00:00 2001 From: Charlie Fan Date: Thu, 9 Mar 2017 07:50:48 +0000 Subject: [PATCH 17/73] Implement placement-in protocol for and `VecDeque` --- src/libcollections/vec_deque.rs | 185 ++++++++++++++++++++++++---- src/libcollectionstest/lib.rs | 1 + src/libcollectionstest/vec_deque.rs | 24 +++- 3 files changed, 184 insertions(+), 26 deletions(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 8d42045ff1637..24f57c506304c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -22,7 +22,7 @@ use core::cmp::Ordering; use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; -use core::ops::{Index, IndexMut}; +use core::ops::{Index, IndexMut, Place, Placer, InPlace}; use core::ptr; use core::ptr::Shared; use core::slice; @@ -1087,14 +1087,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_front(&mut self, value: T) { - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); self.tail = self.wrap_sub(self.tail, 1); let tail = self.tail; @@ -1117,14 +1110,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_back(&mut self, value: T) { - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); let head = self.head; self.head = self.wrap_add(self.head, 1); @@ -1257,14 +1243,7 @@ impl VecDeque { #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn insert(&mut self, index: usize, value: T) { assert!(index <= self.len(), "index out of bounds"); - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); // Move the least number of elements in the ring buffer and insert // the given object @@ -1762,6 +1741,69 @@ impl VecDeque { self.truncate(len - del); } } + + // This may panic or abort + #[inline] + fn grow_if_necessary(&mut self) { + if self.is_full() { + let old_cap = self.cap(); + self.buf.double(); + unsafe { + self.handle_cap_increase(old_cap); + } + debug_assert!(!self.is_full()); + } + } + + /// Returns a place for insertion at the back of the `VecDeque`. + /// + /// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.place_back() <- 3; + /// buf.place_back() <- 4; + /// assert_eq!(&buf, &[3, 4]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_back(&mut self) -> PlaceBack { + PlaceBack { vec_deque: self } + } + + /// Returns a place for insertion at the front of the `VecDeque`. + /// + /// Using this method with placement syntax is equivalent to [`push_front`](#method.push_front), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.place_front() <- 3; + /// buf.place_front() <- 4; + /// assert_eq!(&buf, &[4, 3]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_front(&mut self) -> PlaceFront { + PlaceFront { vec_deque: self } + } } impl VecDeque { @@ -2442,6 +2484,98 @@ impl From> for Vec { } } +/// A place for insertion at the back of a `VecDeque`. +/// +/// See [`VecDeque::place_back`](struct.VecDeque.html#method.place_back) for details. +#[must_use = "places do nothing unless written to with `<-` syntax"] +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol are subject to change", + issue = "30172")] +#[derive(Debug)] +pub struct PlaceBack<'a, T: 'a> { + vec_deque: &'a mut VecDeque, +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Placer for PlaceBack<'a, T> { + type Place = PlaceBack<'a, T>; + + fn make_place(self) -> Self { + self.vec_deque.grow_if_necessary(); + self + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Place for PlaceBack<'a, T> { + fn pointer(&mut self) -> *mut T { + unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) } + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> InPlace for PlaceBack<'a, T> { + type Owner = &'a mut T; + + unsafe fn finalize(mut self) -> &'a mut T { + let head = self.vec_deque.head; + self.vec_deque.head = self.vec_deque.wrap_add(head, 1); + &mut *(self.vec_deque.ptr().offset(head as isize)) + } +} + +/// A place for insertion at the front of a `VecDeque`. +/// +/// See [`VecDeque::place_front`](struct.VecDeque.html#method.place_front) for details. +#[must_use = "places do nothing unless written to with `<-` syntax"] +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol are subject to change", + issue = "30172")] +#[derive(Debug)] +pub struct PlaceFront<'a, T: 'a> { + vec_deque: &'a mut VecDeque, +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Placer for PlaceFront<'a, T> { + type Place = PlaceFront<'a, T>; + + fn make_place(self) -> Self { + self.vec_deque.grow_if_necessary(); + self + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Place for PlaceFront<'a, T> { + fn pointer(&mut self) -> *mut T { + let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); + unsafe { self.vec_deque.ptr().offset(tail as isize) } + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> InPlace for PlaceFront<'a, T> { + type Owner = &'a mut T; + + unsafe fn finalize(mut self) -> &'a mut T { + self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); + &mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize)) + } +} + #[cfg(test)] mod tests { use test; @@ -2797,4 +2931,5 @@ mod tests { } } } + } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 849d240169169..d97d9b8ab83f6 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -32,6 +32,7 @@ extern crate collections; extern crate test; extern crate std_unicode; +extern crate core; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index 1541061a19842..f2935c05d4f7a 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -10,7 +10,7 @@ use std::collections::VecDeque; use std::fmt::Debug; -use std::collections::vec_deque::Drain; +use std::collections::vec_deque::{Drain}; use self::Taggy::*; use self::Taggypar::*; @@ -1000,3 +1000,25 @@ fn test_is_empty() { assert!(v.iter_mut().is_empty()); assert!(v.into_iter().is_empty()); } + +#[test] +fn test_placement_in() { + let mut buf: VecDeque = VecDeque::new(); + buf.place_back() <- 1; + buf.place_back() <- 2; + assert_eq!(buf, [1,2]); + + buf.place_front() <- 3; + buf.place_front() <- 4; + assert_eq!(buf, [4,3,1,2]); + + { + let ptr_head = buf.place_front() <- 5; + assert_eq!(*ptr_head, 5); + } + { + let ptr_tail = buf.place_back() <- 6; + assert_eq!(*ptr_tail, 6); + } + assert_eq!(buf, [5,4,3,1,2,6]); +} From 84d1f6aa82123c2951042aff99e43bdb894d3d81 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 8 Mar 2017 22:17:42 +0200 Subject: [PATCH 18/73] Do not bother creating StorageLive for TyNever Keeps MIR cleaner, `StorageLive(_: !)` makes no sense anyway. --- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/test/mir-opt/issue-38669.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 69b9570200921..42d9ab4d2bf27 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { (https://github.com/rust-lang/rust/issues/39283)"); } - if temp_lifetime.is_some() { + if !expr_ty.is_never() && temp_lifetime.is_some() { this.cfg.push(block, Statement { source_info: source_info, kind: StatementKind::StorageLive(temp.clone()) diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 1d452907cf59a..fbbffe8953b38 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -35,7 +35,6 @@ fn main() { // } // // bb2: { -// StorageLive(_6); // _0 = (); // StorageDead(_4); // StorageDead(_1); From 4078b255897d0cdba8a864bd8bb1da92d827a32d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 9 Mar 2017 19:02:59 +0100 Subject: [PATCH 19/73] Clean up rustdoc css --- src/librustdoc/html/static/rustdoc.css | 33 ++---- src/librustdoc/html/static/styles/main.css | 114 +++++++++++++++------ 2 files changed, 89 insertions(+), 58 deletions(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 6bd9cf6620b0e..4047f6045bcc5 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -377,13 +377,13 @@ h4 > code, h3 > code, .invisible > code { .content .method .where, .content .fn .where, .content .where.fmt-newline { - display: block; + display: block; } /* Bit of whitespace to indent it */ .content .method .where::before, .content .fn .where::before, .content .where.fmt-newline::before { - content: ' '; + content: ' '; } .content .methods > div { margin-left: 40px; } @@ -506,17 +506,15 @@ body.blur > :not(#help) { } #help > div { flex: 0 0 auto; - background: #e9e9e9; box-shadow: 0 0 6px rgba(0,0,0,.2); width: 550px; height: 330px; - border: 1px solid #bfbfbf; + border: 1px solid; } #help dt { float: left; border-radius: 4px; - border: 1px solid #bfbfbf; - background: #fff; + border: 1px solid; width: 23px; text-align: center; clear: left; @@ -567,7 +565,6 @@ body.blur > :not(#help) { .since { font-weight: normal; font-size: initial; - color: grey; position: absolute; right: 0; top: 0; @@ -589,24 +586,12 @@ td.summary-column { padding-right: 0px; } -.line-numbers :target { background-color: transparent; } - -/* Code highlighting */ -pre.rust .kw { color: #8959A8; } -pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } -pre.rust .number, pre.rust .string { color: #718C00; } -pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, -pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } -pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } -pre.rust .lifetime { color: #B76514; } pre.rust .question-mark { - color: #ff9011; font-weight: bold; } pre.rust { position: relative; } a.test-arrow { - background-color: rgba(78, 139, 202, 0.2); display: inline-block; position: absolute; padding: 5px 10px 5px 10px; @@ -616,7 +601,6 @@ a.test-arrow { right: 5px; } a.test-arrow:hover{ - background-color: #4e8bca; text-decoration: none; } @@ -660,10 +644,6 @@ a.test-arrow:hover{ text-align: center; } -.toggle-label { - color: #999; -} - .ghost { display: none; } @@ -719,8 +699,7 @@ span.since { } :target > code { - background: #FDFFD3; - opacity: 1; + opacity: 1; } /* Media Queries */ @@ -793,4 +772,4 @@ span.since { nav.sub, .content .out-of-band, .collapse-toggle { display: none; } -} +} \ No newline at end of file diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index f1e81900d1eec..40561597e93e0 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -13,28 +13,36 @@ /* General structure and fonts */ body { - background-color: white; - color: black; + background-color: white; + color: black; } h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { - color: black; + color: black; } h1.fqn { - border-bottom-color: #D5D5D5; + border-bottom-color: #D5D5D5; } h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { - border-bottom-color: #DDDDDD; + border-bottom-color: #DDDDDD; } .in-band { - background-color: white; + background-color: white; } .docblock code, .docblock-short code { - background-color: #F5F5F5; + background-color: #F5F5F5; } pre { - background-color: #F5F5F5; + background-color: #F5F5F5; +} + +.sidebar { + background-color: #F1F1F1; +} + +.sidebar .current { + background-color: #fff; } .sidebar { @@ -46,24 +54,24 @@ pre { } .sidebar .location { - border-color: #000; - background-color: #fff; - color: #333; + border-color: #000; + background-color: #fff; + color: #333; } .block a:hover { - background: #F5F5F5; + background: #F5F5F5; } .line-numbers span { color: #c67e2d; } .line-numbers .line-highlighted { - background-color: #f6fdb0 !important; + background-color: #f6fdb0 !important; } :target { background: #FDFFD3; } .content .highlighted { - color: #000 !important; - background-color: #ccc; + color: #000 !important; + background-color: #ccc; } .content .highlighted a, .content .highlighted span { color: #000 !important; } .content .highlighted.trait { background-color: #fece7e; } @@ -76,21 +84,21 @@ pre { .content .highlighted.type { background-color: #c6afb3; } .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { - border-bottom-color: #DDD; + border-bottom-color: #DDD; } .docblock table { - border-color: #ddd; + border-color: #ddd; } .docblock table td { - border-top-color: #ddd; - border-bottom-color: #ddd; + border-top-color: #ddd; + border-bottom-color: #ddd; } .docblock table th { - border-top-color: #ddd; - border-bottom-color: #ddd; + border-top-color: #ddd; + border-bottom-color: #ddd; } .content span.primitive, .content a.primitive, .block a.current.primitive { color: #39a7bf; } @@ -105,34 +113,78 @@ pre.rust .comment { color: #8E908C; } pre.rust .doccomment { color: #4D4D4C; } nav { - border-bottom-color: #e0e0e0; + border-bottom-color: #e0e0e0; } nav.main .current { - border-top-color: #000; - border-bottom-color: #000; + border-top-color: #000; + border-bottom-color: #000; } nav.main .separator { - border: 1px solid #000; + border: 1px solid #000; } a { - color: #000; + color: #000; } .docblock a, .docblock-short a, .stability a { - color: #3873AD; + color: #3873AD; } a.test-arrow { - color: #f5f5f5; + color: #f5f5f5; } .content span.trait, .content a.trait, .block a.current.trait { color: #7c5af3; } .search-input { - color: #555; - box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; - background-color: white; + color: #555; + box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; + background-color: white; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } + +#help > div { + background: #e9e9e9; + border-color: #bfbfbf;; +} + +#help dt { + border-color: #bfbfbf; + background: #fff; +} + +.since { + color: grey; +} + +.line-numbers :target { background-color: transparent; } + +/* Code highlighting */ +pre.rust .kw { color: #8959A8; } +pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } +pre.rust .number, pre.rust .string { color: #718C00; } +pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, +pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } +pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } +pre.rust .lifetime { color: #B76514; } +pre.rust .question-mark { + color: #ff9011; +} + +a.test-arrow { + background-color: rgba(78, 139, 202, 0.2); +} + +a.test-arrow:hover{ + background-color: #4e8bca; +} + +.toggle-label { + color: #999; +} + +:target > code { + background: #FDFFD3; +} \ No newline at end of file From cfb41aedd3a5e21c169a0a91dfd600e8e370d291 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 9 Mar 2017 05:54:52 +0200 Subject: [PATCH 20/73] Use subtyping on the target of unsizing coercions. --- src/librustc_typeck/check/coercion.rs | 28 +++++++---- .../object-lifetime-default-elision.rs | 2 +- .../object-lifetime-default-from-box-error.rs | 4 +- ...ions-close-over-type-parameter-multiple.rs | 2 +- .../regions-proc-bound-capture.rs | 2 +- .../regions-trait-object-subtyping.rs | 4 +- .../variance-contravariant-arg-object.rs | 4 +- .../variance-covariant-arg-object.rs | 4 +- .../variance-invariant-arg-object.rs | 4 +- src/test/run-pass/coerce-unsize-subtype.rs | 48 +++++++++++++++++++ 10 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 src/test/run-pass/coerce-unsize-subtype.rs diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 651058728816e..c43291557f7fa 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -453,18 +453,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => (source, None), }; - let source = source.adjust_for_autoref(self.tcx, reborrow); + let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); + + let adjust = Adjust::DerefRef { + autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoref: reborrow, + unsize: true, + }; + + // Setup either a subtyping or a LUB relationship between + // the `CoerceUnsized` target type and the expected type. + // We only have the latter, so we use an inference variable + // for the former and let type inference do the rest. + let origin = TypeVariableOrigin::MiscVariable(self.cause.span); + let coerce_target = self.next_ty_var(origin); + let mut coercion = self.unify_and(coerce_target, target, adjust)?; let mut selcx = traits::SelectionContext::new(self); // Use a FIFO queue for this custom fulfillment procedure. let mut queue = VecDeque::new(); - let mut obligations = vec![]; // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.cause.span, self.body_id); queue.push_back(self.tcx - .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target])); + .predicate_for_trait_def(cause, coerce_unsized_did, 0, + coerce_source, &[coerce_target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -475,7 +489,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), _ => { - obligations.push(obligation); + coercion.obligations.push(obligation); continue; } }; @@ -503,11 +517,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - success(Adjust::DerefRef { - autoderefs: if reborrow.is_some() { 1 } else { 0 }, - autoref: reborrow, - unsize: true, - }, target, obligations) + Ok(coercion) } fn coerce_from_safe_fn(&self, diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index fb75b9aa1dd94..e37b6a2bb9c99 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -79,7 +79,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { // which fails to type check. ss - //~^ ERROR lifetime bound not satisfied + //~^ ERROR cannot infer //~| ERROR cannot infer } diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index dd94dfe1e0823..c0dd5200f6cb4 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR lifetime bound not satisfied + ss.r //~ ERROR cannot infer an appropriate lifetime } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR lifetime bound not satisfied + ss.r = b; //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index c5cf43e355d5a..ad6c5a31bbbd3 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR lifetime bound not satisfied + box v as Box //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index fb726e31af586..17fd55b031b61 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -16,7 +16,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { fn static_proc(x: &isize) -> Box(isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - Box::new(move|| { *x }) //~ ERROR does not fulfill the required lifetime + Box::new(move|| { *x }) //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index b4e527972e476..e8ada6a175571 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -22,8 +22,8 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { // Without knowing 'a:'b, we can't coerce - x //~ ERROR lifetime bound not satisfied - //~^ ERROR cannot infer + x //~ ERROR cannot infer an appropriate lifetime + //~^ ERROR cannot infer an appropriate lifetime } struct Wrapper(T); diff --git a/src/test/compile-fail/variance-contravariant-arg-object.rs b/src/test/compile-fail/variance-contravariant-arg-object.rs index 1795ac95358d7..d3bf92e85f411 100644 --- a/src/test/compile-fail/variance-contravariant-arg-object.rs +++ b/src/test/compile-fail/variance-contravariant-arg-object.rs @@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) @@ -29,7 +29,7 @@ fn get_max_from_min<'min, 'max, G>(v: Box>) where 'max : 'min { // Previously OK: - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/variance-covariant-arg-object.rs b/src/test/compile-fail/variance-covariant-arg-object.rs index ad059a467f570..0e94e35df2839 100644 --- a/src/test/compile-fail/variance-covariant-arg-object.rs +++ b/src/test/compile-fail/variance-covariant-arg-object.rs @@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box>) where 'max : 'min { // Previously OK, now an error as traits are invariant. - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/variance-invariant-arg-object.rs b/src/test/compile-fail/variance-invariant-arg-object.rs index 9edb510b826a1..aa3e06c015d50 100644 --- a/src/test/compile-fail/variance-invariant-arg-object.rs +++ b/src/test/compile-fail/variance-invariant-arg-object.rs @@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/run-pass/coerce-unsize-subtype.rs b/src/test/run-pass/coerce-unsize-subtype.rs new file mode 100644 index 0000000000000..b19708f5a8931 --- /dev/null +++ b/src/test/run-pass/coerce-unsize-subtype.rs @@ -0,0 +1,48 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// pretty-expanded FIXME #23616 + +use std::rc::Rc; + +fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {} + +// The two arguments are a subtype of their LUB, after coercion. +fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) { + lub_short(xs, ys); +} + +// The argument coerces to a subtype of the return type. +fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] { + xs +} + +// Rc is covariant over T just like &T. +fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> { + xs +} + +// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]` +// to a subtype of the LUB of `xs` and `ys` (i.e. `&'b [&'a T]`), +// regardless of the order they appear (in if-else/match/array). +fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) { + let _order1 = [xs, ys]; + let _order2 = [ys, xs]; +} + +// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]` +// needs to be coerced, i.e. the resulting type is not &'b [&'static T], but +// rather the `&'b [&'a T]` LUB. +fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) { + let _order1 = [xs, ys]; + let _order2 = [ys, xs]; +} + +fn main() {} From b95b5db163adfe24117aa25e42a775c7b5b91dc5 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 9 Mar 2017 22:11:23 +0100 Subject: [PATCH 21/73] update gdbr tests gdb will now reliably detect the lanugage as rust even before any code is run. --- src/test/debuginfo/c-style-enum.rs | 21 ++++++++++++++------- src/test/debuginfo/limited-debuginfo.rs | 12 ++++++++---- src/test/debuginfo/simple-struct.rs | 3 --- src/test/debuginfo/simple-tuple.rs | 3 --- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index 2452c18f54347..900b0829530f3 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -15,31 +15,38 @@ // === GDB TESTS =================================================================================== -// gdb-command:print 'c_style_enum::SINGLE_VARIANT' +// gdbg-command:print 'c_style_enum::SINGLE_VARIANT' +// gdbr-command:print c_style_enum::SINGLE_VARIANT // gdbg-check:$1 = TheOnlyVariant // gdbr-check:$1 = c_style_enum::SingleVariant::TheOnlyVariant -// gdb-command:print 'c_style_enum::AUTO_ONE' +// gdbg-command:print 'c_style_enum::AUTO_ONE' +// gdbr-command:print c_style_enum::AUTO_ONE // gdbg-check:$2 = One // gdbr-check:$2 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::AUTO_TWO' +// gdbg-command:print 'c_style_enum::AUTO_TWO' +// gdbr-command:print c_style_enum::AUTO_TWO // gdbg-check:$3 = One // gdbr-check:$3 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::AUTO_THREE' +// gdbg-command:print 'c_style_enum::AUTO_THREE' +// gdbr-command:print c_style_enum::AUTO_THREE // gdbg-check:$4 = One // gdbr-check:$4 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::MANUAL_ONE' +// gdbg-command:print 'c_style_enum::MANUAL_ONE' +// gdbr-command:print c_style_enum::MANUAL_ONE // gdbg-check:$5 = OneHundred // gdbr-check:$5 = c_style_enum::ManualDiscriminant::OneHundred -// gdb-command:print 'c_style_enum::MANUAL_TWO' +// gdbg-command:print 'c_style_enum::MANUAL_TWO' +// gdbr-command:print c_style_enum::MANUAL_TWO // gdbg-check:$6 = OneHundred // gdbr-check:$6 = c_style_enum::ManualDiscriminant::OneHundred -// gdb-command:print 'c_style_enum::MANUAL_THREE' +// gdbg-command:print 'c_style_enum::MANUAL_THREE' +// gdbr-command:print c_style_enum::MANUAL_THREE // gdbg-check:$7 = OneHundred // gdbr-check:$7 = c_style_enum::ManualDiscriminant::OneHundred diff --git a/src/test/debuginfo/limited-debuginfo.rs b/src/test/debuginfo/limited-debuginfo.rs index 3d21def3953b8..e8c3597b8c8dd 100644 --- a/src/test/debuginfo/limited-debuginfo.rs +++ b/src/test/debuginfo/limited-debuginfo.rs @@ -15,10 +15,14 @@ // Make sure functions have proper names // gdb-command:info functions -// gdb-check:[...]void[...]main([...]); -// gdb-check:[...]void[...]some_function([...]); -// gdb-check:[...]void[...]some_other_function([...]); -// gdb-check:[...]void[...]zzz([...]); +// gdbg-check:[...]void[...]main([...]); +// gdbr-check:fn limited_debuginfo::main(); +// gdbg-check:[...]void[...]some_function([...]); +// gdbr-check:fn limited_debuginfo::some_function(); +// gdbg-check:[...]void[...]some_other_function([...]); +// gdbr-check:fn limited_debuginfo::some_other_function(); +// gdbg-check:[...]void[...]zzz([...]); +// gdbr-check:fn limited_debuginfo::zzz(); // gdb-command:run diff --git a/src/test/debuginfo/simple-struct.rs b/src/test/debuginfo/simple-struct.rs index 4956313ad2214..ae05bafe5adaa 100644 --- a/src/test/debuginfo/simple-struct.rs +++ b/src/test/debuginfo/simple-struct.rs @@ -14,9 +14,6 @@ // === GDB TESTS =================================================================================== -// there's no frame yet for gdb to reliably detect the language, set it explicitly -// gdbr-command:set language rust - // gdbg-command:print 'simple_struct::NO_PADDING_16' // gdbr-command:print simple_struct::NO_PADDING_16 // gdbg-check:$1 = {x = 1000, y = -1001} diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index 354a2c26cb36d..b3c2704115095 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -14,9 +14,6 @@ // === GDB TESTS =================================================================================== -// there's no frame yet for gdb to reliably detect the language, set it explicitly -// gdbr-command:set language rust - // gdbg-command:print/d 'simple_tuple::NO_PADDING_8' // gdbr-command:print simple_tuple::NO_PADDING_8 // gdbg-check:$1 = {__0 = -50, __1 = 50} From 7f19f1f91ba7d082b03f36716909eae39c24ddb3 Mon Sep 17 00:00:00 2001 From: Cengiz Can Date: Fri, 10 Mar 2017 02:51:47 +0300 Subject: [PATCH 22/73] fix #40294 obligation cause.body_id is not always a NodeExpr --- src/librustc/traits/error_reporting.rs | 21 ++++++++++------- .../issue-38812-2.rs | 0 .../issue-38812-2.stderr | 0 .../{codemap_tests => resolve}/issue-38812.rs | 0 .../issue-38812.stderr | 0 src/test/ui/resolve/issue-40294.rs | 23 +++++++++++++++++++ src/test/ui/resolve/issue-40294.stderr | 15 ++++++++++++ 7 files changed, 51 insertions(+), 8 deletions(-) rename src/test/ui/{codemap_tests => resolve}/issue-38812-2.rs (100%) rename src/test/ui/{codemap_tests => resolve}/issue-38812-2.stderr (100%) rename src/test/ui/{codemap_tests => resolve}/issue-38812.rs (100%) rename src/test/ui/{codemap_tests => resolve}/issue-38812.stderr (100%) create mode 100644 src/test/ui/resolve/issue-40294.rs create mode 100644 src/test/ui/resolve/issue-40294.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 99db5f9b62435..0e5c786cd8dcf 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -23,11 +23,17 @@ use super::{ ObjectSafetyViolation, }; +use errors::DiagnosticBuilder; use fmt_macros::{Parser, Piece, Position}; +use hir::{intravisit, Local, Pat}; +use hir::intravisit::{Visitor, NestedVisitorMap}; +use hir::map::NodeExpr; use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; +use std::fmt; +use syntax::ast; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; @@ -35,12 +41,8 @@ use ty::fold::TypeFolder; use ty::subst::Subst; use util::nodemap::{FxHashMap, FxHashSet}; -use std::fmt; -use syntax::ast; -use hir::{intravisit, Local, Pat}; -use hir::intravisit::{Visitor, NestedVisitorMap}; use syntax_pos::{DUMMY_SP, Span}; -use errors::DiagnosticBuilder; + #[derive(Debug, PartialEq, Eq, Hash)] pub struct TraitErrorKey<'tcx> { @@ -848,15 +850,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.span_label(cause.span, &format!("cannot infer type for `{}`", name)); - let expr = self.tcx.hir.expect_expr(cause.body_id); - let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, target_ty: &ty, found_pattern: None, }; - local_visitor.visit_expr(expr); + // #40294: cause.body_id can also be a fn declaration. + // Currently, if it's anything other than NodeExpr, we just ignore it + match self.tcx.hir.find(cause.body_id) { + Some(NodeExpr(expr)) => local_visitor.visit_expr(expr), + _ => () + } if let Some(pattern) = local_visitor.found_pattern { let pattern_span = pattern.span; diff --git a/src/test/ui/codemap_tests/issue-38812-2.rs b/src/test/ui/resolve/issue-38812-2.rs similarity index 100% rename from src/test/ui/codemap_tests/issue-38812-2.rs rename to src/test/ui/resolve/issue-38812-2.rs diff --git a/src/test/ui/codemap_tests/issue-38812-2.stderr b/src/test/ui/resolve/issue-38812-2.stderr similarity index 100% rename from src/test/ui/codemap_tests/issue-38812-2.stderr rename to src/test/ui/resolve/issue-38812-2.stderr diff --git a/src/test/ui/codemap_tests/issue-38812.rs b/src/test/ui/resolve/issue-38812.rs similarity index 100% rename from src/test/ui/codemap_tests/issue-38812.rs rename to src/test/ui/resolve/issue-38812.rs diff --git a/src/test/ui/codemap_tests/issue-38812.stderr b/src/test/ui/resolve/issue-38812.stderr similarity index 100% rename from src/test/ui/codemap_tests/issue-38812.stderr rename to src/test/ui/resolve/issue-38812.stderr diff --git a/src/test/ui/resolve/issue-40294.rs b/src/test/ui/resolve/issue-40294.rs new file mode 100644 index 0000000000000..d30a425d1099b --- /dev/null +++ b/src/test/ui/resolve/issue-40294.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo: Sized { + fn foo(self); +} + +fn foo<'a,'b,T>(x: &'a T, y: &'b T) + where &'a T : Foo, + &'b T : Foo +{ + x.foo(); + y.foo(); +} + +fn main() { } diff --git a/src/test/ui/resolve/issue-40294.stderr b/src/test/ui/resolve/issue-40294.stderr new file mode 100644 index 0000000000000..5c388c9d602ea --- /dev/null +++ b/src/test/ui/resolve/issue-40294.stderr @@ -0,0 +1,15 @@ +error[E0282]: type annotations needed + --> $DIR/issue-40294.rs:15:1 + | +15 | fn foo<'a,'b,T>(x: &'a T, y: &'b T) + | _^ starting here... +16 | | where &'a T : Foo, +17 | | &'b T : Foo +18 | | { +19 | | x.foo(); +20 | | y.foo(); +21 | | } + | |_^ ...ending here: cannot infer type for `&'a T` + +error: aborting due to previous error + From d708a4072a9fa35be3cb6a1e74557925507ba606 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 8 Feb 2017 22:19:22 +1300 Subject: [PATCH 23/73] Add extra methods to IndexVec and implement TypeFoldable for it Adds `get`/`get_mut` accessors and `drain`/`drain_enumerated` iterators to IndexVec. Implements TypeFoldable for IndexVec. --- src/librustc/ty/structural_impls.rs | 11 ++++++++++ src/librustc_data_structures/indexed_vec.rs | 23 +++++++++++++++++++++ src/librustc_data_structures/lib.rs | 1 + 3 files changed, 35 insertions(+) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 48f6fcd11b8ac..49824e8a738d7 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -12,6 +12,7 @@ use infer::type_variable; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use std::rc::Rc; use syntax::abi; @@ -834,3 +835,13 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFoun self.expected.visit_with(visitor) || self.found.visit_with(visitor) } } + +impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + self.iter().map(|x| x.fold_with(folder)).collect() + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 00cea9cbdf6b7..3f478d7c165d1 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::range::RangeArgument; use std::fmt::Debug; use std::iter::{self, FromIterator}; use std::slice; @@ -145,6 +146,18 @@ impl IndexVec { self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData }) } + #[inline] + pub fn drain<'a, R: RangeArgument>( + &'a mut self, range: R) -> impl Iterator + 'a { + self.raw.drain(range) + } + + #[inline] + pub fn drain_enumerated<'a, R: RangeArgument>( + &'a mut self, range: R) -> impl Iterator + 'a { + self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) + } + #[inline] pub fn last(&self) -> Option { self.len().checked_sub(1).map(I::new) @@ -164,6 +177,16 @@ impl IndexVec { pub fn truncate(&mut self, a: usize) { self.raw.truncate(a) } + + #[inline] + pub fn get(&self, index: I) -> Option<&T> { + self.raw.get(index.index()) + } + + #[inline] + pub fn get_mut(&mut self, index: I) -> Option<&mut T> { + self.raw.get_mut(index.index()) + } } impl Index for IndexVec { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 3dce4398f3b91..f278325ebec74 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -38,6 +38,7 @@ #![feature(associated_consts)] #![feature(unsize)] #![feature(i128_type)] +#![feature(conservative_impl_trait)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] From 540b52e145afb09f1784c6094220a7f8268f09ed Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 8 Feb 2017 22:23:09 +1300 Subject: [PATCH 24/73] Fix recursion depth counting in `layout` --- src/librustc/ty/util.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index be1582066e393..a81c3a177f885 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -654,11 +654,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } tcx.layout_depth.set(depth+1); - let layout = Layout::compute_uncached(self, infcx)?; + let layout = Layout::compute_uncached(self, infcx); + tcx.layout_depth.set(depth); + let layout = layout?; if can_cache { tcx.layout_cache.borrow_mut().insert(self, layout); } - tcx.layout_depth.set(depth); Ok(layout) } From 71d0d921c2f38a13ae9c538225f6181f77d604b3 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 8 Feb 2017 22:24:49 +1300 Subject: [PATCH 25/73] Initial implementation of inlining for MIR Fairly basic implementation of inlining for MIR. Uses conservative heuristics for inlining. --- src/librustc/mir/mod.rs | 348 +++++++++- src/librustc/ty/mod.rs | 14 + src/librustc_driver/driver.rs | 1 + src/librustc_mir/callgraph.rs | 252 ++++++++ src/librustc_mir/lib.rs | 3 +- src/librustc_mir/transform/inline.rs | 842 +++++++++++++++++++++++++ src/librustc_mir/transform/mod.rs | 1 + src/librustc_mir/transform/simplify.rs | 18 +- 8 files changed, 1473 insertions(+), 6 deletions(-) create mode 100644 src/librustc_mir/callgraph.rs create mode 100644 src/librustc_mir/transform/inline.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ed72fe1801663..fea576f706780 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -19,6 +19,7 @@ use hir::def::CtorKind; use hir::def_id::DefId; use ty::subst::Substs; use ty::{self, AdtDef, ClosureSubsts, Region, Ty}; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use util::ppaux; use rustc_back::slice; use hir::InlineAsm; @@ -63,8 +64,7 @@ macro_rules! newtype_index { } /// Lowered representation of a single function. -// Do not implement clone for Mir, which can be accidently done and kind of expensive. -#[derive(RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Mir<'tcx> { /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` /// that indexes into this vector. @@ -1333,3 +1333,347 @@ impl Location { } } } + + +/* + * TypeFoldable implementations for MIR types + */ + +impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + Mir { + basic_blocks: self.basic_blocks.fold_with(folder), + visibility_scopes: self.visibility_scopes.clone(), + promoted: self.promoted.fold_with(folder), + return_ty: self.return_ty.fold_with(folder), + local_decls: self.local_decls.fold_with(folder), + arg_count: self.arg_count, + upvar_decls: self.upvar_decls.clone(), + spread_arg: self.spread_arg, + span: self.span, + cache: cache::Cache::new() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.basic_blocks.visit_with(visitor) || + self.promoted.visit_with(visitor) || + self.return_ty.visit_with(visitor) || + self.local_decls.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + LocalDecl { + ty: self.ty.fold_with(folder), + ..self.clone() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + BasicBlockData { + statements: self.statements.fold_with(folder), + terminator: self.terminator.fold_with(folder), + is_cleanup: self.is_cleanup + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.statements.visit_with(visitor) || self.terminator.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::StatementKind::*; + + let kind = match self.kind { + Assign(ref lval, ref rval) => Assign(lval.fold_with(folder), rval.fold_with(folder)), + SetDiscriminant { ref lvalue, variant_index } => SetDiscriminant { + lvalue: lvalue.fold_with(folder), + variant_index: variant_index + }, + StorageLive(ref lval) => StorageLive(lval.fold_with(folder)), + StorageDead(ref lval) => StorageDead(lval.fold_with(folder)), + InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm { + asm: asm.clone(), + outputs: outputs.fold_with(folder), + inputs: inputs.fold_with(folder) + }, + Nop => Nop, + }; + Statement { + source_info: self.source_info, + kind: kind + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::StatementKind::*; + + match self.kind { + Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) } + SetDiscriminant { ref lvalue, .. } | + StorageLive(ref lvalue) | + StorageDead(ref lvalue) => lvalue.visit_with(visitor), + InlineAsm { ref outputs, ref inputs, .. } => + outputs.visit_with(visitor) || inputs.visit_with(visitor), + Nop => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::TerminatorKind::*; + + let kind = match self.kind { + Goto { target } => Goto { target: target }, + SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { + discr: discr.fold_with(folder), + switch_ty: switch_ty.fold_with(folder), + values: values.clone(), + targets: targets.clone() + }, + Drop { ref location, target, unwind } => Drop { + location: location.fold_with(folder), + target: target, + unwind: unwind + }, + DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { + location: location.fold_with(folder), + value: value.fold_with(folder), + target: target, + unwind: unwind + }, + Call { ref func, ref args, ref destination, cleanup } => { + let dest = destination.as_ref().map(|&(ref loc, dest)| { + (loc.fold_with(folder), dest) + }); + + Call { + func: func.fold_with(folder), + args: args.fold_with(folder), + destination: dest, + cleanup: cleanup + } + }, + Assert { ref cond, expected, ref msg, target, cleanup } => { + let msg = if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { + AssertMessage::BoundsCheck { + len: len.fold_with(folder), + index: index.fold_with(folder), + } + } else { + msg.clone() + }; + Assert { + cond: cond.fold_with(folder), + expected: expected, + msg: msg, + target: target, + cleanup: cleanup + } + }, + Resume => Resume, + Return => Return, + Unreachable => Unreachable, + }; + Terminator { + source_info: self.source_info, + kind: kind + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::TerminatorKind::*; + + match self.kind { + SwitchInt { ref discr, switch_ty, .. } => + discr.visit_with(visitor) || switch_ty.visit_with(visitor), + Drop { ref location, ..} => location.visit_with(visitor), + DropAndReplace { ref location, ref value, ..} => + location.visit_with(visitor) || value.visit_with(visitor), + Call { ref func, ref args, ref destination, .. } => { + let dest = if let Some((ref loc, _)) = *destination { + loc.visit_with(visitor) + } else { false }; + dest || func.visit_with(visitor) || args.visit_with(visitor) + }, + Assert { ref cond, ref msg, .. } => { + if cond.visit_with(visitor) { + if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { + len.visit_with(visitor) || index.visit_with(visitor) + } else { + false + } + } else { + false + } + }, + Goto { .. } | + Resume | + Return | + Unreachable => false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Lvalue<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match self { + &Lvalue::Projection(ref p) => Lvalue::Projection(p.fold_with(folder)), + _ => self.clone() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + if let &Lvalue::Projection(ref p) = self { + p.visit_with(visitor) + } else { + false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::Rvalue::*; + match *self { + Use(ref op) => Use(op.fold_with(folder)), + Repeat(ref op, len) => Repeat(op.fold_with(folder), len), + Ref(region, bk, ref lval) => Ref(region.fold_with(folder), bk, lval.fold_with(folder)), + Len(ref lval) => Len(lval.fold_with(folder)), + Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), + BinaryOp(op, ref rhs, ref lhs) => + BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + CheckedBinaryOp(op, ref rhs, ref lhs) => + CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), + Discriminant(ref lval) => Discriminant(lval.fold_with(folder)), + Box(ty) => Box(ty.fold_with(folder)), + Aggregate(ref kind, ref fields) => { + let kind = match *kind { + AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), + AggregateKind::Tuple => AggregateKind::Tuple, + AggregateKind::Adt(def, v, substs, n) => + AggregateKind::Adt(def, v, substs.fold_with(folder), n), + AggregateKind::Closure(id, substs) => + AggregateKind::Closure(id, substs.fold_with(folder)) + }; + Aggregate(kind, fields.fold_with(folder)) + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::Rvalue::*; + match *self { + Use(ref op) => op.visit_with(visitor), + Repeat(ref op, _) => op.visit_with(visitor), + Ref(region, _, ref lval) => region.visit_with(visitor) || lval.visit_with(visitor), + Len(ref lval) => lval.visit_with(visitor), + Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), + BinaryOp(_, ref rhs, ref lhs) | + CheckedBinaryOp(_, ref rhs, ref lhs) => + rhs.visit_with(visitor) || lhs.visit_with(visitor), + UnaryOp(_, ref val) => val.visit_with(visitor), + Discriminant(ref lval) => lval.visit_with(visitor), + Box(ty) => ty.visit_with(visitor), + Aggregate(ref kind, ref fields) => { + (match *kind { + AggregateKind::Array(ty) => ty.visit_with(visitor), + AggregateKind::Tuple => false, + AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor), + AggregateKind::Closure(_, substs) => substs.visit_with(visitor) + }) || fields.visit_with(visitor) + } + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)), + Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + Operand::Consume(ref lval) => lval.visit_with(visitor), + Operand::Constant(ref c) => c.visit_with(visitor) + } + } +} + +impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V> + where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx> +{ + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::ProjectionElem::*; + + let base = self.base.fold_with(folder); + let elem = match self.elem { + Deref => Deref, + Field(f, ty) => Field(f, ty.fold_with(folder)), + Index(ref v) => Index(v.fold_with(folder)), + ref elem => elem.clone() + }; + + Projection { + base: base, + elem: elem + } + } + + fn super_visit_with>(&self, visitor: &mut Vs) -> bool { + use mir::ProjectionElem::*; + + self.base.visit_with(visitor) || + match self.elem { + Field(_, ty) => ty.visit_with(visitor), + Index(ref v) => v.visit_with(visitor), + _ => false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + Constant { + span: self.span.clone(), + ty: self.ty.fold_with(folder), + literal: self.literal.fold_with(folder) + } + } + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) || self.literal.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + Literal::Item { def_id, substs } => Literal::Item { + def_id: def_id, + substs: substs.fold_with(folder) + }, + _ => self.clone() + } + } + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + Literal::Item { substs, .. } => substs.visit_with(visitor), + _ => false + } + } +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index be04b0e6577f0..3c37c7353d683 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2302,6 +2302,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::mir::get(self, DUMMY_SP, did).borrow() } + /// Given the DefId of an item, returns its MIR, borrowed immutably. + /// Returns None if there is no MIR for the DefId + pub fn maybe_item_mir(self, did: DefId) -> Option>> { + if did.is_local() && !self.maps.mir.borrow().contains_key(&did) { + return None; + } + + if !did.is_local() && !self.sess.cstore.is_item_mir_available(did) { + return None; + } + + Some(self.item_mir(did)) + } + /// If `type_needs_drop` returns true, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// false, then `ty` definitely has no destructor (i.e. no drop glue). diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..7790a84da4944 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1048,6 +1048,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); // No lifetime analysis based on borrowing can be done from here on out. + passes.push_pass(box mir::transform::inline::Inline); passes.push_pass(box mir::transform::instcombine::InstCombine::new()); passes.push_pass(box mir::transform::deaggregator::Deaggregator); passes.push_pass(box mir::transform::copy_prop::CopyPropagation); diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs new file mode 100644 index 0000000000000..69416289d8e26 --- /dev/null +++ b/src/librustc_mir/callgraph.rs @@ -0,0 +1,252 @@ +// 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. + +//! MIR-based callgraph. +//! +//! This only considers direct calls + +use rustc::hir::def_id::DefId; +use rustc_data_structures::graph; + +use rustc::mir::*; +use rustc::mir::visit::*; + +use rustc::ty; + +use rustc::util::nodemap::DefIdMap; + +pub struct CallGraph { + node_map: DefIdMap, + graph: graph::Graph +} + +impl CallGraph { + // FIXME: allow for construction of a callgraph that inspects + // cross-crate MIRs if available. + pub fn build<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> CallGraph { + let def_ids = tcx.maps.mir.borrow().keys(); + + let mut callgraph = CallGraph { + node_map: DefIdMap(), + graph: graph::Graph::new() + }; + + for def_id in def_ids { + if !def_id.is_local() { continue; } + + let idx = callgraph.add_node(def_id); + + let mut call_visitor = CallVisitor { + caller: idx, + graph: &mut callgraph + }; + + let mir = tcx.item_mir(def_id); + call_visitor.visit_mir(&mir); + } + + callgraph + } + + // Iterate over the strongly-connected components of the graph + pub fn scc_iter(&self) -> SCCIterator { + SCCIterator::new(&self.graph) + } + + // Get the def_id for the given graph node + pub fn def_id(&self, node: graph::NodeIndex) -> DefId { + *self.graph.node_data(node) + } + + fn add_node(&mut self, id: DefId) -> graph::NodeIndex { + let graph = &mut self.graph; + *self.node_map.entry(id).or_insert_with(|| { + graph.add_node(id) + }) + } +} + +struct CallVisitor<'a> { + caller: graph::NodeIndex, + graph: &'a mut CallGraph +} + +impl<'a, 'tcx> Visitor<'tcx> for CallVisitor<'a> { + fn visit_terminator_kind(&mut self, _block: BasicBlock, + kind: &TerminatorKind<'tcx>, _loc: Location) { + if let TerminatorKind::Call { + func: Operand::Constant(ref f) + , .. } = *kind { + if let ty::TyFnDef(def_id, _, _) = f.ty.sty { + let callee = self.graph.add_node(def_id); + self.graph.graph.add_edge(self.caller, callee, ()); + } + } + } +} + +struct StackElement<'g> { + node: graph::NodeIndex, + lowlink: usize, + children: graph::AdjacentTargets<'g, DefId, ()> +} + +/** + * Iterator over strongly-connected-components using Tarjan's algorithm[1] + * + * [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + */ +pub struct SCCIterator<'g> { + graph: &'g graph::Graph, + index: usize, + node_indices: Vec>, + scc_stack: Vec, + current_scc: Vec, + visit_stack: Vec>, +} + +impl<'g> SCCIterator<'g> { + pub fn new(graph: &'g graph::Graph) -> SCCIterator<'g> { + if graph.len_nodes() == 0 { + return SCCIterator { + graph: graph, + index: 0, + node_indices: Vec::new(), + scc_stack: Vec::new(), + current_scc: Vec::new(), + visit_stack: Vec::new() + }; + } + + let first = graph::NodeIndex(0); + + SCCIterator::with_entry(graph, first) + } + + pub fn with_entry(graph: &'g graph::Graph, + entry: graph::NodeIndex) -> SCCIterator<'g> { + let mut iter = SCCIterator { + graph: graph, + index: 0, + node_indices: Vec::with_capacity(graph.len_nodes()), + scc_stack: Vec::new(), + current_scc: Vec::new(), + visit_stack: Vec::new() + }; + + iter.visit_one(entry); + + iter + } + + fn get_next(&mut self) { + self.current_scc.clear(); + + while !self.visit_stack.is_empty() { + self.visit_children(); + + let node = self.visit_stack.pop().unwrap(); + + if let Some(last) = self.visit_stack.last_mut() { + if last.lowlink > node.lowlink { + last.lowlink = node.lowlink; + } + } + + debug!("TarjanSCC: Popped node {:?} : lowlink = {:?}; index = {:?}", + node.node, node.lowlink, self.node_index(node.node).unwrap()); + + if node.lowlink != self.node_index(node.node).unwrap() { + continue; + } + + loop { + let n = self.scc_stack.pop().unwrap(); + self.current_scc.push(n); + self.set_node_index(n, !0); + if n == node.node { return; } + } + } + } + + fn visit_one(&mut self, node: graph::NodeIndex) { + self.index += 1; + let idx = self.index; + self.set_node_index(node, idx); + self.scc_stack.push(node); + self.visit_stack.push(StackElement { + node: node, + lowlink: self.index, + children: self.graph.successor_nodes(node) + }); + debug!("TarjanSCC: Node {:?} : index = {:?}", node, idx); + } + + fn visit_children(&mut self) { + while let Some(child) = self.visit_stack.last_mut().unwrap().children.next() { + if let Some(child_num) = self.node_index(child) { + let cur = self.visit_stack.last_mut().unwrap(); + if cur.lowlink > child_num { + cur.lowlink = child_num; + } + } else { + self.visit_one(child); + } + } + } + + fn node_index(&self, node: graph::NodeIndex) -> Option { + self.node_indices.get(node.node_id()).and_then(|&idx| idx) + } + + fn set_node_index(&mut self, node: graph::NodeIndex, idx: usize) { + let i = node.node_id(); + if i >= self.node_indices.len() { + self.node_indices.resize(i + 1, None); + } + self.node_indices[i] = Some(idx); + } +} + +impl<'g> Iterator for SCCIterator<'g> { + type Item = Vec; + + fn next(&mut self) -> Option> { + self.get_next(); + + if self.current_scc.is_empty() { + // Try a new root for the next SCC, if the node_indices + // map is doesn't contain all nodes, use the smallest one + // with no entry, otherwise find the first empty node. + // + // FIXME: This should probably use a set of precomputed + // roots instead + if self.node_indices.len() < self.graph.len_nodes() { + let idx = graph::NodeIndex(self.node_indices.len()); + self.visit_one(idx); + } else { + for idx in 0..self.node_indices.len() { + if self.node_indices[idx].is_none() { + let idx = graph::NodeIndex(idx); + self.visit_one(idx); + break; + } + } + } + self.get_next(); + } + + if self.current_scc.is_empty() { + None + } else { + Some(self.current_scc.clone()) + } + } +} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index a97495a0ebcc4..f21f1881c832e 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -46,6 +46,7 @@ extern crate rustc_const_eval; pub mod diagnostics; pub mod build; +pub mod callgraph; pub mod def_use; pub mod graphviz; mod hair; @@ -58,4 +59,4 @@ use rustc::ty::maps::Providers; pub fn provide(providers: &mut Providers) { mir_map::provide(providers); transform::qualify_consts::provide(providers); -} +} \ No newline at end of file diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs new file mode 100644 index 0000000000000..4b8e2bf49b9ee --- /dev/null +++ b/src/librustc_mir/transform/inline.rs @@ -0,0 +1,842 @@ +// 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. + +//! Inlining pass for MIR functions + +use rustc::hir::def_id::DefId; + +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::graph; + +use rustc::dep_graph::DepNode; +use rustc::mir::*; +use rustc::mir::transform::{MirMapPass, MirPassHook, MirSource, Pass}; +use rustc::mir::visit::*; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{Subst,Substs}; +use rustc::util::nodemap::{DefIdSet}; + +use super::simplify::{remove_dead_blocks, CfgSimplifier}; + +use syntax::attr; +use syntax::abi::Abi; + +use callgraph; + +const DEFAULT_THRESHOLD: usize = 50; +const HINT_THRESHOLD: usize = 100; + +const INSTR_COST: usize = 5; +const CALL_PENALTY: usize = 25; + +const UNKNOWN_SIZE_COST: usize = 10; + +pub struct Inline; + +impl<'tcx> MirMapPass<'tcx> for Inline { + fn run_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + hooks: &mut [Box MirPassHook<'s>>]) { + + //if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } + + let _ignore = tcx.dep_graph.in_ignore(); + + let callgraph = callgraph::CallGraph::build(tcx); + + let mut inliner = Inliner { + tcx: tcx, + }; + + let def_ids = tcx.maps.mir.borrow().keys(); + for &def_id in &def_ids { + if !def_id.is_local() { continue; } + + let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); + let mut mir = if let Some(mir) = tcx.maps.mir.borrow().get(&def_id) { + mir.borrow_mut() + } else { + continue; + }; + + tcx.dep_graph.write(DepNode::Mir(def_id)); + + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let src = MirSource::from_node(tcx, id); + + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, &mut mir, self, false); + } + } + + for scc in callgraph.scc_iter() { + inliner.inline_scc(&callgraph, &scc); + } + + for def_id in def_ids { + if !def_id.is_local() { continue; } + + let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); + let mut mir = tcx.maps.mir.borrow()[&def_id].borrow_mut(); + tcx.dep_graph.write(DepNode::Mir(def_id)); + + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let src = MirSource::from_node(tcx, id); + + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, &mut mir, self, true); + } + } + } +} + +impl<'tcx> Pass for Inline { } + +struct Inliner<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, +} + +#[derive(Copy, Clone)] +struct CallSite<'tcx> { + caller: DefId, + callee: DefId, + substs: &'tcx Substs<'tcx>, + bb: BasicBlock, + location: SourceInfo, +} + +impl<'a, 'tcx> Inliner<'a, 'tcx> { + fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool { + let mut callsites = Vec::new(); + let mut in_scc = DefIdSet(); + + let mut inlined_into = DefIdSet(); + + for &node in scc { + let def_id = callgraph.def_id(node); + + // Don't inspect functions from other crates + let id = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { + id + } else { + continue; + }; + let src = MirSource::from_node(self.tcx, id); + if let MirSource::Fn(_) = src { + if let Some(mir) = self.tcx.maybe_item_mir(def_id) { + for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + // Don't inline calls that are in cleanup blocks. + if bb_data.is_cleanup { continue; } + + // Only consider direct calls to functions + let terminator = bb_data.terminator(); + if let TerminatorKind::Call { + func: Operand::Constant(ref f), .. } = terminator.kind { + if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + callsites.push(CallSite { + caller: def_id, + callee: callee_def_id, + substs: substs, + bb: bb, + location: terminator.source_info + }); + } + } + } + + in_scc.insert(def_id); + } + } + } + + // Move callsites that are in the the SCC to the end so + // they're inlined after calls to outside the SCC + let mut first_call_in_scc = callsites.len(); + + let mut i = 0; + while i < first_call_in_scc { + let f = callsites[i].caller; + if in_scc.contains(&f) { + first_call_in_scc -= 1; + callsites.swap(i, first_call_in_scc); + } else { + i += 1; + } + } + + let mut local_change; + let mut changed = false; + + loop { + local_change = false; + let mut csi = 0; + while csi < callsites.len() { + let callsite = callsites[csi]; + csi += 1; + + let callee_mir = { + if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) { + if !self.should_inline(callsite, &callee_mir) { + continue; + } + + callee_mir.subst(self.tcx, callsite.substs) + } else { + continue; + } + + }; + + let mut caller_mir = { + let map = self.tcx.maps.mir.borrow(); + let mir = map.get(&callsite.caller).unwrap(); + mir.borrow_mut() + }; + + let start = caller_mir.basic_blocks().len(); + + if !self.inline_call(callsite, &mut caller_mir, callee_mir) { + continue; + } + + inlined_into.insert(callsite.caller); + + // Add callsites from inlined function + for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) { + // Only consider direct calls to functions + let terminator = bb_data.terminator(); + if let TerminatorKind::Call { + func: Operand::Constant(ref f), .. } = terminator.kind { + if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + // Don't inline the same function multiple times. + if callsite.callee != callee_def_id { + callsites.push(CallSite { + caller: callsite.caller, + callee: callee_def_id, + substs: substs, + bb: bb, + location: terminator.source_info + }); + } + } + } + } + + + csi -= 1; + if scc.len() == 1 { + callsites.swap_remove(csi); + } else { + callsites.remove(csi); + } + + local_change = true; + changed = true; + } + + if !local_change { + break; + } + } + + // Simplify functions we inlined into. + for def_id in inlined_into { + let mut caller_mir = { + let map = self.tcx.maps.mir.borrow(); + let mir = map.get(&def_id).unwrap(); + mir.borrow_mut() + }; + + debug!("Running simplify cfg on {:?}", def_id); + CfgSimplifier::new(&mut caller_mir).simplify(); + remove_dead_blocks(&mut caller_mir); + } + changed + } + + fn should_inline(&self, callsite: CallSite<'tcx>, + callee_mir: &'a Mir<'tcx>) -> bool { + + let tcx = self.tcx; + + // Don't inline closures that have captures + // FIXME: Handle closures better + if callee_mir.upvar_decls.len() > 0 { + return false; + } + + // Don't inline calls to trait methods + // FIXME: Should try to resolve it to a concrete method, and + // only bail if that isn't possible + let trait_def = tcx.trait_of_item(callsite.callee); + if trait_def.is_some() { return false; } + + let attrs = tcx.get_attrs(callsite.callee); + let hint = attr::find_inline_attr(None, &attrs[..]); + + let hinted = match hint { + // Just treat inline(always) as a hint for now, + // there are cases that prevent inlining that we + // need to check for first. + attr::InlineAttr::Always => true, + attr::InlineAttr::Never => return false, + attr::InlineAttr::Hint => true, + attr::InlineAttr::None => false, + }; + + // Only inline local functions if they would be eligible for + // cross-crate inlining. This ensures that any symbols they + // use are reachable cross-crate + // FIXME(#36594): This shouldn't be necessary, and is more conservative + // than it could be, but trans should generate the reachable set from + // the MIR anyway, making any check obsolete. + if callsite.callee.is_local() { + // No type substs and no inline hint means this function + // wouldn't be eligible for cross-crate inlining + if callsite.substs.types().count() == 0 && !hinted { + return false; + } + + } + + let mut threshold = if hinted { + HINT_THRESHOLD + } else { + DEFAULT_THRESHOLD + }; + + // Significantly lower the threshold for inlining cold functions + if attr::contains_name(&attrs[..], "cold") { + threshold /= 5; + } + + // Give a bonus functions with a small number of blocks, + // We normally have two or three blocks for even + // very small functions. + if callee_mir.basic_blocks().len() <= 3 { + threshold += threshold / 4; + } + + // FIXME: Give a bonus to functions with only a single caller + + let id = tcx.hir.as_local_node_id(callsite.caller).expect("Caller not local"); + let param_env = ty::ParameterEnvironment::for_item(tcx, id); + + let mut first_block = true; + let mut cost = 0; + + // Traverse the MIR manually so we can account for the effects of + // inlining on the CFG. + let mut work_list = vec![START_BLOCK]; + let mut visited = BitVector::new(callee_mir.basic_blocks().len()); + while let Some(bb) = work_list.pop() { + if !visited.insert(bb.index()) { continue; } + let blk = &callee_mir.basic_blocks()[bb]; + + for stmt in &blk.statements { + // Don't count StorageLive/StorageDead in the inlining cost. + match stmt.kind { + StatementKind::StorageLive(_) | + StatementKind::StorageDead(_) | + StatementKind::Nop => {} + _ => cost += INSTR_COST + } + } + let term = blk.terminator(); + let mut is_drop = false; + match term.kind { + TerminatorKind::Drop { ref location, target, unwind } | + TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => { + is_drop = true; + work_list.push(target); + // If the location doesn't actually need dropping, treat it like + // a regular goto. + let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs); + let ty = ty.to_ty(tcx); + if tcx.type_needs_drop_given_env(ty, ¶m_env) { + cost += CALL_PENALTY; + if let Some(unwind) = unwind { + work_list.push(unwind); + } + } else { + cost += INSTR_COST; + } + } + + TerminatorKind::Unreachable | + TerminatorKind::Call { destination: None, .. } if first_block => { + // If the function always diverges, don't inline + // unless the cost is zero + threshold = 0; + } + + TerminatorKind::Call {func: Operand::Constant(ref f), .. } => { + if let ty::TyFnDef(.., f) = f.ty.sty { + // Don't give intrinsics the extra penalty for calls + if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { + cost += INSTR_COST; + } else { + cost += CALL_PENALTY; + } + } + } + TerminatorKind::Assert { .. } => cost += CALL_PENALTY, + _ => cost += INSTR_COST + } + + if !is_drop { + for &succ in &term.successors()[..] { + work_list.push(succ); + } + } + + first_block = false; + } + + // Count up the cost of local variables and temps, if we know the size + // use that, otherwise we use a moderately-large dummy cost. + + let ptr_size = tcx.data_layout.pointer_size.bytes(); + + for v in callee_mir.vars_and_temps_iter() { + let v = &callee_mir.local_decls[v]; + let ty = v.ty.subst(tcx, callsite.substs); + // Cost of the var is the size in machine-words, if we know + // it. + if let Some(size) = type_size_of(tcx, param_env.clone(), ty) { + cost += (size / ptr_size) as usize; + } else { + cost += UNKNOWN_SIZE_COST; + } + } + + debug!("Inline cost for {:?} is {}", callsite.callee, cost); + + if let attr::InlineAttr::Always = hint { + true + } else { + cost <= threshold + } + } + + + fn inline_call(&self, callsite: CallSite<'tcx>, + caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool { + + // Don't inline a function into itself + if callsite.caller == callsite.callee { return false; } + + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); + + + let terminator = caller_mir[callsite.bb].terminator.take().unwrap(); + match terminator.kind { + // FIXME: Handle inlining of diverging calls + TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { + + debug!("Inlined {:?} into {:?}", callsite.callee, callsite.caller); + + let is_box_free = Some(callsite.callee) == self.tcx.lang_items.box_free_fn(); + + let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len()); + let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len()); + let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len()); + + for mut scope in callee_mir.visibility_scopes.iter().cloned() { + if scope.parent_scope.is_none() { + scope.parent_scope = Some(callsite.location.scope); + scope.span = callee_mir.span; + } + + scope.span = callsite.location.span; + + let idx = caller_mir.visibility_scopes.push(scope); + scope_map.push(idx); + } + + for loc in callee_mir.vars_and_temps_iter() { + let mut local = callee_mir.local_decls[loc].clone(); + + if let Some(ref mut source_info) = local.source_info { + source_info.scope = scope_map[source_info.scope]; + + source_info.span = callsite.location.span; + } + + let idx = caller_mir.local_decls.push(local); + local_map.push(idx); + } + + for p in callee_mir.promoted.iter().cloned() { + let idx = caller_mir.promoted.push(p); + promoted_map.push(idx); + } + + // If the call is something like `a[*i] = f(i)`, where + // `i : &mut usize`, then just duplicating the `a[*i]` + // Lvalue could result in two different locations if `f` + // writes to `i`. To prevent this we need to create a temporary + // borrow of the lvalue and pass the destination as `*temp` instead. + fn dest_needs_borrow(lval: &Lvalue) -> bool { + match *lval { + Lvalue::Projection(ref p) => { + match p.elem { + ProjectionElem::Deref | + ProjectionElem::Index(_) => true, + _ => dest_needs_borrow(&p.base) + } + } + // Static variables need a borrow because the callee + // might modify the same static. + Lvalue::Static(_) => true, + _ => false + } + } + + let dest = if dest_needs_borrow(&destination.0) { + debug!("Creating temp for return destination"); + let dest = Rvalue::Ref( + self.tcx.mk_region(ty::ReErased), + BorrowKind::Mut, + destination.0); + + let ty = dest.ty(caller_mir, self.tcx); + + let temp = LocalDecl::new_temp(ty); + + let tmp = caller_mir.local_decls.push(temp); + let tmp = Lvalue::Local(tmp); + + let stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(tmp.clone(), dest) + }; + caller_mir[callsite.bb] + .statements.push(stmt); + tmp.deref() + } else { + destination.0 + }; + + let return_block = destination.1; + + let args : Vec<_> = if is_box_free { + assert!(args.len() == 1); + // box_free takes a Box, but is defined with a *mut T, inlining + // needs to generate the cast. + // FIXME: we should probably just generate correct MIR in the first place... + + let arg = if let Operand::Consume(ref lval) = args[0] { + lval.clone() + } else { + bug!("Constant arg to \"box_free\""); + }; + + let ptr_ty = args[0].ty(caller_mir, self.tcx); + vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)] + } else { + // Copy the arguments if needed. + self.make_call_args(args, &callsite, caller_mir) + }; + + let bb_len = caller_mir.basic_blocks().len(); + let mut integrator = Integrator { + block_idx: bb_len, + args: &args, + local_map: local_map, + scope_map: scope_map, + promoted_map: promoted_map, + _callsite: callsite, + destination: dest, + return_block: return_block, + cleanup_block: cleanup, + in_cleanup_block: false + }; + + + for (bb, mut block) in callee_mir.basic_blocks_mut().drain_enumerated(..) { + integrator.visit_basic_block_data(bb, &mut block); + caller_mir.basic_blocks_mut().push(block); + } + + let terminator = Terminator { + source_info: callsite.location, + kind: TerminatorKind::Goto { target: BasicBlock::new(bb_len) } + }; + + caller_mir[callsite.bb].terminator = Some(terminator); + + true + } + kind => { + caller_mir[callsite.bb].terminator = Some(Terminator { + source_info: terminator.source_info, + kind: kind + }); + false + } + } + } + + fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>, + callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> { + let arg = Rvalue::Ref( + self.tcx.mk_region(ty::ReErased), + BorrowKind::Mut, + arg.deref()); + + let ty = arg.ty(caller_mir, self.tcx); + let ref_tmp = LocalDecl::new_temp(ty); + let ref_tmp = caller_mir.local_decls.push(ref_tmp); + let ref_tmp = Lvalue::Local(ref_tmp); + + let ref_stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(ref_tmp.clone(), arg) + }; + + caller_mir[callsite.bb] + .statements.push(ref_stmt); + + let pointee_ty = match ptr_ty.sty { + ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty, + _ if ptr_ty.is_box() => ptr_ty.boxed_ty(), + _ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty) + }; + let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty); + + let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty); + + let cast_tmp = LocalDecl::new_temp(ptr_ty); + let cast_tmp = caller_mir.local_decls.push(cast_tmp); + let cast_tmp = Lvalue::Local(cast_tmp); + + let cast_stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(cast_tmp.clone(), raw_ptr) + }; + + caller_mir[callsite.bb] + .statements.push(cast_stmt); + + Operand::Consume(cast_tmp) + } + + fn make_call_args(&self, args: Vec>, + callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Vec> { + let tcx = self.tcx; + // FIXME: Analysis of the usage of the arguments to avoid + // unnecessary temporaries. + args.into_iter().map(|a| { + if let Operand::Consume(Lvalue::Local(local)) = a { + if caller_mir.local_kind(local) == LocalKind::Temp { + // Reuse the operand if it's a temporary already + return a; + } + } + + debug!("Creating temp for argument"); + // Otherwise, create a temporary for the arg + let arg = Rvalue::Use(a); + + let ty = arg.ty(caller_mir, tcx); + + let arg_tmp = LocalDecl::new_temp(ty); + let arg_tmp = caller_mir.local_decls.push(arg_tmp); + let arg_tmp = Lvalue::Local(arg_tmp); + + let stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(arg_tmp.clone(), arg) + }; + caller_mir[callsite.bb].statements.push(stmt); + Operand::Consume(arg_tmp) + }).collect() + } +} + +fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParameterEnvironment<'tcx>, + ty: Ty<'tcx>) -> Option { + tcx.infer_ctxt(param_env, traits::Reveal::All).enter(|infcx| { + ty.layout(&infcx).ok().map(|layout| { + layout.size(&tcx.data_layout).bytes() + }) + }) +} + +/** + * Integrator. + * + * Integrates blocks from the callee function into the calling function. + * Updates block indices, references to locals and other control flow + * stuff. + */ +struct Integrator<'a, 'tcx: 'a> { + block_idx: usize, + args: &'a [Operand<'tcx>], + local_map: IndexVec, + scope_map: IndexVec, + promoted_map: IndexVec, + _callsite: CallSite<'tcx>, + destination: Lvalue<'tcx>, + return_block: BasicBlock, + cleanup_block: Option, + in_cleanup_block: bool, +} + +impl<'a, 'tcx> Integrator<'a, 'tcx> { + fn update_target(&self, tgt: BasicBlock) -> BasicBlock { + let new = BasicBlock::new(tgt.index() + self.block_idx); + debug!("Updating target `{:?}`, new: `{:?}`", tgt, new); + new + } + + fn update_local(&self, local: Local) -> Option { + let idx = local.index(); + if idx < (self.args.len() + 1) { + return None; + } + let idx = idx - (self.args.len() + 1); + let local = Local::new(idx); + self.local_map.get(local).cloned() + } + + fn arg_index(&self, arg: Local) -> Option { + let idx = arg.index(); + if idx > 0 && idx <= self.args.len() { + Some(idx - 1) + } else { + None + } + } +} + +impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + _ctxt: LvalueContext<'tcx>, + _location: Location) { + if let Lvalue::Local(ref mut local) = *lvalue { + if let Some(l) = self.update_local(*local) { + // Temp or Var; update the local reference + *local = l; + return; + } + } + if let Lvalue::Local(local) = *lvalue { + if local == RETURN_POINTER { + // Return pointer; update the lvalue itself + *lvalue = self.destination.clone(); + } else if local.index() < (self.args.len() + 1) { + // Argument, once again update the the lvalue itself + let idx = local.index() - 1; + if let Operand::Consume(ref lval) = self.args[idx] { + *lvalue = lval.clone(); + } else { + bug!("Arg operand `{:?}` is not an Lvalue use.", idx) + } + } + } else { + self.super_lvalue(lvalue, _ctxt, _location) + } + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { + if let Operand::Consume(Lvalue::Local(arg)) = *operand { + if let Some(idx) = self.arg_index(arg) { + let new_arg = self.args[idx].clone(); + *operand = new_arg; + return; + } + } + self.super_operand(operand, location); + } + + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { + self.in_cleanup_block = data.is_cleanup; + self.super_basic_block_data(block, data); + self.in_cleanup_block = false; + } + + fn visit_terminator_kind(&mut self, block: BasicBlock, + kind: &mut TerminatorKind<'tcx>, loc: Location) { + self.super_terminator_kind(block, kind, loc); + + match *kind { + TerminatorKind::Goto { ref mut target} => { + *target = self.update_target(*target); + } + TerminatorKind::SwitchInt { ref mut targets, .. } => { + for tgt in targets { + *tgt = self.update_target(*tgt); + } + } + TerminatorKind::Drop { ref mut target, ref mut unwind, .. } | + TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => { + *target = self.update_target(*target); + if let Some(tgt) = *unwind { + *unwind = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this drop is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *unwind = self.cleanup_block; + } + } + TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => { + if let Some((_, ref mut tgt)) = *destination { + *tgt = self.update_target(*tgt); + } + if let Some(tgt) = *cleanup { + *cleanup = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this call is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *cleanup = self.cleanup_block; + } + } + TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => { + *target = self.update_target(*target); + if let Some(tgt) = *cleanup { + *cleanup = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this assert is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *cleanup = self.cleanup_block; + } + } + TerminatorKind::Return => { + *kind = TerminatorKind::Goto { target: self.return_block }; + } + TerminatorKind::Resume => { + if let Some(tgt) = self.cleanup_block { + *kind = TerminatorKind::Goto { target: tgt } + } + } + TerminatorKind::Unreachable => { } + } + } + + fn visit_visibility_scope(&mut self, scope: &mut VisibilityScope) { + *scope = self.scope_map[*scope]; + } + + fn visit_literal(&mut self, literal: &mut Literal<'tcx>, loc: Location) { + if let Literal::Promoted { ref mut index } = *literal { + if let Some(p) = self.promoted_map.get(*index).cloned() { + *index = p; + } + } else { + self.super_literal(literal, loc); + } + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index ae255f70fb788..cbd054a72499b 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -20,3 +20,4 @@ pub mod dump_mir; pub mod deaggregator; pub mod instcombine; pub mod copy_prop; +pub mod inline; diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index e93a412dc744f..a762507f35e7e 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -79,7 +79,7 @@ pub struct CfgSimplifier<'a, 'tcx: 'a> { } impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { - fn new(mir: &'a mut Mir<'tcx>) -> Self { + pub fn new(mir: &'a mut Mir<'tcx>) -> Self { let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks()); // we can't use mir.predecessors() here because that counts @@ -102,7 +102,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { } } - fn simplify(mut self) { + pub fn simplify(mut self) { loop { let mut changed = false; @@ -137,6 +137,8 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { if !changed { break } } + + self.strip_nops() } // Collapse a goto chain starting from `start` @@ -231,9 +233,19 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { terminator.kind = TerminatorKind::Goto { target: first_succ }; true } + + fn strip_nops(&mut self) { + for blk in self.basic_blocks.iter_mut() { + blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind { + false + } else { + true + }) + } + } } -fn remove_dead_blocks(mir: &mut Mir) { +pub fn remove_dead_blocks(mir: &mut Mir) { let mut seen = BitVector::new(mir.basic_blocks().len()); for (bb, _) in traversal::preorder(mir) { seen.insert(bb.index()); From f55e92b2a7a83f424f661c777e76054403b008b5 Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 9 Feb 2017 06:31:47 +1300 Subject: [PATCH 26/73] Add dep-graph tasks where needed --- src/librustc_mir/transform/inline.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 4b8e2bf49b9ee..4b4bd44230163 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -27,7 +27,7 @@ use rustc::util::nodemap::{DefIdSet}; use super::simplify::{remove_dead_blocks, CfgSimplifier}; -use syntax::attr; +use syntax::{attr}; use syntax::abi::Abi; use callgraph; @@ -184,6 +184,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let callsite = callsites[csi]; csi += 1; + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); + self.tcx.dep_graph.write(DepNode::Mir(callsite.caller)); + let callee_mir = { if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) { if !self.should_inline(callsite, &callee_mir) { @@ -232,7 +235,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - csi -= 1; if scc.len() == 1 { callsites.swap_remove(csi); @@ -251,6 +253,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Simplify functions we inlined into. for def_id in inlined_into { + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(def_id)); + self.tcx.dep_graph.write(DepNode::Mir(def_id)); + let mut caller_mir = { let map = self.tcx.maps.mir.borrow(); let mir = map.get(&def_id).unwrap(); @@ -275,11 +280,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { return false; } - // Don't inline calls to trait methods - // FIXME: Should try to resolve it to a concrete method, and - // only bail if that isn't possible - let trait_def = tcx.trait_of_item(callsite.callee); - if trait_def.is_some() { return false; } let attrs = tcx.get_attrs(callsite.callee); let hint = attr::find_inline_attr(None, &attrs[..]); @@ -294,19 +294,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { attr::InlineAttr::None => false, }; - // Only inline local functions if they would be eligible for - // cross-crate inlining. This ensures that any symbols they - // use are reachable cross-crate - // FIXME(#36594): This shouldn't be necessary, and is more conservative - // than it could be, but trans should generate the reachable set from - // the MIR anyway, making any check obsolete. + // Only inline local functions if they would be eligible for cross-crate + // inlining. This is to ensure that the final crate doesn't have MIR that + // reference unexported symbols if callsite.callee.is_local() { - // No type substs and no inline hint means this function - // wouldn't be eligible for cross-crate inlining if callsite.substs.types().count() == 0 && !hinted { return false; } - } let mut threshold = if hinted { From 3eb26d1f2bd9bd8d2c8f72d624d45f94bfe39695 Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 9 Feb 2017 06:50:08 +1300 Subject: [PATCH 27/73] Only run inlining if mir opts are enabled --- src/librustc_mir/transform/inline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 4b4bd44230163..80a9c06f11b28 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -48,7 +48,7 @@ impl<'tcx> MirMapPass<'tcx> for Inline { tcx: TyCtxt<'a, 'tcx, 'tcx>, hooks: &mut [Box MirPassHook<'s>>]) { - //if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } let _ignore = tcx.dep_graph.in_ignore(); From 889337da06e764369897ef15a6dfca6f27879a45 Mon Sep 17 00:00:00 2001 From: Cengiz Can Date: Fri, 10 Mar 2017 11:43:34 +0300 Subject: [PATCH 28/73] move related tests to type-check ui test directory --- src/test/ui/{resolve => type-check}/issue-38812-2.rs | 0 src/test/ui/{resolve => type-check}/issue-38812-2.stderr | 0 src/test/ui/{resolve => type-check}/issue-38812.rs | 0 src/test/ui/{resolve => type-check}/issue-38812.stderr | 0 src/test/ui/{resolve => type-check}/issue-40294.rs | 0 src/test/ui/{resolve => type-check}/issue-40294.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{resolve => type-check}/issue-38812-2.rs (100%) rename src/test/ui/{resolve => type-check}/issue-38812-2.stderr (100%) rename src/test/ui/{resolve => type-check}/issue-38812.rs (100%) rename src/test/ui/{resolve => type-check}/issue-38812.stderr (100%) rename src/test/ui/{resolve => type-check}/issue-40294.rs (100%) rename src/test/ui/{resolve => type-check}/issue-40294.stderr (100%) diff --git a/src/test/ui/resolve/issue-38812-2.rs b/src/test/ui/type-check/issue-38812-2.rs similarity index 100% rename from src/test/ui/resolve/issue-38812-2.rs rename to src/test/ui/type-check/issue-38812-2.rs diff --git a/src/test/ui/resolve/issue-38812-2.stderr b/src/test/ui/type-check/issue-38812-2.stderr similarity index 100% rename from src/test/ui/resolve/issue-38812-2.stderr rename to src/test/ui/type-check/issue-38812-2.stderr diff --git a/src/test/ui/resolve/issue-38812.rs b/src/test/ui/type-check/issue-38812.rs similarity index 100% rename from src/test/ui/resolve/issue-38812.rs rename to src/test/ui/type-check/issue-38812.rs diff --git a/src/test/ui/resolve/issue-38812.stderr b/src/test/ui/type-check/issue-38812.stderr similarity index 100% rename from src/test/ui/resolve/issue-38812.stderr rename to src/test/ui/type-check/issue-38812.stderr diff --git a/src/test/ui/resolve/issue-40294.rs b/src/test/ui/type-check/issue-40294.rs similarity index 100% rename from src/test/ui/resolve/issue-40294.rs rename to src/test/ui/type-check/issue-40294.rs diff --git a/src/test/ui/resolve/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr similarity index 100% rename from src/test/ui/resolve/issue-40294.stderr rename to src/test/ui/type-check/issue-40294.stderr From a8cacd3d21ee094a9577a6700b6c99f92ce9117c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Mar 2017 09:08:03 -0800 Subject: [PATCH 29/73] travis: Attempt to debug sccache failures I can't find anything that'd cause unexpected EOF in the source, so let's try taking a look at the error logs on failures. --- .travis.yml | 1 + src/ci/docker/run.sh | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fa6c9cf074864..bbb0226a0c550 100644 --- a/.travis.yml +++ b/.travis.yml @@ -128,6 +128,7 @@ after_failure: echo "#### Build failed; Disk usage after running script:"; df -h; du . | sort -nr | head -n100 + - cat obj/tmp/sccache.log # Save tagged docker images we created and load them if they're available before_cache: diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 1e61f2169106c..437041e0292ca 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -30,13 +30,17 @@ retry docker \ objdir=$root_dir/obj mkdir -p $HOME/.cargo -mkdir -p $objdir +mkdir -p $objdir/tmp args= if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env SCCACHE_BUCKET=$SCCACHE_BUCKET" args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" + args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log" + args="$args --env SCCACHE_LOG_LEVEL=debug" + args="$args --env RUST_LOG=sccache=debug" + args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache" From 7688222144e33b18821494983cbb6e23bad4fd55 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Mar 2017 06:55:24 -0800 Subject: [PATCH 30/73] Don't put Cargo into the rustc workspace This causes problems when first cloning and bootstrapping the repository unfortunately, so let's ensure that Cargo sticks around in its own workspace. Because Cargo is a submodule it's not available by default on the inital clone of the rust-lang/rust repository. Normally it's the responsibility of the rustbuild to take care of this, but unfortunately to build rustbuild itself we need to resolve the workspace conflicts. To deal with this we'll just have to ensure that all submodules are in their own workspace, which sort of makes sense anyway as updates to dependencies as bugfixes to Cargo should go to rust-lang/cargo instead of rust-lang/rust. In any case this commit removes Cargo from the global workspace which should resolve the issues that we've been seeing. To actually perform this the `cargo` submodule has been moved to the top directory to ensure it's outside the scope of `src/Cargo.toml` as a workspace. --- .gitmodules | 2 +- cargo | 1 + src/Cargo.lock | 666 --------------------------------------- src/Cargo.toml | 1 - src/bootstrap/compile.rs | 5 +- src/bootstrap/dist.rs | 1 + src/bootstrap/step.rs | 2 +- src/tools/cargo | 1 - 8 files changed, 8 insertions(+), 671 deletions(-) create mode 160000 cargo delete mode 160000 src/tools/cargo diff --git a/.gitmodules b/.gitmodules index bdc14d8c3be71..9bc2a6a70eb45 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,7 +22,7 @@ path = src/doc/nomicon url = https://github.com/rust-lang-nursery/nomicon [submodule "src/tools/cargo"] - path = src/tools/cargo + path = cargo url = https://github.com/rust-lang/cargo [submodule "reference"] path = src/doc/reference diff --git a/cargo b/cargo new file mode 160000 index 0000000000000..5f3b9c4c6a7be --- /dev/null +++ b/cargo @@ -0,0 +1 @@ +Subproject commit 5f3b9c4c6a7be1f177d6024cb83d150b6479148a diff --git a/src/Cargo.lock b/src/Cargo.lock index f4174693a5771..6dc71e8b602db 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -6,23 +6,6 @@ dependencies = [ "libc 0.0.0", ] -[[package]] -name = "advapi32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "aho-corasick" version = "0.6.2" @@ -90,11 +73,6 @@ dependencies = [ "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bufstream" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "build-manifest" version = "0.1.0" @@ -110,81 +88,10 @@ dependencies = [ "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cargo" -version = "0.18.0" -dependencies = [ - "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargotest 0.1.0", - "crates-io 0.7.0", - "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cargotest" -version = "0.1.0" -dependencies = [ - "bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo 0.18.0", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargotest2" version = "0.1.0" -[[package]] -name = "cfg-if" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "clap" version = "2.20.5" @@ -240,58 +147,6 @@ dependencies = [ name = "core" version = "0.0.0" -[[package]] -name = "crates-io" -version = "0.7.0" -dependencies = [ - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "curl" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "curl-sys" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "docopt" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dtoa" version = "0.4.1" @@ -334,48 +189,15 @@ dependencies = [ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "flate2" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fmt_macros" version = "0.0.0" -[[package]] -name = "foreign-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fs2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "gcc" version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "gdi32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "getopts" version = "0.0.0" @@ -385,48 +207,10 @@ name = "getopts" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "git2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "git2-curl" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "graphviz" version = "0.0.0" -[[package]] -name = "hamcrest" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "handlebars" version = "0.25.1" @@ -441,16 +225,6 @@ dependencies = [ "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "idna" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.3.1" @@ -482,43 +256,6 @@ name = "libc" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libgit2-sys" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libssh2-sys" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libz-sys" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "linkchecker" version = "0.1.0" @@ -532,11 +269,6 @@ name = "log" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "matches" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "mdbook" version = "0.0.17" @@ -554,14 +286,6 @@ dependencies = [ "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "1.0.1" @@ -570,99 +294,6 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "miniz-sys" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-iter" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-rational" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.1.36" @@ -676,48 +307,11 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num_cpus" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "open" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "openssl" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl-probe" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "openssl-sys" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "panic_abort" version = "0.0.0" @@ -741,11 +335,6 @@ name = "pest" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "pkg-config" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc_macro" version = "0.0.0" @@ -762,15 +351,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "psapi-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pulldown-cmark" version = "0.0.8" @@ -793,11 +373,6 @@ name = "quick-error" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rand" version = "0.0.0" @@ -805,26 +380,6 @@ dependencies = [ "core 0.0.0", ] -[[package]] -name = "rand" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" version = "0.2.1" @@ -837,11 +392,6 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex-syntax" version = "0.4.0" @@ -1218,50 +768,11 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "semver" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "serde" version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "serde_codegen_internals" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_ignored" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "serde_json" version = "0.9.7" @@ -1277,11 +788,6 @@ dependencies = [ name = "serialize" version = "0.0.0" -[[package]] -name = "shell-escape" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "std" version = "0.0.0" @@ -1318,24 +824,6 @@ name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "syn" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synom" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syntax" version = "0.0.0" @@ -1367,36 +855,10 @@ dependencies = [ "serialize 0.0.0", ] -[[package]] -name = "tar" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempdir" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term" version = "0.0.0" -[[package]] -name = "term" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term_size" version = "0.2.3" @@ -1415,15 +877,6 @@ dependencies = [ "term 0.0.0", ] -[[package]] -name = "thread-id" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread-id" version = "3.0.0" @@ -1433,14 +886,6 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "thread_local" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread_local" version = "0.3.3" @@ -1470,19 +915,6 @@ dependencies = [ "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unicode-bidi" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-segmentation" version = "1.1.0" @@ -1493,11 +925,6 @@ name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unreachable" version = "0.1.1" @@ -1506,29 +933,6 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "url" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "user32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "utf8-ranges" version = "1.0.0" @@ -1554,119 +958,49 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" -"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b48dbe2ff0e98fa2f03377d204a9637d3c9816cd431bfe05a8abbd0ea11d074" -"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758" "checksum cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "e1acc68a3f714627af38f9f5d09706a28584ba60dfe2cca68f40bf779f941b25" -"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c90e1240ef340dd4027ade439e5c7c2064dd9dc652682117bd50d1486a3add7b" -"checksum curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d909dc402ae80b6f7b0118c039203436061b9d9a3ca5d2c2546d93e0a61aaa" -"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99971fb1b635fe7a0ee3c4d065845bb93cca80a23b5613b5613391ece5de4144" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "d4e4d0c15ef829cbc1b7cda651746be19cceeb238be7b1049227b14891df9e25" -"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" -"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf" "checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d" -"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "046ae03385257040b2a35e56d9669d950dd911ba2bf48202fbef73ee6aab27b2" -"checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" "checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" -"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b" "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5" -"checksum libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d951fd5eccae07c74e8c2c1075b05ea1e43be7f8952245af8c2840d1480b1d95" -"checksum libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "91e135645c2e198a39552c8c7686bb5b83b1b99f64831c040a6c2798a1195934" -"checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" -"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" "checksum mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dbba458ca886cb082d026afd704eeeeb0531f7e4ffd6c619f72dc309c1c18fe4" -"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" -"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" -"checksum miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a78d2605eb97302c10cf944b8d96b0a2a890c52957caf92fcd1f24f69049579" -"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2" -"checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120" -"checksum num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "88b14378471f7c2adc5262f05b4701ef53e8da376453a8d8fee48e51db745e49" -"checksum num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c78e054dd19c3fd03419ade63fa661e9c49bb890ce3beb4eee5b7baf93f92f" -"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92" -"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c" -"checksum num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "54ff603b8334a72fbb27fe66948aac0abaaa40231b3cecd189e76162f6f38aaf" "checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" -"checksum num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a225d1e2717567599c24f88e49f00856c6e825a12125181ee42c4257e3688d39" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" -"checksum openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f9871ecf7629da3760599e3e547d35940cff3cead49159b49f81cd1250f24f1d" -"checksum openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "756d49c8424483a3df3b5d735112b4da22109ced9a8294f1f5cdf80fb3810919" -"checksum openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5dd48381e9e8a6dce9c4c402db143b2e243f5f872354532f7a009c289b3998ca" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" -"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" -"checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" -"checksum quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7375cf7ad34a92e8fd18dd9c42f58b9a11def59ab48bec955bf359a788335592" -"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" -"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" -"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" "checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" -"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0ed773960f90a78567fcfbe935284adf50c5d7cf119aa2cf43bb0b4afa69bb" -"checksum serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d52006899f910528a10631e5b727973fe668f3228109d1707ccf5bad5490b6e" -"checksum serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "789ee9f3cd78c850948b94121020147f5220b47dafbf230d7098a93a58f726cf" -"checksum serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4b3f5576874721d14690657e9f0ed286e72a52be2f6fdc0cf2f024182bd8f64" "checksum serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb96d30e4e6f9fc52e08f51176d078b6f79b981dc3ed4134f7b850be9f446a8" -"checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "37c279fb816210c9bb28b2c292664581e7b87b4561e86b94df462664d8620bb8" -"checksum synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27e31aa4b09b9f4cb12dff3c30ba503e17b1a624413d764d32dab76e3920e5bc" -"checksum tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb3bf6ec92843ca93f4fcfb5fc6dfe30534815b147885db4b5759b8e2ff7d52" -"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989" "checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" -"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" -"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" "checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796" "checksum toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08272367dd2e766db3fa38f068067d17aa6a9dfd7259af24b3927db92f1e0c2f" -"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032" -"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" "checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" -"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" -"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" -"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/src/Cargo.toml b/src/Cargo.toml index c5ca80accbf02..0dafbb8428e3e 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -13,7 +13,6 @@ members = [ "tools/build-manifest", "tools/qemu-test-client", "tools/qemu-test-server", - "tools/cargo", ] # Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 46d8d4b4aab2d..3459c1d2b8425 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -417,7 +417,10 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) { // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build"); - let dir = build.src.join("src/tools").join(tool); + let mut dir = build.src.join(tool); + if !dir.exists() { + dir = build.src.join("src/tools").join(tool); + } cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); // We don't want to build tools dynamically as they'll be running across diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 67e4dad83ce88..d437e907d1e6c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -392,6 +392,7 @@ pub fn rust_src(build: &Build) { let src_dirs = [ "man", "src", + "cargo", ]; let filter_fn = move |path: &Path| { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index a5c0d11d21985..a11726a57dbdd 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -559,7 +559,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.build("tool-qemu-test-client", "src/tools/qemu-test-client") .dep(|s| s.name("libstd")) .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client")); - rules.build("tool-cargo", "src/tools/cargo") + rules.build("tool-cargo", "cargo") .dep(|s| s.name("libstd")) .dep(|s| s.stage(0).host(s.target).name("openssl")) .dep(move |s| { diff --git a/src/tools/cargo b/src/tools/cargo deleted file mode 160000 index d17b61aa5a2ca..0000000000000 --- a/src/tools/cargo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d17b61aa5a2ca790f268a043bffdb0ffb04f0ec7 From ac2bc7c570eec8a024cec779908c8ae718924e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Jan 2017 23:17:48 -0800 Subject: [PATCH 31/73] Point to enclosing block/fn on nested unsafe When declaring nested unsafe blocks (`unsafe {unsafe {}}`) that trigger the "unnecessary `unsafe` block" error, point out the enclosing `unsafe block` or `unsafe fn` that makes it unnecessary. --- src/librustc_lint/unused.rs | 29 ++++- .../span}/lint-unused-unsafe.rs | 0 src/test/ui/span/lint-unused-unsafe.stderr | 116 ++++++++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) rename src/test/{compile-fail => ui/span}/lint-unused-unsafe.rs (100%) create mode 100644 src/test/ui/span/lint-unused-unsafe.stderr diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 28ce9126019eb..f9b7c68587678 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -189,11 +189,38 @@ impl LintPass for UnusedUnsafe { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe { fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + /// Return the NodeId for an enclosing scope that is also `unsafe` + fn is_enclosed(cx: &LateContext, id: ast::NodeId) -> Option<(String, ast::NodeId)> { + let parent_id = cx.tcx.hir.get_parent_node(id); + if parent_id != id { + if cx.tcx.used_unsafe.borrow().contains(&parent_id) { + Some(("block".to_string(), parent_id)) + } else if let Some(hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _), + .. + })) = cx.tcx.hir.find(parent_id) { + Some(("fn".to_string(), parent_id)) + } else { + is_enclosed(cx, parent_id) + } + } else { + None + } + } if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) && !cx.tcx.used_unsafe.borrow().contains(&blk.id) { - cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block"); + + let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span, + "unnecessary `unsafe` block"); + + db.span_label(blk.span, &"unnecessary `unsafe` block"); + if let Some((kind, id)) = is_enclosed(cx, blk.id) { + db.span_note(cx.tcx.hir.span(id), + &format!("because it's nested under this `unsafe` {}", kind)); + } + db.emit(); } } } diff --git a/src/test/compile-fail/lint-unused-unsafe.rs b/src/test/ui/span/lint-unused-unsafe.rs similarity index 100% rename from src/test/compile-fail/lint-unused-unsafe.rs rename to src/test/ui/span/lint-unused-unsafe.rs diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr new file mode 100644 index 0000000000000..0df3fa43022a4 --- /dev/null +++ b/src/test/ui/span/lint-unused-unsafe.stderr @@ -0,0 +1,116 @@ +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:26:13 + | +26 | fn bad1() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^ unnecessary `unsafe` block + | +note: lint level defined here + --> $DIR/lint-unused-unsafe.rs:14:9 + | +14 | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:27:13 + | +27 | fn bad2() { unsafe { bad1() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:28:20 + | +28 | unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^ unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:28:1 + | +28 | unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:29:13 + | +29 | fn bad4() { unsafe { callback(||{}) } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:30:20 + | +30 | unsafe fn bad5() { unsafe { unsf() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:30:1 + | +30 | unsafe fn bad5() { unsafe { unsf() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:33:9 + | +33 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _________^ starting here... +34 | | unsf() +35 | | } + | |_________^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` block + --> $DIR/lint-unused-unsafe.rs:32:5 + | +32 | unsafe { // don't put the warning here + | _____^ starting here... +33 | | unsafe { //~ ERROR: unnecessary `unsafe` block +34 | | unsf() +35 | | } +36 | | } + | |_____^ ...ending here + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:39:5 + | +39 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _____^ starting here... +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } + | |_____^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:38:1 + | +38 | unsafe fn bad7() { + | _^ starting here... +39 | | unsafe { //~ ERROR: unnecessary `unsafe` block +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } +44 | | } + | |_^ ...ending here + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:40:9 + | +40 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _________^ starting here... +41 | | unsf() +42 | | } + | |_________^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:38:1 + | +38 | unsafe fn bad7() { + | _^ starting here... +39 | | unsafe { //~ ERROR: unnecessary `unsafe` block +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } +44 | | } + | |_^ ...ending here + +error: aborting due to 8 previous errors + From b68b6c2f5d42db9719fa52af3968932ebf06349e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 10:21:16 -0800 Subject: [PATCH 32/73] configure: Remove git probing logic This is all in rustbuild already. --- configure | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/configure b/configure index be8628de62832..1ebbef54ed120 100755 --- a/configure +++ b/configure @@ -821,17 +821,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi -# If we have no git directory then we are probably a tarball distribution -# and shouldn't attempt to load submodules -if [ ! -e ${CFG_SRC_DIR}.git ] -then - probe CFG_GIT git - msg "git: no git directory. disabling submodules" - CFG_DISABLE_MANAGE_SUBMODULES=1 -else - probe_need CFG_GIT git -fi - # Use `md5sum` on GNU platforms, or `md5 -q` on BSD probe CFG_MD5 md5 probe CFG_MD5SUM md5sum From f15a0c9e5d911541982bf2b6c716b4a9347738d6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 10:21:41 -0800 Subject: [PATCH 33/73] configure: Remove md5 probing logic This is all not used any more --- configure | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/configure b/configure index 1ebbef54ed120..7592729fa0eaa 100755 --- a/configure +++ b/configure @@ -821,20 +821,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi -# Use `md5sum` on GNU platforms, or `md5 -q` on BSD -probe CFG_MD5 md5 -probe CFG_MD5SUM md5sum -if [ -n "$CFG_MD5" ] -then - CFG_HASH_COMMAND="$CFG_MD5 -q | cut -c 1-8" -elif [ -n "$CFG_MD5SUM" ] -then - CFG_HASH_COMMAND="$CFG_MD5SUM | cut -c 1-8" -else - err 'could not find one of: md5 md5sum' -fi -putvar CFG_HASH_COMMAND - probe CFG_CLANG clang++ probe CFG_CCACHE ccache probe CFG_GCC gcc From 8544d73e48cf5938f8fba63ef2cba786d8f14307 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 10:23:09 -0800 Subject: [PATCH 34/73] configure: Remove miscellaneous program probes All of these should be handled by rustbuild in sanity.rs right now. --- configure | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) diff --git a/configure b/configure index 7592729fa0eaa..2f985b1bcb50d 100755 --- a/configure +++ b/configure @@ -821,51 +821,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi -probe CFG_CLANG clang++ -probe CFG_CCACHE ccache -probe CFG_GCC gcc -probe CFG_LD ld -probe CFG_VALGRIND valgrind -probe CFG_PERF perf -probe CFG_ISCC iscc -probe CFG_ANTLR4 antlr4 -probe CFG_GRUN grun -probe CFG_FLEX flex -probe CFG_BISON bison -probe CFG_GDB gdb -probe CFG_LLDB lldb - -if [ -n "$CFG_ENABLE_NINJA" ] -then - probe CFG_NINJA ninja - if [ -z "$CFG_NINJA" ] - then - # On Debian and Fedora, the `ninja` binary is an IRC bot, so the build tool was - # renamed. Handle this case. - probe CFG_NINJA ninja-build - fi -fi - -# For building LLVM -if [ -z "$CFG_LLVM_ROOT" ] -then - probe_need CFG_CMAKE cmake -fi - -# On MacOS X, invoking `javac` pops up a dialog if the JDK is not -# installed. Since `javac` is only used if `antlr4` is available, -# probe for it only in this case. -if [ -n "$CFG_ANTLR4" ] -then - CFG_ANTLR4_JAR="\"$(find /usr/ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" - if [ "x" = "x$CFG_ANTLR4_JAR" ] - then - CFG_ANTLR4_JAR="\"$(find ~ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" - fi - putvar CFG_ANTLR4_JAR $CFG_ANTLR4_JAR - probe CFG_JAVAC javac -fi - # the valgrind rpass tests will fail if you don't have a valgrind, but they're # only disabled if you opt out. if [ -z "$CFG_VALGRIND" ] @@ -927,10 +882,6 @@ if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then fi fi -step_msg "looking for target specific programs" - -probe CFG_ADB adb - BIN_SUF= if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ] then From 1389f5d17b176d08b831bf5595abeda2e84e72db Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 10:25:32 -0800 Subject: [PATCH 35/73] configure: Remove some lldb-specific logic All of this should already be vendored in rustbuild if necessary or otherwise it's just not used. --- configure | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/configure b/configure index 2f985b1bcb50d..d01ce227e1f81 100755 --- a/configure +++ b/configure @@ -835,41 +835,6 @@ then fi fi -if [ -n "$CFG_LLDB" ] -then - # Store LLDB's version - CFG_LLDB_VERSION=$($CFG_LLDB --version 2>/dev/null | head -1) - putvar CFG_LLDB_VERSION - - # If CFG_LLDB_PYTHON_DIR is not already set from the outside and valid, try to read it from - # LLDB via the -P commandline options. - if [ -z "$CFG_LLDB_PYTHON_DIR" ] || [ ! -d "$CFG_LLDB_PYTHON_DIR" ] - then - CFG_LLDB_PYTHON_DIR=$($CFG_LLDB -P) - - # If CFG_LLDB_PYTHON_DIR is not a valid directory, set it to something more readable - if [ ! -d "$CFG_LLDB_PYTHON_DIR" ] - then - CFG_LLDB_PYTHON_DIR="LLDB_PYTHON_DIRECTORY_NOT_FOUND" - fi - - putvar CFG_LLDB_PYTHON_DIR - fi -fi - -# LLDB tests on OSX require /usr/bin/python, not something like Homebrew's -# /usr/local/bin/python. We're loading a compiled module for LLDB tests which is -# only compatible with the system. -case $CFG_BUILD in - *-apple-darwin) - CFG_LLDB_PYTHON=/usr/bin/python - ;; - *) - CFG_LLDB_PYTHON=$CFG_PYTHON - ;; -esac -putvar CFG_LLDB_PYTHON - # Do some sanity checks if running on buildbot # (these env vars are set by rust-buildbot) if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then From 84076516b79d0c8f8fe86b2b7ebc80789ef292e8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 11:12:40 -0800 Subject: [PATCH 36/73] configure: Remove SUPPORTED_TARGET support This is not used any more --- configure | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configure b/configure index d01ce227e1f81..4c684b313091e 100755 --- a/configure +++ b/configure @@ -912,10 +912,6 @@ CFG_MANDIR=${CFG_MANDIR%/} CFG_DOCDIR=${CFG_DOCDIR%/} CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')" CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')" -CFG_SUPPORTED_TARGET="" -for target_file in ${CFG_SRC_DIR}mk/cfg/*.mk; do - CFG_SUPPORTED_TARGET="${CFG_SUPPORTED_TARGET} $(basename "$target_file" .mk)" -done # copy build-triples to host-triples so that builds are a subset of hosts V_TEMP="" From 171ec25b7149107e9479af4e468e1ee1d95bae5b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 11:13:41 -0800 Subject: [PATCH 37/73] configure: Remove misc unused vars None of this is used by rustbuild any more --- configure | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/configure b/configure index 4c684b313091e..9c90eb5f1fc91 100755 --- a/configure +++ b/configure @@ -951,31 +951,6 @@ putvar CFG_MANDIR putvar CFG_DOCDIR putvar CFG_USING_LIBCPP -# Avoid spurious warnings from clang by feeding it original source on -# ccache-miss rather than preprocessed input. -if [ -n "$CFG_ENABLE_CCACHE" ] && [ -n "$CFG_USING_CLANG" ] -then - CFG_CCACHE_CPP2=1 - putvar CFG_CCACHE_CPP2 -fi - -if [ -n "$CFG_ENABLE_CCACHE" ] -then - CFG_CCACHE_BASEDIR=${CFG_SRC_DIR} - putvar CFG_CCACHE_BASEDIR -fi - - -putvar CFG_LLVM_SRC_DIR - -for t in $CFG_HOST -do - CFG_LLVM_BUILD_DIR=$(echo CFG_LLVM_BUILD_DIR_${t} | tr - _) - CFG_LLVM_INST_DIR=$(echo CFG_LLVM_INST_DIR_${t} | tr - _) - putvar $CFG_LLVM_BUILD_DIR - putvar $CFG_LLVM_INST_DIR -done - msg copy_if_changed ${CFG_SRC_DIR}src/bootstrap/mk/Makefile.in ./Makefile move_if_changed config.tmp config.mk From cd23f1cd75fbc34f9b7f09807eccc81fa21d3c84 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 11:27:39 -0800 Subject: [PATCH 38/73] configure: Remove --build detection This commit removes detection of CFG_OSTYPE and CFG_CPUTYPE from the configure script, which means that the default value of `--build` is no longer present in the configure script. All this logic is now available in rustbuild itself, so there's no need to duplicate it. --- configure | 203 +------------------------------------ src/bootstrap/bootstrap.py | 23 ++++- src/bootstrap/config.rs | 6 +- 3 files changed, 23 insertions(+), 209 deletions(-) diff --git a/configure b/configure index 9c90eb5f1fc91..9b34e214214a5 100755 --- a/configure +++ b/configure @@ -384,207 +384,6 @@ need_cmd sed need_cmd file need_cmd make -msg "inspecting environment" - -CFG_OSTYPE=$(uname -s) -CFG_CPUTYPE=$(uname -m) - -if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ] -then - # Darwin's `uname -s` lies and always returns i386. We have to use sysctl - # instead. - if sysctl hw.optional.x86_64 | grep -q ': 1' - then - CFG_CPUTYPE=x86_64 - fi -fi - -# The goal here is to come up with the same triple as LLVM would, -# at least for the subset of platforms we're willing to target. - -case $CFG_OSTYPE in - - Linux) - CFG_OSTYPE=unknown-linux-gnu - ;; - - FreeBSD) - CFG_OSTYPE=unknown-freebsd - ;; - - DragonFly) - CFG_OSTYPE=unknown-dragonfly - ;; - - Bitrig) - CFG_OSTYPE=unknown-bitrig - ;; - - OpenBSD) - CFG_OSTYPE=unknown-openbsd - ;; - - NetBSD) - CFG_OSTYPE=unknown-netbsd - ;; - - Darwin) - CFG_OSTYPE=apple-darwin - ;; - - SunOS) - CFG_OSTYPE=sun-solaris - CFG_CPUTYPE=$(isainfo -n) - ;; - - Haiku) - CFG_OSTYPE=unknown-haiku - ;; - - MINGW*) - # msys' `uname` does not print gcc configuration, but prints msys - # configuration. so we cannot believe `uname -m`: - # msys1 is always i686 and msys2 is always x86_64. - # instead, msys defines $MSYSTEM which is MINGW32 on i686 and - # MINGW64 on x86_64. - CFG_CPUTYPE=i686 - CFG_OSTYPE=pc-windows-gnu - if [ "$MSYSTEM" = MINGW64 ] - then - CFG_CPUTYPE=x86_64 - fi - ;; - - MSYS*) - CFG_OSTYPE=pc-windows-gnu - ;; - -# Thad's Cygwin identifiers below - -# Vista 32 bit - CYGWIN_NT-6.0) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=i686 - ;; - -# Vista 64 bit - CYGWIN_NT-6.0-WOW64) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=x86_64 - ;; - -# Win 7 32 bit - CYGWIN_NT-6.1) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=i686 - ;; - -# Win 7 64 bit - CYGWIN_NT-6.1-WOW64) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=x86_64 - ;; - -# Win 8 # uname -s on 64-bit cygwin does not contain WOW64, so simply use uname -m to detect arch (works in my install) - CYGWIN_NT-6.3) - CFG_OSTYPE=pc-windows-gnu - ;; -# We do not detect other OS such as XP/2003 using 64 bit using uname. -# If we want to in the future, we will need to use Cygwin - Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative. - *) - err "unknown OS type: $CFG_OSTYPE" - ;; -esac - - -case $CFG_CPUTYPE in - - i386 | i486 | i686 | i786 | x86) - CFG_CPUTYPE=i686 - ;; - - xscale | arm) - CFG_CPUTYPE=arm - ;; - - armv6l) - CFG_CPUTYPE=arm - CFG_OSTYPE="${CFG_OSTYPE}eabihf" - ;; - - armv7l) - CFG_CPUTYPE=armv7 - CFG_OSTYPE="${CFG_OSTYPE}eabihf" - ;; - - aarch64 | arm64) - CFG_CPUTYPE=aarch64 - ;; - - powerpc | ppc) - CFG_CPUTYPE=powerpc - ;; - - powerpc64 | ppc64) - CFG_CPUTYPE=powerpc64 - ;; - - powerpc64le | ppc64le) - CFG_CPUTYPE=powerpc64le - ;; - - s390x) - CFG_CPUTYPE=s390x - ;; - - x86_64 | x86-64 | x64 | amd64) - CFG_CPUTYPE=x86_64 - ;; - - mips | mips64) - if [ "$CFG_CPUTYPE" = "mips64" ]; then - CFG_OSTYPE="${CFG_OSTYPE}abi64" - fi - ENDIAN=$(printf '\1' | od -dAn) - if [ "$ENDIAN" -eq 1 ]; then - CFG_CPUTYPE="${CFG_CPUTYPE}el" - elif [ "$ENDIAN" -ne 256 ]; then - err "unknown endianness: $ENDIAN (expecting 1 for little or 256 for big)" - fi - ;; - - BePC) - CFG_CPUTYPE=i686 - ;; - - *) - err "unknown CPU type: $CFG_CPUTYPE" -esac - -# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation -if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ] -then - # $SHELL does not exist in standard 'sh', so probably only exists - # if configure is running in an interactive bash shell. /usr/bin/env - # exists *everywhere*. - BIN_TO_PROBE="$SHELL" - if [ ! -r "$BIN_TO_PROBE" ]; then - if [ -r "/usr/bin/env" ]; then - BIN_TO_PROBE="/usr/bin/env" - else - warn "Cannot check if the userland is i686 or x86_64" - fi - fi - file -L "$BIN_TO_PROBE" | grep -q "x86[_-]64" - if [ $? != 0 ]; then - msg "i686 userland on x86_64 Linux kernel" - CFG_CPUTYPE=i686 - fi -fi - - -DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}" - CFG_SRC_DIR="$(abs_path $(dirname $0))/" CFG_SRC_DIR_RELATIVE="$(dirname $0)/" CFG_BUILD_DIR="$(pwd)/" @@ -673,7 +472,7 @@ valopt infodir "${CFG_PREFIX}/share/info" "install additional info" valopt llvm-root "" "set LLVM root" valopt python "" "set path to python" valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located" -valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple" +valopt build "" "GNUs ./configure syntax LLVM build triple" valopt android-cross-path "" "Android NDK standalone path (deprecated)" valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path" valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 7dd53f41a214a..b34a43d90540c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -296,8 +296,10 @@ def get_toml(self, key): def get_mk(self, key): for line in iter(self.config_mk.splitlines()): - if line.startswith(key): - return line[line.find(':=') + 2:].strip() + if line.startswith(key + ' :='): + var = line[line.find(':=') + 2:].strip() + if var != '': + return var return None def cargo(self): @@ -438,6 +440,8 @@ def build_triple(self): sys.exit(err) elif ostype == 'Darwin': ostype = 'apple-darwin' + elif ostype == 'Haiku': + ostype = 'unknown-haiku' elif ostype.startswith('MINGW'): # msys' `uname` does not print gcc configuration, but prints msys # configuration. so we cannot believe `uname -m`: @@ -465,9 +469,12 @@ def build_triple(self): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype == 'armv7l': + elif cputype == 'armv6l': cputype = 'arm' ostype += 'eabihf' + elif cputype == 'armv7l': + cputype = 'armv7' + ostype += 'eabihf' elif cputype == 'aarch64': cputype = 'aarch64' elif cputype == 'arm64': @@ -488,12 +495,20 @@ def build_triple(self): raise ValueError('unknown byteorder: ' + sys.byteorder) # only the n64 ABI is supported, indicate it ostype += 'abi64' - elif cputype in {'powerpc', 'ppc', 'ppc64'}: + elif cputype in {'powerpc', 'ppc'}: cputype = 'powerpc' + elif cputype in {'powerpc64', 'ppc64'}: + cputype = 'powerpc64' + elif cputype in {'powerpc64le', 'ppc64le'}: + cputype = 'powerpc64le' elif cputype == 'sparcv9': pass elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}: cputype = 'x86_64' + elif cputype == 's390x': + cputype = 's390x' + elif cputype == 'BePC': + cputype = 'i686' else: err = "unknown cpu type: " + cputype if self.verbose: diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 438ce6103d624..38fb1177bcd14 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -460,12 +460,12 @@ impl Config { } match key { - "CFG_BUILD" => self.build = value.to_string(), - "CFG_HOST" => { + "CFG_BUILD" if value.len() > 0 => self.build = value.to_string(), + "CFG_HOST" if value.len() > 0 => { self.host = value.split(" ").map(|s| s.to_string()) .collect(); } - "CFG_TARGET" => { + "CFG_TARGET" if value.len() > 0 => { self.target = value.split(" ").map(|s| s.to_string()) .collect(); } From a07c9a20b721554d23c45499a753bf4fdfdc7474 Mon Sep 17 00:00:00 2001 From: Jonas Bushart Date: Tue, 14 Feb 2017 11:05:53 +0100 Subject: [PATCH 39/73] Export attributes in save-analysis data Some annotations like the "test" annotations might be of interest for other projects, especially rls. Export all attributes in a new attributes item. --- src/librustc_save_analysis/data.rs | 12 +- src/librustc_save_analysis/dump_visitor.rs | 14 ++- src/librustc_save_analysis/external_data.rs | 118 +++++++++++++++++++- src/librustc_save_analysis/json_dumper.rs | 12 ++ src/librustc_save_analysis/lib.rs | 21 +++- 5 files changed, 171 insertions(+), 6 deletions(-) diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 0a6281bf8c54c..6caf81380e40d 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -15,7 +15,7 @@ use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId}; -use syntax::ast::{self, NodeId}; +use syntax::ast::{self, Attribute, NodeId}; use syntax_pos::Span; pub struct CrateData { @@ -136,6 +136,7 @@ pub struct EnumData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for extern crates. @@ -171,6 +172,7 @@ pub struct FunctionData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data about a function call. @@ -256,6 +258,7 @@ pub struct MethodData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for modules. @@ -271,6 +274,7 @@ pub struct ModData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for a reference to a module. @@ -295,6 +299,7 @@ pub struct StructData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -309,6 +314,7 @@ pub struct StructVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -323,6 +329,7 @@ pub struct TraitData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -337,6 +344,7 @@ pub struct TupleVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for a typedef. @@ -351,6 +359,7 @@ pub struct TypeDefData { pub parent: Option, pub docs: String, pub sig: Option, + pub attributes: Vec, } /// Data for a reference to a type or trait. @@ -396,6 +405,7 @@ pub struct VariableData { pub visibility: Visibility, pub docs: String, pub sig: Option, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3c275e0996dac..54069775418ce 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -47,7 +47,8 @@ use syntax::ptr::P; use syntax::codemap::Spanned; use syntax_pos::*; -use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; +use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs, + remove_docs_from_attrs}; use super::data::*; use super::dump::Dump; use super::external_data::{Lower, make_def_id}; @@ -373,6 +374,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -448,6 +450,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: method_data.sig, + attributes: remove_docs_from_attrs(attrs), }.lower(self.tcx)); } @@ -519,6 +522,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: None, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -592,6 +596,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: None, + attributes: remove_docs_from_attrs(attrs), }.lower(self.tcx)); } @@ -636,6 +641,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), }.lower(self.tcx)); } @@ -701,6 +707,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, + attributes: remove_docs_from_attrs(&variant.node.attrs), }.lower(self.tcx)); } } @@ -727,6 +734,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, + attributes: remove_docs_from_attrs(&variant.node.attrs), }.lower(self.tcx)); } } @@ -798,6 +806,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), }.lower(self.tcx)); } @@ -1064,6 +1073,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -1305,6 +1315,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, parent: None, docs: docs_for_attrs(&item.attrs), sig: Some(self.save_ctxt.sig_base(item)), + attributes: remove_docs_from_attrs(&item.attrs), }.lower(self.tcx)); } @@ -1527,6 +1538,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index fccb56e88b3de..0cfa71a349916 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -11,7 +11,7 @@ use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; -use syntax::ast::NodeId; +use syntax::ast::{self, LitKind, NodeId, StrStyle}; use syntax::codemap::CodeMap; use syntax_pos::Span; @@ -64,6 +64,102 @@ impl SpanData { } } +/// Represent an arbitrary attribute on a code element +#[derive(Clone, Debug, RustcEncodable)] +pub struct Attribute { + value: AttributeItem, + span: SpanData, +} + +impl Lower for ast::Attribute { + type Target = Attribute; + + fn lower(self, tcx: TyCtxt) -> Attribute { + Attribute { + value: self.value.lower(tcx), + span: SpanData::from_span(self.span, tcx.sess.codemap()), + } + } +} + +impl Lower for Vec { + type Target = Vec; + + fn lower(self, tcx: TyCtxt) -> Vec { + self.into_iter().map(|x| x.lower(tcx)).collect() + } +} + +/// A single item as part of an attribute +#[derive(Clone, Debug, RustcEncodable)] +pub struct AttributeItem { + name: LitKind, + kind: AttributeItemKind, + span: SpanData, +} + +impl Lower for ast::MetaItem { + type Target = AttributeItem; + + fn lower(self, tcx: TyCtxt) -> AttributeItem { + AttributeItem { + name: LitKind::Str(self.name, StrStyle::Cooked), + kind: self.node.lower(tcx), + span: SpanData::from_span(self.span, tcx.sess.codemap()), + } + } +} + +impl Lower for ast::NestedMetaItem { + type Target = AttributeItem; + + fn lower(self, tcx: TyCtxt) -> AttributeItem { + match self.node { + ast::NestedMetaItemKind::MetaItem(item) => item.lower(tcx), + ast::NestedMetaItemKind::Literal(lit) => { + AttributeItem { + name: lit.node, + kind: AttributeItemKind::Literal, + span: SpanData::from_span(lit.span, tcx.sess.codemap()), + } + } + } + } +} + +#[derive(Clone, Debug, RustcEncodable)] +pub enum AttributeItemKind { + /// Word meta item. + /// + /// E.g. `test` as in `#[test]` + Literal, + /// Name value meta item. + /// + /// E.g. `feature = "foo"` as in `#[feature = "foo"]` + NameValue(LitKind, SpanData), + /// List meta item. + /// + /// E.g. the `derive(..)` as in `#[derive(..)]` + List(Vec), +} + +impl Lower for ast::MetaItemKind { + type Target = AttributeItemKind; + + fn lower(self, tcx: TyCtxt) -> AttributeItemKind { + match self { + ast::MetaItemKind::Word => AttributeItemKind::Literal, + ast::MetaItemKind::List(items) => { + AttributeItemKind::List(items.into_iter().map(|x| x.lower(tcx)).collect()) + } + ast::MetaItemKind::NameValue(lit) => { + let span = SpanData::from_span(lit.span, tcx.sess.codemap()); + AttributeItemKind::NameValue(lit.node, span) + } + } + } +} + #[derive(Debug, RustcEncodable)] pub struct CratePreludeData { pub crate_name: String, @@ -98,6 +194,7 @@ pub struct EnumData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::EnumData { @@ -115,6 +212,7 @@ impl Lower for data::EnumData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -179,6 +277,7 @@ pub struct FunctionData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::FunctionData { @@ -197,6 +296,7 @@ impl Lower for data::FunctionData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -346,6 +446,7 @@ pub struct MethodData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::MethodData { @@ -364,6 +465,7 @@ impl Lower for data::MethodData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -381,6 +483,7 @@ pub struct ModData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::ModData { @@ -398,6 +501,7 @@ impl Lower for data::ModData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -437,6 +541,7 @@ pub struct StructData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::StructData { @@ -455,6 +560,7 @@ impl Lower for data::StructData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -471,6 +577,7 @@ pub struct StructVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::StructVariantData { @@ -488,6 +595,7 @@ impl Lower for data::StructVariantData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -504,6 +612,7 @@ pub struct TraitData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::TraitData { @@ -521,6 +630,7 @@ impl Lower for data::TraitData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -537,6 +647,7 @@ pub struct TupleVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::TupleVariantData { @@ -554,6 +665,7 @@ impl Lower for data::TupleVariantData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -570,6 +682,7 @@ pub struct TypeDefData { pub parent: Option, pub docs: String, pub sig: Option, + pub attributes: Vec, } impl Lower for data::TypeDefData { @@ -586,6 +699,7 @@ impl Lower for data::TypeDefData { parent: self.parent, docs: self.docs, sig: self.sig.map(|s| s.lower(tcx)), + attributes: self.attributes.lower(tcx), } } } @@ -675,6 +789,7 @@ pub struct VariableData { pub visibility: Visibility, pub docs: String, pub sig: Option, + pub attributes: Vec, } impl Lower for data::VariableData { @@ -694,6 +809,7 @@ impl Lower for data::VariableData { visibility: self.visibility, docs: self.docs, sig: self.sig.map(|s| s.lower(tcx)), + attributes: self.attributes.lower(tcx), } } } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 09752994290c9..1b72489f83c67 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -87,6 +87,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, }; if def.span.file_name != def.value { // If the module is an out-of-line defintion, then we'll make the @@ -232,6 +233,7 @@ struct Def { decl_id: Option, docs: String, sig: Option, + attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -274,6 +276,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -291,6 +294,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -307,6 +311,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -323,6 +328,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -339,6 +345,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -355,6 +362,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -371,6 +379,7 @@ impl From for Def { decl_id: data.decl_id.map(|id| From::from(id)), docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -387,6 +396,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: None, + attributes: vec![], } } } @@ -403,6 +413,7 @@ impl From for Def { decl_id: None, docs: String::new(), sig: data.sig.map(|s| From::from(s)), + attributes: data.attributes, } } } @@ -424,6 +435,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: None, + attributes: data.attributes, } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b1e435dcc751c..b650fe1024b23 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -136,6 +136,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -164,6 +165,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -183,6 +185,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Mod(ref m) => { @@ -205,6 +208,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Enum(ref def, _) => { @@ -228,6 +232,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => { @@ -315,6 +320,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&field.vis), docs: docs_for_attrs(&field.attrs), sig: Some(sig), + attributes: remove_docs_from_attrs(&field.attrs), }) } else { None @@ -327,7 +333,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, parent_scope, decl_id, vis, docs) = + let (qualname, parent_scope, decl_id, vis, docs, attributes) = match self.tcx.impl_of_method(self.tcx.hir.local_def_id(id)) { Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) { Some(Node::NodeItem(item)) => { @@ -349,7 +355,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { (result, trait_id, decl_id, From::from(&item.vis), - docs_for_attrs(&item.attrs)) + docs_for_attrs(&item.attrs), + remove_docs_from_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -374,7 +381,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { (format!("::{}", self.tcx.item_path_str(def_id)), Some(def_id), None, From::from(&item.vis), - docs_for_attrs(&item.attrs)) + docs_for_attrs(&item.attrs), + remove_docs_from_attrs(&item.attrs)) } r => { span_bug!(span, @@ -423,6 +431,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: parent_scope, docs: docs, sig: sig, + attributes: attributes, }) } @@ -836,6 +845,12 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { result } +/// Remove all attributes which are docs +fn remove_docs_from_attrs(attrs: &[Attribute]) -> Vec { + let doc = Symbol::intern("doc"); + attrs.iter().cloned().filter(|attr| attr.name() != doc).collect() +} + #[derive(Clone, Copy, Debug, RustcEncodable)] pub enum Format { Csv, From 203d22762ddb215af583108d79a521a8441693c2 Mon Sep 17 00:00:00 2001 From: Jonas Bushart Date: Thu, 23 Feb 2017 23:24:12 +0100 Subject: [PATCH 40/73] Store attributes as strings Remove the AST structure --- src/librustc_save_analysis/external_data.rs | 85 +++------------------ 1 file changed, 11 insertions(+), 74 deletions(-) diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 0cfa71a349916..38d1df2abb888 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -11,8 +11,9 @@ use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; -use syntax::ast::{self, LitKind, NodeId, StrStyle}; +use syntax::ast::{self, NodeId}; use syntax::codemap::CodeMap; +use syntax::print::pprust; use syntax_pos::Span; use data::{self, Visibility, SigElement}; @@ -67,16 +68,22 @@ impl SpanData { /// Represent an arbitrary attribute on a code element #[derive(Clone, Debug, RustcEncodable)] pub struct Attribute { - value: AttributeItem, + value: String, span: SpanData, } impl Lower for ast::Attribute { type Target = Attribute; - fn lower(self, tcx: TyCtxt) -> Attribute { + fn lower(mut self, tcx: TyCtxt) -> Attribute { + // strip #[] and #![] from the original attributes + self.style = ast::AttrStyle::Outer; + let value = pprust::attribute_to_string(&self); + // #[] are all ASCII which makes this slice save + let value = value[2..value.len()-1].to_string(); + Attribute { - value: self.value.lower(tcx), + value: value, span: SpanData::from_span(self.span, tcx.sess.codemap()), } } @@ -90,76 +97,6 @@ impl Lower for Vec { } } -/// A single item as part of an attribute -#[derive(Clone, Debug, RustcEncodable)] -pub struct AttributeItem { - name: LitKind, - kind: AttributeItemKind, - span: SpanData, -} - -impl Lower for ast::MetaItem { - type Target = AttributeItem; - - fn lower(self, tcx: TyCtxt) -> AttributeItem { - AttributeItem { - name: LitKind::Str(self.name, StrStyle::Cooked), - kind: self.node.lower(tcx), - span: SpanData::from_span(self.span, tcx.sess.codemap()), - } - } -} - -impl Lower for ast::NestedMetaItem { - type Target = AttributeItem; - - fn lower(self, tcx: TyCtxt) -> AttributeItem { - match self.node { - ast::NestedMetaItemKind::MetaItem(item) => item.lower(tcx), - ast::NestedMetaItemKind::Literal(lit) => { - AttributeItem { - name: lit.node, - kind: AttributeItemKind::Literal, - span: SpanData::from_span(lit.span, tcx.sess.codemap()), - } - } - } - } -} - -#[derive(Clone, Debug, RustcEncodable)] -pub enum AttributeItemKind { - /// Word meta item. - /// - /// E.g. `test` as in `#[test]` - Literal, - /// Name value meta item. - /// - /// E.g. `feature = "foo"` as in `#[feature = "foo"]` - NameValue(LitKind, SpanData), - /// List meta item. - /// - /// E.g. the `derive(..)` as in `#[derive(..)]` - List(Vec), -} - -impl Lower for ast::MetaItemKind { - type Target = AttributeItemKind; - - fn lower(self, tcx: TyCtxt) -> AttributeItemKind { - match self { - ast::MetaItemKind::Word => AttributeItemKind::Literal, - ast::MetaItemKind::List(items) => { - AttributeItemKind::List(items.into_iter().map(|x| x.lower(tcx)).collect()) - } - ast::MetaItemKind::NameValue(lit) => { - let span = SpanData::from_span(lit.span, tcx.sess.codemap()); - AttributeItemKind::NameValue(lit.node, span) - } - } - } -} - #[derive(Debug, RustcEncodable)] pub struct CratePreludeData { pub crate_name: String, From db35604792fb64efa0a3deaebc0ea0842e19c67a Mon Sep 17 00:00:00 2001 From: Jonas Bushart Date: Thu, 2 Mar 2017 22:38:57 +0100 Subject: [PATCH 41/73] Move remove_docs_from_attrs into lowering step --- src/librustc_save_analysis/dump_visitor.rs | 17 +++++---- src/librustc_save_analysis/external_data.rs | 38 +++++++++++---------- src/librustc_save_analysis/lib.rs | 22 +++++------- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 54069775418ce..cbb1a3e502363 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -47,8 +47,7 @@ use syntax::ptr::P; use syntax::codemap::Spanned; use syntax_pos::*; -use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs, - remove_docs_from_attrs}; +use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; use super::data::*; use super::dump::Dump; use super::external_data::{Lower, make_def_id}; @@ -450,7 +449,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: method_data.sig, - attributes: remove_docs_from_attrs(attrs), + attributes: attrs.to_vec(), }.lower(self.tcx)); } @@ -596,7 +595,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: None, - attributes: remove_docs_from_attrs(attrs), + attributes: attrs.to_vec(), }.lower(self.tcx)); } @@ -641,7 +640,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -707,7 +706,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, - attributes: remove_docs_from_attrs(&variant.node.attrs), + attributes: variant.node.attrs.clone(), }.lower(self.tcx)); } } @@ -734,7 +733,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, - attributes: remove_docs_from_attrs(&variant.node.attrs), + attributes: variant.node.attrs.clone(), }.lower(self.tcx)); } } @@ -806,7 +805,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -1315,7 +1314,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, parent: None, docs: docs_for_attrs(&item.attrs), sig: Some(self.save_ctxt.sig_base(item)), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), }.lower(self.tcx)); } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 38d1df2abb888..41658dc5b1b48 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -14,6 +14,7 @@ use rustc::ty::TyCtxt; use syntax::ast::{self, NodeId}; use syntax::codemap::CodeMap; use syntax::print::pprust; +use syntax::symbol::Symbol; use syntax_pos::Span; use data::{self, Visibility, SigElement}; @@ -72,28 +73,29 @@ pub struct Attribute { span: SpanData, } -impl Lower for ast::Attribute { - type Target = Attribute; - - fn lower(mut self, tcx: TyCtxt) -> Attribute { - // strip #[] and #![] from the original attributes - self.style = ast::AttrStyle::Outer; - let value = pprust::attribute_to_string(&self); - // #[] are all ASCII which makes this slice save - let value = value[2..value.len()-1].to_string(); - - Attribute { - value: value, - span: SpanData::from_span(self.span, tcx.sess.codemap()), - } - } -} - impl Lower for Vec { type Target = Vec; fn lower(self, tcx: TyCtxt) -> Vec { - self.into_iter().map(|x| x.lower(tcx)).collect() + let doc = Symbol::intern("doc"); + self.into_iter() + // Only retain real attributes. Doc comments are lowered separately. + .filter(|attr| attr.name() != doc) + .map(|mut attr| { + // Remove the surrounding '#[..]' or '#![..]' of the pretty printed + // attribute. First normalize all inner attribute (#![..]) to outer + // ones (#[..]), then remove the two leading and the one trailing character. + attr.style = ast::AttrStyle::Outer; + let value = pprust::attribute_to_string(&attr); + // This str slicing works correctly, because the leading and trailing characters + // are in the ASCII range and thus exactly one byte each. + let value = value[2..value.len()-1].to_string(); + + Attribute { + value: value, + span: SpanData::from_span(attr.span, tcx.sess.codemap()), + } + }).collect() } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b650fe1024b23..2153b30b62cd5 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -136,7 +136,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -165,7 +165,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -185,7 +185,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Mod(ref m) => { @@ -208,7 +208,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Enum(ref def, _) => { @@ -232,7 +232,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => { @@ -320,7 +320,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&field.vis), docs: docs_for_attrs(&field.attrs), sig: Some(sig), - attributes: remove_docs_from_attrs(&field.attrs), + attributes: field.attrs.clone(), }) } else { None @@ -356,7 +356,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { (result, trait_id, decl_id, From::from(&item.vis), docs_for_attrs(&item.attrs), - remove_docs_from_attrs(&item.attrs)) + item.attrs.to_vec()) } _ => { span_bug!(span, @@ -382,7 +382,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(def_id), None, From::from(&item.vis), docs_for_attrs(&item.attrs), - remove_docs_from_attrs(&item.attrs)) + item.attrs.to_vec()) } r => { span_bug!(span, @@ -845,12 +845,6 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { result } -/// Remove all attributes which are docs -fn remove_docs_from_attrs(attrs: &[Attribute]) -> Vec { - let doc = Symbol::intern("doc"); - attrs.iter().cloned().filter(|attr| attr.name() != doc).collect() -} - #[derive(Clone, Copy, Debug, RustcEncodable)] pub enum Format { Csv, From 17e694d47f4d5dbb1fc32a495fe9067c31061faa Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 17 Feb 2017 15:12:47 -0800 Subject: [PATCH 42/73] Add catch expr to AST and disallow catch as a struct name --- src/librustc/hir/lowering.rs | 37 +++++++++++++++++-- src/libsyntax/ast.rs | 2 + src/libsyntax/feature_gate.rs | 6 +++ src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 35 ++++++++++++++++++ src/libsyntax/print/pprust.rs | 5 +++ src/libsyntax/symbol.rs | 3 +- src/libsyntax/visit.rs | 3 ++ .../compile-fail/catch-empty-struct-name.rs | 15 ++++++++ src/test/compile-fail/catch-enum-variant.rs | 17 +++++++++ src/test/compile-fail/catch-struct-name.rs | 15 ++++++++ .../compile-fail/catch-tuple-struct-name.rs | 15 ++++++++ .../compile-fail/feature-gate-catch_expr.rs | 17 +++++++++ src/test/run-pass/catch-expr.rs | 30 +++++++++++++++ 14 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/catch-empty-struct-name.rs create mode 100644 src/test/compile-fail/catch-enum-variant.rs create mode 100644 src/test/compile-fail/catch-struct-name.rs create mode 100644 src/test/compile-fail/catch-tuple-struct-name.rs create mode 100644 src/test/compile-fail/feature-gate-catch_expr.rs create mode 100644 src/test/run-pass/catch-expr.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 257cdb960d529..3d51a64c22132 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -83,6 +83,7 @@ pub struct LoweringContext<'a> { trait_impls: BTreeMap>, trait_default_impl: BTreeMap, + catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, @@ -121,6 +122,7 @@ pub fn lower_crate(sess: &Session, bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), + catch_scopes: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), @@ -259,6 +261,21 @@ impl<'a> LoweringContext<'a> { span } + fn with_catch_scope(&mut self, catch_id: NodeId, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let len = self.catch_scopes.len(); + self.catch_scopes.push(catch_id); + + let result = f(self); + assert_eq!(len + 1, self.catch_scopes.len(), + "catch scopes should be added and removed in stack order"); + + self.catch_scopes.pop().unwrap(); + + result + } + fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { @@ -293,15 +310,17 @@ impl<'a> LoweringContext<'a> { result } - fn with_new_loop_scopes(&mut self, f: F) -> T + fn with_new_scopes(&mut self, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; + let catch_scopes = mem::replace(&mut self.catch_scopes, Vec::new()); let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new()); let result = f(self); - mem::replace(&mut self.loop_scopes, loop_scopes); + self.catch_scopes = catch_scopes; + self.loop_scopes = loop_scopes; self.is_in_loop_condition = was_in_loop_condition; @@ -1063,7 +1082,7 @@ impl<'a> LoweringContext<'a> { self.record_body(value, None)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { let body = this.lower_block(body); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); @@ -1660,13 +1679,17 @@ impl<'a> LoweringContext<'a> { this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } + ExprKind::Catch(ref body) => { + // FIXME(cramertj): Add catch to HIR + self.with_catch_scope(e.id, |this| hir::ExprBlock(this.lower_block(body))) + } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), arms.iter().map(|x| self.lower_arm(x)).collect(), hir::MatchSource::Normal) } ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { let expr = this.lower_expr(body); hir::ExprClosure(this.lower_capture_clause(capture_clause), @@ -2064,6 +2087,12 @@ impl<'a> LoweringContext<'a> { // Err(err) => #[allow(unreachable_code)] // return Carrier::from_error(From::from(err)), // } + + // FIXME(cramertj): implement breaking to catch + if !self.catch_scopes.is_empty() { + bug!("`?` in catch scopes is unimplemented") + } + let unstable_span = self.allow_internal_unstable("?", e.span); // Carrier::translate() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9cc754cbf4d19..43089e541af0e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -936,6 +936,8 @@ pub enum ExprKind { Closure(CaptureBy, P, P, Span), /// A block (`{ ... }`) Block(P), + /// A catch block (`catch { ... }`) + Catch(P), /// An assignment (`a = foo()`) Assign(P, P), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e7bf16eae9ee6..15913d56d162f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -339,6 +339,9 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + + // Allows the `catch {...}` expression + (active, catch_expr, "1.17.0", Some(31436)), ); declare_features! ( @@ -1287,6 +1290,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } } + ast::ExprKind::Catch(_) => { + gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); + } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4242b0f8b9803..c7f423ffaaf91 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1272,6 +1272,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu }; } ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), + ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)), }, id: folder.new_id(id), span: folder.new_span(span), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..3af66d6164131 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -602,6 +602,12 @@ impl<'a> Parser<'a> { } } + pub fn error_if_typename_is_catch(&mut self, ident: ast::Ident) { + if ident.name == keywords::Catch.name() { + self.span_err(self.span, "cannot use `catch` as the name of a type"); + } + } + /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -2273,6 +2279,11 @@ impl<'a> Parser<'a> { BlockCheckMode::Unsafe(ast::UserProvided), attrs); } + if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Catch)); + let lo = self.prev_span.lo; + return self.parse_catch_expr(lo, attrs); + } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; @@ -3092,6 +3103,16 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } + /// Parse a `catch {...}` expression (`catch` token already eaten) + pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) + -> PResult<'a, P> + { + let (iattrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(iattrs); + let hi = body.span.hi; + Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs)) + } + // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let match_span = self.prev_span; @@ -3699,6 +3720,14 @@ impl<'a> Parser<'a> { }) } + fn is_catch_expr(&mut self) -> bool { + self.token.is_keyword(keywords::Catch) && + self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && + + // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. + !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) + } + fn is_union_item(&mut self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) @@ -4839,6 +4868,8 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + self.error_if_typename_is_catch(class_name); + let mut generics = self.parse_generics()?; // There is a special case worth noting here, as reported in issue #17904. @@ -4888,6 +4919,8 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + self.error_if_typename_is_catch(class_name); + let mut generics = self.parse_generics()?; let vdata = if self.token.is_keyword(keywords::Where) { @@ -5404,6 +5437,7 @@ impl<'a> Parser<'a> { let struct_def; let mut disr_expr = None; let ident = self.parse_ident()?; + self.error_if_typename_is_catch(ident); if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; @@ -5445,6 +5479,7 @@ impl<'a> Parser<'a> { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; + self.error_if_typename_is_catch(id); let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 53ef8e8dfa49c..a700232c02d15 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2270,6 +2270,11 @@ impl<'a> State<'a> { self.print_expr(e)?; word(&mut self.s, "?")? } + ast::ExprKind::Catch(ref blk) => { + self.head("catch")?; + space(&mut self.s)?; + self.print_block_with_attrs(&blk, attrs)? + } } self.ann.post(self, NodeExpr(expr))?; self.end() diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index c278171aa109a..6642c60d256b3 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -221,9 +221,10 @@ declare_keywords! { (53, Default, "default") (54, StaticLifetime, "'static") (55, Union, "union") + (56, Catch, "catch") // A virtual keyword that resolves to the crate root when used in a lexical scope. - (56, CrateRoot, "{{root}}") + (57, CrateRoot, "{{root}}") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 013632141dee6..c76846cdf8e27 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -787,6 +787,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Try(ref subexpression) => { visitor.visit_expr(subexpression) } + ExprKind::Catch(ref body) => { + visitor.visit_block(body) + } } visitor.visit_expr_post(expression) diff --git a/src/test/compile-fail/catch-empty-struct-name.rs b/src/test/compile-fail/catch-empty-struct-name.rs new file mode 100644 index 0000000000000..257cb802cc0f8 --- /dev/null +++ b/src/test/compile-fail/catch-empty-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch; //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/catch-enum-variant.rs b/src/test/compile-fail/catch-enum-variant.rs new file mode 100644 index 0000000000000..7aa162750d189 --- /dev/null +++ b/src/test/compile-fail/catch-enum-variant.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +enum Enum { + catch {} //~ ERROR cannot use `catch` as the name of a type +} diff --git a/src/test/compile-fail/catch-struct-name.rs b/src/test/compile-fail/catch-struct-name.rs new file mode 100644 index 0000000000000..63661ccf607a0 --- /dev/null +++ b/src/test/compile-fail/catch-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch {} //~ ERROR cannot use `catch` as the name of a type \ No newline at end of file diff --git a/src/test/compile-fail/catch-tuple-struct-name.rs b/src/test/compile-fail/catch-tuple-struct-name.rs new file mode 100644 index 0000000000000..1a8866d85430d --- /dev/null +++ b/src/test/compile-fail/catch-tuple-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch(); //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/feature-gate-catch_expr.rs b/src/test/compile-fail/feature-gate-catch_expr.rs new file mode 100644 index 0000000000000..8a1a5ceae89e0 --- /dev/null +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let catch_result = catch { //~ ERROR `catch` expression is experimental + let x = 5; + x + }; + assert_eq!(catch_result, 5); +} diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs new file mode 100644 index 0000000000000..c70b6100efe4f --- /dev/null +++ b/src/test/run-pass/catch-expr.rs @@ -0,0 +1,30 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(catch_expr)] + +pub fn main() { + let catch_result = catch { + let x = 5; + x + }; + assert_eq!(catch_result, 5); + + let mut catch = true; + while catch { catch = false; } + assert_eq!(catch, false); + + catch = if catch { false } else { true }; + assert_eq!(catch, true); + + match catch { + _ => {} + }; +} From 9f0e9f3d71a7197333029a48df6dedd4055852e1 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 3 Mar 2017 14:41:07 -0800 Subject: [PATCH 43/73] Temporarily prefix catch block with do keyword --- src/libsyntax/parse/parser.rs | 18 +++++------------- src/libsyntax/parse/token.rs | 1 + .../compile-fail/catch-empty-struct-name.rs | 15 --------------- src/test/compile-fail/catch-enum-variant.rs | 17 ----------------- src/test/compile-fail/catch-struct-name.rs | 15 --------------- .../compile-fail/catch-tuple-struct-name.rs | 15 --------------- .../compile-fail/feature-gate-catch_expr.rs | 2 +- src/test/run-pass/catch-expr.rs | 4 +++- 8 files changed, 10 insertions(+), 77 deletions(-) delete mode 100644 src/test/compile-fail/catch-empty-struct-name.rs delete mode 100644 src/test/compile-fail/catch-enum-variant.rs delete mode 100644 src/test/compile-fail/catch-struct-name.rs delete mode 100644 src/test/compile-fail/catch-tuple-struct-name.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3af66d6164131..a38666a0e94ad 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -602,12 +602,6 @@ impl<'a> Parser<'a> { } } - pub fn error_if_typename_is_catch(&mut self, ident: ast::Ident) { - if ident.name == keywords::Catch.name() { - self.span_err(self.span, "cannot use `catch` as the name of a type"); - } - } - /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -2280,6 +2274,7 @@ impl<'a> Parser<'a> { attrs); } if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Do)); assert!(self.eat_keyword(keywords::Catch)); let lo = self.prev_span.lo; return self.parse_catch_expr(lo, attrs); @@ -3103,7 +3098,7 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } - /// Parse a `catch {...}` expression (`catch` token already eaten) + /// Parse a `do catch {...}` expression (`do catch` token already eaten) pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) -> PResult<'a, P> { @@ -3721,8 +3716,9 @@ impl<'a> Parser<'a> { } fn is_catch_expr(&mut self) -> bool { - self.token.is_keyword(keywords::Catch) && - self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && + self.token.is_keyword(keywords::Do) && + self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && + self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) && // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) @@ -4868,7 +4864,6 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; - self.error_if_typename_is_catch(class_name); let mut generics = self.parse_generics()?; @@ -4919,7 +4914,6 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; - self.error_if_typename_is_catch(class_name); let mut generics = self.parse_generics()?; @@ -5437,7 +5431,6 @@ impl<'a> Parser<'a> { let struct_def; let mut disr_expr = None; let ident = self.parse_ident()?; - self.error_if_typename_is_catch(ident); if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; @@ -5479,7 +5472,6 @@ impl<'a> Parser<'a> { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; - self.error_if_typename_is_catch(id); let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5b65aac92b81c..25601f2420e8a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -86,6 +86,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { !ident_token.is_any_keyword() || ident_token.is_path_segment_keyword() || [ + keywords::Do.name(), keywords::Box.name(), keywords::Break.name(), keywords::Continue.name(), diff --git a/src/test/compile-fail/catch-empty-struct-name.rs b/src/test/compile-fail/catch-empty-struct-name.rs deleted file mode 100644 index 257cb802cc0f8..0000000000000 --- a/src/test/compile-fail/catch-empty-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch; //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/catch-enum-variant.rs b/src/test/compile-fail/catch-enum-variant.rs deleted file mode 100644 index 7aa162750d189..0000000000000 --- a/src/test/compile-fail/catch-enum-variant.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -enum Enum { - catch {} //~ ERROR cannot use `catch` as the name of a type -} diff --git a/src/test/compile-fail/catch-struct-name.rs b/src/test/compile-fail/catch-struct-name.rs deleted file mode 100644 index 63661ccf607a0..0000000000000 --- a/src/test/compile-fail/catch-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch {} //~ ERROR cannot use `catch` as the name of a type \ No newline at end of file diff --git a/src/test/compile-fail/catch-tuple-struct-name.rs b/src/test/compile-fail/catch-tuple-struct-name.rs deleted file mode 100644 index 1a8866d85430d..0000000000000 --- a/src/test/compile-fail/catch-tuple-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch(); //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/feature-gate-catch_expr.rs b/src/test/compile-fail/feature-gate-catch_expr.rs index 8a1a5ceae89e0..5568a5cf0aac2 100644 --- a/src/test/compile-fail/feature-gate-catch_expr.rs +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let catch_result = catch { //~ ERROR `catch` expression is experimental + let catch_result = do catch { //~ ERROR `catch` expression is experimental let x = 5; x }; diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs index c70b6100efe4f..a9b28a534a348 100644 --- a/src/test/run-pass/catch-expr.rs +++ b/src/test/run-pass/catch-expr.rs @@ -10,8 +10,10 @@ #![feature(catch_expr)] +struct catch {} + pub fn main() { - let catch_result = catch { + let catch_result = do catch { let x = 5; x }; From b549f1495b7b48bec5e46701d47cf633d82bc011 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 6 Mar 2017 18:16:57 -0800 Subject: [PATCH 44/73] Add compile-fail tests for catch expr in match or condition --- src/test/compile-fail/catch-in-match.rs | 15 +++++++++++++++ src/test/compile-fail/catch-in-while.rs | 15 +++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/compile-fail/catch-in-match.rs create mode 100644 src/test/compile-fail/catch-in-while.rs diff --git a/src/test/compile-fail/catch-in-match.rs b/src/test/compile-fail/catch-in-match.rs new file mode 100644 index 0000000000000..9f9968e81242a --- /dev/null +++ b/src/test/compile-fail/catch-in-match.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(catch_expr)] + +fn main() { + match do catch { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `do` +} diff --git a/src/test/compile-fail/catch-in-while.rs b/src/test/compile-fail/catch-in-while.rs new file mode 100644 index 0000000000000..cb8613ee60b42 --- /dev/null +++ b/src/test/compile-fail/catch-in-while.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(catch_expr)] + +fn main() { + while do catch { false } {} //~ ERROR expected expression, found reserved keyword `do` +} From 2b5f1b2f8e62176e3a10c00c63f3e4b70475959c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 1 Mar 2017 15:34:54 -0800 Subject: [PATCH 45/73] rustbuild: Build documentation for `proc_macro` This commit fixes #38749 by building documentation for the `proc_macro` crate by default for configured hosts. Unfortunately did not turn out to be a trivial fix. Currently rustbuild generates documentation into multiple locations: one for std, one for test, and one for rustc. The initial fix for this issue simply actually executed `cargo doc -p proc_macro` which was otherwise completely elided before. Unfortunately rustbuild was the left to merge two documentation trees together. One for the standard library and one for the rustc tree (which only had docs for the `proc_macro` crate). Rustdoc itself knows how to merge documentation files (specifically around search indexes, etc) but rustbuild was unaware of this, so an initial fix ended up destroying the sidebar and the search bar from the libstd docs. To solve this issue the method of documentation has been tweaked slightly in rustbuild. The build system will not use symlinks (or directory junctions on Windows) to generate all documentation into the same location initially. This'll rely on rustdoc's logic to weave together all the output and ensure that it ends up all consistent. Closes #38749 --- src/bootstrap/doc.rs | 63 +++++++++++++++--- src/bootstrap/lib.rs | 7 ++ src/bootstrap/step.rs | 2 +- src/bootstrap/util.rs | 139 +++++++++++++++++++++++++++++++++++++++ src/libproc_macro/lib.rs | 2 +- 5 files changed, 202 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index d19e5b1b88456..9c3f0ce62f349 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -19,10 +19,12 @@ use std::fs::{self, File}; use std::io::prelude::*; +use std::io; +use std::path::Path; use std::process::Command; use {Build, Compiler, Mode}; -use util::cp_r; +use util::{cp_r, symlink_dir}; use build_helper::up_to_date; /// Invoke `rustbook` as compiled in `stage` for `target` for the doc book @@ -141,7 +143,22 @@ pub fn std(build: &Build, stage: u32, target: &str) { .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - build.clear_if_dirty(&out_dir, &rustdoc); + // Here what we're doing is creating a *symlink* (directory junction on + // Windows) to the final output location. This is not done as an + // optimization but rather for correctness. We've got three trees of + // documentation, one for std, one for test, and one for rustc. It's then + // our job to merge them all together. + // + // Unfortunately rustbuild doesn't know nearly as well how to merge doc + // trees as rustdoc does itself, so instead of actually having three + // separate trees we just have rustdoc output to the same location across + // all of them. + // + // This way rustdoc generates output directly into the output, and rustdoc + // will also directly handle merging. + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc"); cargo.arg("--manifest-path") @@ -166,7 +183,7 @@ pub fn std(build: &Build, stage: u32, target: &str) { build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Compile all libtest documentation. @@ -187,13 +204,16 @@ pub fn test(build: &Build, stage: u32, target: &str) { .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - build.clear_if_dirty(&out_dir, &rustdoc); + // See docs in std above for why we symlink + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/libtest/Cargo.toml")); build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Generate all compiler documentation. @@ -213,15 +233,28 @@ pub fn rustc(build: &Build, stage: u32, target: &str) { let out_dir = build.stage_out(&compiler, Mode::Librustc) .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) && out_dir.exists() { - t!(fs::remove_dir_all(&out_dir)); - } + + // See docs in std above for why we symlink + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); + let mut cargo = build.cargo(&compiler, Mode::Librustc, target, "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")) .arg("--features").arg(build.rustc_features()); + + // Like with libstd above if compiler docs aren't enabled then we're not + // documenting internal dependencies, so we have a whitelist. + if !build.config.compiler_docs { + cargo.arg("--no-deps"); + for krate in &["proc_macro"] { + cargo.arg("-p").arg(krate); + } + } + build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Generates the HTML rendered error-index by running the @@ -240,3 +273,15 @@ pub fn error_index(build: &Build, target: &str) { build.run(&mut index); } + +fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> { + if let Ok(m) = fs::symlink_metadata(dst) { + if m.file_type().is_dir() { + try!(fs::remove_dir_all(dst)); + } else { + try!(fs::remove_file(dst)); + } + } + + symlink_dir(src, dst) +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 071d0b0b09009..97fc5886478c8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -707,6 +707,13 @@ impl Build { self.out.join(target).join("doc") } + /// Output directory for all crate documentation for a target (temporary) + /// + /// The artifacts here are then copied into `doc_out` above. + fn crate_doc_out(&self, target: &str) -> PathBuf { + self.out.join(target).join("crate-docs") + } + /// Returns true if no custom `llvm-config` is set for the specified target. /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index a5c0d11d21985..c24a555280ba9 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -640,7 +640,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc(&krate.doc_step, path) .dep(|s| s.name("librustc-link")) .host(true) - .default(default && build.config.compiler_docs) + .default(default && build.config.docs) .run(move |s| doc::rustc(build, s.stage, s.target)); } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index fc63655d79b6c..dab20f44bc361 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -16,6 +16,7 @@ use std::env; use std::ffi::OsString; use std::fs; +use std::io; use std::path::{Path, PathBuf}; use std::process::Command; use std::time::Instant; @@ -183,3 +184,141 @@ impl Drop for TimeIt { time.subsec_nanos() / 1_000_000); } } + +/// Symlinks two directories, using junctions on Windows and normal symlinks on +/// Unix. +pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> { + let _ = fs::remove_dir(dest); + return symlink_dir_inner(src, dest); + + #[cfg(not(windows))] + fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> { + use std::os::unix::fs; + fs::symlink(src, dest) + } + + // Creating a directory junction on windows involves dealing with reparse + // points and the DeviceIoControl function, and this code is a skeleton of + // what can be found here: + // + // http://www.flexhex.com/docs/articles/hard-links.phtml + // + // Copied from std + #[cfg(windows)] + #[allow(bad_style)] + fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> { + use std::ptr; + use std::ffi::OsStr; + use std::os::windows::ffi::OsStrExt; + + const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; + const GENERIC_WRITE: DWORD = 0x40000000; + const OPEN_EXISTING: DWORD = 3; + const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; + const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; + const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; + const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003; + const FILE_SHARE_DELETE: DWORD = 0x4; + const FILE_SHARE_READ: DWORD = 0x1; + const FILE_SHARE_WRITE: DWORD = 0x2; + + type BOOL = i32; + type DWORD = u32; + type HANDLE = *mut u8; + type LPCWSTR = *const u16; + type LPDWORD = *mut DWORD; + type LPOVERLAPPED = *mut u8; + type LPSECURITY_ATTRIBUTES = *mut u8; + type LPVOID = *mut u8; + type WCHAR = u16; + type WORD = u16; + + #[repr(C)] + struct REPARSE_MOUNTPOINT_DATA_BUFFER { + ReparseTag: DWORD, + ReparseDataLength: DWORD, + Reserved: WORD, + ReparseTargetLength: WORD, + ReparseTargetMaximumLength: WORD, + Reserved1: WORD, + ReparseTarget: WCHAR, + } + + extern "system" { + fn CreateFileW(lpFileName: LPCWSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE) + -> HANDLE; + fn DeviceIoControl(hDevice: HANDLE, + dwIoControlCode: DWORD, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesReturned: LPDWORD, + lpOverlapped: LPOVERLAPPED) -> BOOL; + } + + fn to_u16s>(s: S) -> io::Result> { + Ok(s.as_ref().encode_wide().chain(Some(0)).collect()) + } + + // We're using low-level APIs to create the junction, and these are more + // picky about paths. For example, forward slashes cannot be used as a + // path separator, so we should try to canonicalize the path first. + let target = try!(fs::canonicalize(target)); + + try!(fs::create_dir(junction)); + + let path = try!(to_u16s(junction)); + + unsafe { + let h = CreateFileW(path.as_ptr(), + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0 as *mut _, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + ptr::null_mut()); + + let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut db = data.as_mut_ptr() + as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; + let buf = &mut (*db).ReparseTarget as *mut _; + let mut i = 0; + // FIXME: this conversion is very hacky + let v = br"\??\"; + let v = v.iter().map(|x| *x as u16); + for c in v.chain(target.as_os_str().encode_wide().skip(4)) { + *buf.offset(i) = c; + i += 1; + } + *buf.offset(i) = 0; + i += 1; + (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + (*db).ReparseTargetMaximumLength = (i * 2) as WORD; + (*db).ReparseTargetLength = ((i - 1) * 2) as WORD; + (*db).ReparseDataLength = + (*db).ReparseTargetLength as DWORD + 12; + + let mut ret = 0; + let res = DeviceIoControl(h as *mut _, + FSCTL_SET_REPARSE_POINT, + data.as_ptr() as *mut _, + (*db).ReparseDataLength + 8, + ptr::null_mut(), 0, + &mut ret, + ptr::null_mut()); + + if res == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + } +} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 8d7fe655c23b2..0d2a467b57702 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -21,7 +21,7 @@ //! This functionality is intended to be expanded over time as more surface //! area for macro authors is stabilized. //! -//! See [the book](../../book/procedural-macros.html) for more. +//! See [the book](../book/procedural-macros.html) for more. #![crate_name = "proc_macro"] #![stable(feature = "proc_macro_lib", since = "1.15.0")] From 212b6c25507b963b60a646a2ff3df7496bd30acf Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 5 Mar 2017 05:15:58 +0000 Subject: [PATCH 46/73] Refactor out `ast::ItemKind::MacroDef`. --- src/librustc/hir/lowering.rs | 51 ++++++++++-------- src/librustc/hir/map/def_collector.rs | 6 +-- src/librustc/middle/cstore.rs | 2 +- src/librustc_driver/driver.rs | 3 -- src/librustc_metadata/cstore_impl.rs | 6 ++- src/librustc_passes/hir_stats.rs | 5 -- src/librustc_resolve/build_reduced_graph.rs | 34 ++++++------ src/librustc_resolve/lib.rs | 15 ++---- src/librustc_resolve/macros.rs | 53 +++++++------------ src/librustdoc/visit_ast.rs | 12 +++-- src/libsyntax/ast.rs | 27 +++------- src/libsyntax/ext/base.rs | 6 +-- src/libsyntax/ext/expand.rs | 17 ++---- src/libsyntax/ext/hygiene.rs | 2 +- src/libsyntax/ext/placeholders.rs | 15 ------ src/libsyntax/ext/tt/macro_rules.rs | 10 ++-- src/libsyntax/fold.rs | 11 ++-- src/libsyntax/parse/parser.rs | 46 ++++++++++++++-- src/libsyntax/print/pprust.rs | 11 +++- src/libsyntax/util/node_count.rs | 5 -- src/libsyntax/visit.rs | 10 +--- src/libsyntax_ext/deriving/mod.rs | 2 +- src/libsyntax_ext/lib.rs | 2 +- src/libsyntax_ext/proc_macro_registrar.rs | 16 +++--- .../pretty-expanded-hygiene/input.pp.rs | 1 + 25 files changed, 172 insertions(+), 196 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 257cdb960d529..f9f63ccbfde7e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -79,6 +79,7 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, bodies: BTreeMap, + exported_macros: Vec, trait_impls: BTreeMap>, trait_default_impl: BTreeMap, @@ -121,6 +122,7 @@ pub fn lower_crate(sess: &Session, bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), + exported_macros: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), @@ -170,9 +172,10 @@ impl<'a> LoweringContext<'a> { impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { fn visit_item(&mut self, item: &'lcx Item) { - let hir_item = self.lctx.lower_item(item); - self.lctx.items.insert(item.id, hir_item); - visit::walk_item(self, item); + if let Some(hir_item) = self.lctx.lower_item(item) { + self.lctx.items.insert(item.id, hir_item); + visit::walk_item(self, item); + } } fn visit_trait_item(&mut self, item: &'lcx TraitItem) { @@ -195,14 +198,13 @@ 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, attrs: attrs, span: c.span, - exported_macros: exported_macros, + exported_macros: hir::HirVec::from(self.exported_macros), items: self.items, trait_items: self.trait_items, impl_items: self.impl_items, @@ -1134,7 +1136,7 @@ impl<'a> LoweringContext<'a> { bounds, items) } - ItemKind::Mac(_) => panic!("Shouldn't still be around"), + ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } } @@ -1256,42 +1258,45 @@ impl<'a> LoweringContext<'a> { } } - fn lower_macro_def(&mut self, m: &MacroDef) -> hir::MacroDef { - hir::MacroDef { - name: m.ident.name, - attrs: self.lower_attrs(&m.attrs), - id: m.id, - span: m.span, - body: m.body.clone().into(), - } - } - fn lower_item_id(&mut self, i: &Item) -> SmallVector { - if let ItemKind::Use(ref view_path) = i.node { - if let ViewPathList(_, ref imports) = view_path.node { - return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)) - .map(|id| hir::ItemId { id: id }).collect(); + match i.node { + ItemKind::Use(ref view_path) => { + if let ViewPathList(_, ref imports) = view_path.node { + return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)) + .map(|id| hir::ItemId { id: id }).collect(); + } } + ItemKind::MacroDef(..) => return SmallVector::new(), + _ => {} } SmallVector::one(hir::ItemId { id: i.id }) } - pub fn lower_item(&mut self, i: &Item) -> hir::Item { + pub fn lower_item(&mut self, i: &Item) -> Option { let mut name = i.ident.name; let attrs = self.lower_attrs(&i.attrs); let mut vis = self.lower_visibility(&i.vis); + if let ItemKind::MacroDef(ref tts, _) = i.node { + if i.attrs.iter().any(|attr| attr.name() == "macro_export") { + self.exported_macros.push(hir::MacroDef { + name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(), + }); + } + return None; + } + let node = self.with_parent_def(i.id, |this| { this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node) }); - hir::Item { + Some(hir::Item { id: i.id, name: name, attrs: attrs, node: node, vis: vis, span: i.span, - } + }) } fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index ccaf663c7ad2a..f15e063e81e33 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -108,7 +108,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => DefPathData::ValueNs(i.ident.name.as_str()), - ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder + ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), ItemKind::Use(ref view_path) => { match view_path.node { @@ -269,10 +269,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str())); } - fn visit_macro_def(&mut self, macro_def: &'a MacroDef) { - self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str())); - } - fn visit_stmt(&mut self, stmt: &'a Stmt) { match stmt.node { StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4a7027b8997a5..e9fb4632fa178 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -136,7 +136,7 @@ pub struct NativeLibrary { } pub enum LoadedMacro { - MacroRules(ast::MacroDef), + MacroDef(ast::Item), ProcMacro(Rc), } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..e458d45bbd6e8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -43,7 +43,6 @@ use super::Compilation; use serialize::json; use std::env; -use std::mem; use std::ffi::{OsString, OsStr}; use std::fs; use std::io::{self, Write}; @@ -705,8 +704,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate }); - krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new()); - krate = time(time_passes, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, &mut resolver, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cf2219e0e3df5..cfe67726ab228 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -34,6 +34,7 @@ use std::rc::Rc; use syntax::ast; use syntax::attr; +use syntax::ext::hygiene::Mark; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; use syntax_pos::{mk_sp, Span}; @@ -414,12 +415,13 @@ impl CrateStore for cstore::CStore { sess.imported_macro_spans.borrow_mut() .insert(local_span, (name.to_string(), data.get_span(id.index, sess))); - LoadedMacro::MacroRules(ast::MacroDef { + LoadedMacro::MacroDef(ast::Item { ident: ast::Ident::with_empty_ctxt(name), id: ast::DUMMY_NODE_ID, span: local_span, attrs: attrs, - body: body.into(), + node: ast::ItemKind::MacroDef(body.into(), Mark::fresh()), + vis: ast::Visibility::Inherited, }) } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 65a60732fc807..749146fe49672 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -375,9 +375,4 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_attribute(&mut self, attr: &'v ast::Attribute) { self.record("Attribute", Id::None, attr); } - - fn visit_macro_def(&mut self, macro_def: &'v ast::MacroDef) { - self.record("MacroDef", Id::None, macro_def); - ast_visit::walk_macro_def(self, macro_def) - } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index da08d1b7c78e2..8b20c31be03b7 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -37,7 +37,6 @@ use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::Undetermined; -use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::parse::token; @@ -373,7 +372,7 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.current_module = module; } - ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), + ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(), } } @@ -502,22 +501,21 @@ impl<'a> Resolver<'a> { return ext.clone(); } - let mut macro_rules = match self.session.cstore.load_macro(def_id, &self.session) { - LoadedMacro::MacroRules(macro_rules) => macro_rules, + let macro_def = match self.session.cstore.load_macro(def_id, &self.session) { + LoadedMacro::MacroDef(macro_def) => macro_def, LoadedMacro::ProcMacro(ext) => return ext, }; - let mark = Mark::fresh(); let invocation = self.arenas.alloc_invocation_data(InvocationData { module: Cell::new(self.get_extern_crate_root(def_id.krate)), - def_index: CRATE_DEF_INDEX, - const_expr: false, - legacy_scope: Cell::new(LegacyScope::Empty), - expansion: Cell::new(LegacyScope::Empty), + // FIXME(jseyfried) the following are irrelevant + def_index: CRATE_DEF_INDEX, const_expr: false, + legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty), }); - self.invocations.insert(mark, invocation); - macro_rules.body = mark_tts(macro_rules.stream(), mark).into(); - let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_rules)); + if let ast::ItemKind::MacroDef(_, mark) = macro_def.node { + self.invocations.insert(mark, invocation); + } + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext } @@ -707,12 +705,12 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { fn visit_item(&mut self, item: &'a Item) { let macro_use = match item.node { - ItemKind::Mac(ref mac) => { - if mac.node.path.segments.is_empty() { - self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); - } else { - self.resolver.define_macro(item, &mut self.legacy_scope); - } + ItemKind::MacroDef(..) => { + self.resolver.define_macro(item, &mut self.legacy_scope); + return + } + ItemKind::Mac(..) => { + self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); return } ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d51ec268ec217..9ea129c2efbf6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1092,10 +1092,6 @@ pub struct Resolver<'a> { pub definitions: Definitions, - // Maps the node id of a statement to the expansions of the `macro_rules!`s - // immediately above the statement (if appropriate). - macros_at_scope: FxHashMap>, - graph_root: Module<'a>, prelude: Option>, @@ -1171,7 +1167,6 @@ pub struct Resolver<'a> { dummy_binding: &'a NameBinding<'a>, use_extern_macros: bool, // true if `#![feature(use_extern_macros)]` - pub exported_macros: Vec, crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, builtin_macros: FxHashMap>, @@ -1309,7 +1304,6 @@ impl<'a> Resolver<'a> { session: session, definitions: definitions, - macros_at_scope: FxHashMap(), // The outermost module has def ID 0; this is not reflected in the // AST. @@ -1365,7 +1359,6 @@ impl<'a> Resolver<'a> { // `#![feature(proc_macro)]` implies `#[feature(extern_macros)]` use_extern_macros: features.use_extern_macros || features.proc_macro, - exported_macros: Vec::new(), crate_loader: crate_loader, macro_names: FxHashSet(), builtin_macros: FxHashMap(), @@ -1696,7 +1689,7 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) => { + ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => { // do nothing, these are just around to be encoded } @@ -2031,9 +2024,9 @@ impl<'a> Resolver<'a> { // Descend into the block. for stmt in &block.stmts { - if let Some(marks) = self.macros_at_scope.remove(&stmt.id) { - num_macro_definition_ribs += marks.len() as u32; - for mark in marks { + if let ast::StmtKind::Item(ref item) = stmt.node { + if let ast::ItemKind::MacroDef(_, mark) = item.node { + num_macro_definition_ribs += 1; self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark))); self.label_ribs.push(Rib::new(MacroDefinition(mark))); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 720d616e007d2..fc6b1baca160b 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -25,7 +25,7 @@ use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension}; use syntax::ext::base::MacroKind; -use syntax::ext::expand::{Expansion, mark_tts}; +use syntax::ext::expand::Expansion; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; @@ -33,7 +33,6 @@ use syntax::fold::{self, Folder}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax::visit::Visitor; use syntax_pos::{Span, DUMMY_SP}; #[derive(Clone)] @@ -151,7 +150,7 @@ impl<'a> base::Resolver for Resolver<'a> { invocation.expansion.set(visitor.legacy_scope); } - fn add_ext(&mut self, ident: ast::Ident, ext: Rc) { + fn add_builtin(&mut self, ident: ast::Ident, ext: Rc) { let def_id = DefId { krate: BUILTIN_MACROS_CRATE, index: DefIndex::new(self.macro_map.len()), @@ -167,10 +166,6 @@ impl<'a> base::Resolver for Resolver<'a> { self.builtin_macros.insert(ident.name, binding); } - fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { - self.macros_at_scope.insert(id, macros); - } - fn resolve_imports(&mut self) { ImportResolver { resolver: self }.resolve_imports() } @@ -544,45 +539,33 @@ impl<'a> Resolver<'a> { } pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) { - let tts = match item.node { - ast::ItemKind::Mac(ref mac) => mac.node.stream(), - _ => unreachable!(), - }; - if item.ident.name == "macro_rules" { self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); } - let mark = Mark::from_placeholder_id(item.id); - let invocation = self.invocations[&mark]; - invocation.module.set(self.current_module); - - let mut def = ast::MacroDef { - ident: item.ident, - attrs: item.attrs.clone(), - id: ast::DUMMY_NODE_ID, - span: item.span, - body: mark_tts(tts, mark).into(), - }; + let invocation = self.arenas.alloc_invocation_data(InvocationData { + module: Cell::new(self.current_module), + // FIXME(jseyfried) the following are irrelevant + def_index: CRATE_DEF_INDEX, const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty), + }); + if let ast::ItemKind::MacroDef(_, mark) = item.node { + self.invocations.insert(mark, invocation); + } *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { parent: Cell::new(*legacy_scope), - name: def.ident.name, - ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), - span: def.span, + name: item.ident.name, + ext: Rc::new(macro_rules::compile(&self.session.parse_sess, item)), + span: item.span, })); - self.macro_names.insert(def.ident.name); + self.macro_names.insert(item.ident.name); - if attr::contains_name(&def.attrs, "macro_export") { - def.id = self.next_node_id(); - DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { - collector.visit_macro_def(&def) - }); + if attr::contains_name(&item.attrs, "macro_export") { self.macro_exports.push(Export { - name: def.ident.name, - def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang), + name: item.ident.name, + def: Def::Macro(self.definitions.local_def_id(item.id), MacroKind::Bang), }); - self.exported_macros.push(def); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 42928427233d7..35d459422033f 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -16,6 +16,7 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; +use syntax::tokenstream::TokenStream; use syntax_pos::Span; use rustc::hir::map as hir_map; @@ -205,14 +206,17 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate); let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) { - LoadedMacro::MacroRules(macro_rules) => macro_rules, + LoadedMacro::MacroDef(macro_def) => macro_def, // FIXME(jseyfried): document proc macro reexports LoadedMacro::ProcMacro(..) => continue, }; - // FIXME(jseyfried) merge with `self.visit_macro()` - let tts = def.stream().trees().collect::>(); - let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect(); + let matchers = if let ast::ItemKind::MacroDef(ref tokens, _) = def.node { + let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect(); + tts.chunks(4).map(|arm| arm[0].span()).collect() + } else { + unreachable!() + }; om.macros.push(Macro { def_id: def_id, attrs: def.attrs.clone().into(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9cc754cbf4d19..a79cfc2bceb33 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -20,7 +20,7 @@ pub use util::ThinVec; use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId}; use codemap::{respan, Spanned}; use abi::Abi; -use ext::hygiene::SyntaxContext; +use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; use ptr::P; use symbol::{Symbol, keywords}; @@ -414,7 +414,6 @@ pub struct Crate { pub module: Mod, pub attrs: Vec, pub span: Span, - pub exported_macros: Vec, } /// A spanned compile-time attribute list item. @@ -1855,10 +1854,13 @@ pub enum ItemKind { Option, // (optional) trait this impl implements P, // self Vec), - /// A macro invocation (which includes macro definition). + /// A macro invocation. /// /// E.g. `macro_rules! foo { .. }` or `foo!(..)` Mac(Mac), + + /// A macro definition. + MacroDef(ThinTokenStream, Mark /* FIXME(jseyfried) remove this */), } impl ItemKind { @@ -1877,6 +1879,7 @@ impl ItemKind { ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", ItemKind::Mac(..) | + ItemKind::MacroDef(..) | ItemKind::Impl(..) | ItemKind::DefaultImpl(..) => "item" } @@ -1912,24 +1915,6 @@ impl ForeignItemKind { } } -/// A macro definition, in this crate or imported from another. -/// -/// Not parsed directly, but created on macro import or `macro_rules!` expansion. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct MacroDef { - pub ident: Ident, - pub attrs: Vec, - pub id: NodeId, - pub span: Span, - pub body: ThinTokenStream, -} - -impl MacroDef { - pub fn stream(&self) -> TokenStream { - self.body.clone().into() - } -} - #[cfg(test)] mod tests { use serialize; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e242cf2777fe5..39d919106147d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -552,8 +552,7 @@ pub trait Resolver { fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]); - fn add_ext(&mut self, ident: ast::Ident, ext: Rc); - fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); + fn add_builtin(&mut self, ident: ast::Ident, ext: Rc); fn resolve_imports(&mut self); // Resolves attribute and derive legacy macros from `#![plugin(..)]`. @@ -577,8 +576,7 @@ impl Resolver for DummyResolver { fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {} - fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} - fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} + fn add_builtin(&mut self, _ident: ast::Ident, _ext: Rc) {} fn resolve_imports(&mut self) {} fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f1662284a8820..8451414ec3d8a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -948,17 +948,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { match item.node { ast::ItemKind::Mac(..) => { self.check_attributes(&item.attrs); - let is_macro_def = if let ItemKind::Mac(ref mac) = item.node { - mac.node.path.segments[0].identifier.name == "macro_rules" - } else { - unreachable!() - }; - - item.and_then(|mut item| match item.node { - ItemKind::Mac(_) if is_macro_def => { - item.id = Mark::fresh().as_placeholder_id(); - SmallVector::one(P(item)) - } + item.and_then(|item| match item.node { ItemKind::Mac(mac) => { self.collect(ExpansionKind::Items, InvocationKind::Bang { mac: mac, @@ -1078,7 +1068,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { - noop_fold_item_kind(self.cfg.configure_item_kind(item), self) + match item { + ast::ItemKind::MacroDef(..) => item, + _ => noop_fold_item_kind(self.cfg.configure_item_kind(item), self), + } } fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 2af5c2ea9995e..83c51bb9d2fcf 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -31,7 +31,7 @@ pub struct SyntaxContextData { } /// A mark is a unique id associated with a macro expansion. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)] pub struct Mark(u32); impl Mark { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index e2fb1946e90db..f60b1d17a5e2f 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -21,7 +21,6 @@ use util::move_map::MoveMap; use util::small_vector::SmallVector; use std::collections::HashMap; -use std::mem; pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { fn mac_placeholder() -> ast::Mac { @@ -174,20 +173,11 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_block(&mut self, block: P) -> P { noop_fold_block(block, self).map(|mut block| { - let mut macros = Vec::new(); let mut remaining_stmts = block.stmts.len(); block.stmts = block.stmts.move_flat_map(|mut stmt| { remaining_stmts -= 1; - // `macro_rules!` macro definition - if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::Mac(_) = item.node { - macros.push(Mark::from_placeholder_id(item.id)); - return None; - } - } - match stmt.node { // Avoid wasting a node id on a trailing expression statement, // which shares a HIR node with the expression itself. @@ -201,11 +191,6 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { _ => {} } - if self.monotonic && !macros.is_empty() { - let macros = mem::replace(&mut macros, Vec::new()); - self.cx.resolver.add_expansions_at_stmt(stmt.id, macros); - } - Some(stmt) }); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 1d386c1a3ac93..8ad679b853e85 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -12,7 +12,7 @@ use {ast, attr}; use syntax_pos::{Span, DUMMY_SP}; use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; use ext::base::{NormalTT, TTMacroExpander}; -use ext::expand::{Expansion, ExpansionKind}; +use ext::expand::{Expansion, ExpansionKind, mark_tts}; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_failure_msg}; @@ -153,7 +153,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // Holy self-referential! /// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { +pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); @@ -183,7 +183,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { ]; // Parse the macro_rules! invocation - let argument_map = match parse(sess, def.body.clone().into(), &argument_gram, None) { + let body = match def.node { + ast::ItemKind::MacroDef(ref body, mark) => mark_tts(body.clone().into(), mark), + _ => unreachable!(), + }; + let argument_map = match parse(sess, body, &argument_gram, None) { Success(m) => m, Failure(sp, tok) => { let s = parse_failure_msg(tok); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4242b0f8b9803..d23f880bc7bac 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -899,6 +899,8 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { items.move_flat_map(|item| folder.fold_trait_item(item)), ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), + ItemKind::MacroDef(tts, mark) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into(), + mark), } } @@ -959,7 +961,7 @@ pub fn noop_fold_mod(Mod {inner, items}: Mod, folder: &mut T) -> Mod } } -pub fn noop_fold_crate(Crate {module, attrs, mut exported_macros, span}: Crate, +pub fn noop_fold_crate(Crate {module, attrs, span}: Crate, folder: &mut T) -> Crate { let mut items = folder.fold_item(P(ast::Item { ident: keywords::Invalid.ident(), @@ -987,14 +989,9 @@ pub fn noop_fold_crate(Crate {module, attrs, mut exported_macros, spa }, vec![], span) }; - for def in &mut exported_macros { - def.id = folder.new_id(def.id); - } - Crate { module: module, attrs: attrs, - exported_macros: exported_macros, span: span, } } @@ -1387,6 +1384,6 @@ mod tests { matches_codepattern, "matches_codepattern", pprust::to_string(|s| fake_print_crate(s, &folded_crate)), - "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string()); + "macro_rules! zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string()); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..d81732489dd3d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,6 +43,7 @@ use {ast, attr}; use codemap::{self, CodeMap, Spanned, spanned, respan}; use syntax_pos::{self, Span, Pos, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; +use ext::hygiene::Mark; use parse::{self, classify, token}; use parse::common::SeqSep; use parse::lexer::TokenAndSpan; @@ -1048,7 +1049,7 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } - pub fn look_ahead(&mut self, dist: usize, f: F) -> R where + pub fn look_ahead(&self, dist: usize, f: F) -> R where F: FnOnce(&token::Token) -> R, { if dist == 0 { @@ -3699,11 +3700,41 @@ impl<'a> Parser<'a> { }) } - fn is_union_item(&mut self) -> bool { + fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) } + fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) + -> PResult<'a, Option>> { + let lo = self.span.lo; + match self.token { + token::Ident(ident) if ident.name == "macro_rules" => { + if self.look_ahead(1, |t| *t == token::Not) { + let prev_span = self.prev_span; + self.complain_if_pub_macro(vis, prev_span); + self.bump(); + self.bump(); + } + } + _ => return Ok(None), + }; + + let id = self.parse_ident()?; + let (delim, tts) = self.expect_delimited_token_tree()?; + if delim != token::Brace { + if !self.eat(&token::Semi) { + let msg = "macros that expand to items must either be surrounded with braces \ + or followed by a semicolon"; + self.span_err(self.prev_span, msg); + } + } + + let hi = self.prev_span.hi; + let kind = ItemKind::MacroDef(tts, Mark::fresh()); + Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) + } + fn parse_stmt_without_recovery(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option> { @@ -3718,6 +3749,12 @@ impl<'a> Parser<'a> { node: StmtKind::Local(self.parse_local(attrs.into())?), span: mk_sp(lo, self.prev_span.hi), } + } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? { + Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Item(macro_def), + span: mk_sp(lo, self.prev_span.hi), + } // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && !self.token.is_qpath_start() && @@ -5767,6 +5804,10 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } + if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility)? { + return Ok(Some(macro_def)); + } + self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility) } @@ -5948,7 +5989,6 @@ impl<'a> Parser<'a> { attrs: self.parse_inner_attributes()?, module: self.parse_mod_items(&token::Eof, lo)?, span: mk_sp(lo, self.span.lo), - exported_macros: Vec::new(), }) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 53ef8e8dfa49c..78212fb4b447c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1318,7 +1318,6 @@ impl<'a> State<'a> { self.bclose(item.span)?; } ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { - self.print_visibility(&item.vis)?; self.print_path(&node.path, false, 0, false)?; word(&mut self.s, "! ")?; self.print_ident(item.ident)?; @@ -1329,6 +1328,16 @@ impl<'a> State<'a> { word(&mut self.s, ";")?; self.end()?; } + ast::ItemKind::MacroDef(ref tts, _) => { + word(&mut self.s, "macro_rules! ")?; + self.print_ident(item.ident)?; + self.cbox(INDENT_UNIT)?; + self.popen()?; + self.print_tts(tts.clone().into())?; + self.pclose()?; + word(&mut self.s, ";")?; + self.end()?; + } } self.ann.post(self, NodeItem(item)) } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index b90802d1e7eb8..9d9957a0f4534 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -148,9 +148,4 @@ impl<'ast> Visitor<'ast> for NodeCounter { fn visit_attribute(&mut self, _attr: &Attribute) { self.count += 1; } - fn visit_macro_def(&mut self, macro_def: &MacroDef) { - self.count += 1; - walk_macro_def(self, macro_def) - } - } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 013632141dee6..ee7dd18247b21 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -125,9 +125,6 @@ pub trait Visitor<'ast>: Sized { walk_assoc_type_binding(self, type_binding) } fn visit_attribute(&mut self, _attr: &'ast Attribute) {} - fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { - walk_macro_def(self, macro_def) - } fn visit_vis(&mut self, vis: &'ast Visibility) { walk_vis(self, vis) } @@ -176,12 +173,6 @@ pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, ident: Ident) pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) { visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); walk_list!(visitor, visit_attribute, &krate.attrs); - walk_list!(visitor, visit_macro_def, &krate.exported_macros); -} - -pub fn walk_macro_def<'a, V: Visitor<'a>>(visitor: &mut V, macro_def: &'a MacroDef) { - visitor.visit_ident(macro_def.span, macro_def.ident); - walk_list!(visitor, visit_attribute, ¯o_def.attrs); } pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) { @@ -295,6 +286,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_trait_item, methods); } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), + ItemKind::MacroDef(..) => {}, } walk_list!(visitor, visit_attribute, &item.attrs); } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 3bceb02f3d6c5..b51591bf89d5e 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -99,7 +99,7 @@ macro_rules! derive_traits { pub fn register_builtin_derives(resolver: &mut Resolver) { $( - resolver.add_ext( + resolver.add_builtin( ast::Ident::with_empty_ctxt(Symbol::intern($name)), Rc::new(SyntaxExtension::BuiltinDerive($func)) ); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index f92cde4019f67..1e9b112b6df56 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -59,7 +59,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, deriving::register_builtin_derives(resolver); let mut register = |name, ext| { - resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); + resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); }; macro_rules! register { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 9c96ad547e1ae..5adaf470f2374 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -90,12 +90,7 @@ pub fn modify(sess: &ParseSess, krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros)); - if krate.exported_macros.len() > 0 { - handler.err("cannot export macro_rules! macros from a `proc-macro` \ - crate type currently"); - } - - return krate + krate } fn is_proc_macro_attr(attr: &ast::Attribute) -> bool { @@ -251,6 +246,15 @@ impl<'a> CollectProcMacros<'a> { impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { + if let ast::ItemKind::MacroDef(..) = item.node { + if self.is_proc_macro_crate && + item.attrs.iter().any(|attr| attr.name() == "macro_export") { + let msg = + "cannot export macro_rules! macros from a `proc-macro` crate type currently"; + self.handler.span_err(item.span, msg); + } + } + // First up, make sure we're checking a bare function. If we're not then // we're just not interested in this item. // diff --git a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs index 0717af98b30b4..3d2dd380e488e 100644 --- a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs +++ b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs @@ -12,6 +12,7 @@ #![feature(no_core)] #![no_core] +macro_rules! foo /* 60#0 */(( $ x : ident ) => { y + $ x }); fn bar /* 62#0 */() { let x /* 59#2 */ = 1; y /* 61#4 */ + x /* 59#5 */ } From e83948631836555c61f9eb97e8657f28c74ba433 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 1 Mar 2017 08:44:05 +0000 Subject: [PATCH 47/73] Move `resolve_invoc` from `syntax` to `resolve`. --- src/librustc_resolve/macros.rs | 76 ++++++++++++++++++++++++++++++---- src/libsyntax/ext/base.rs | 12 ++++-- src/libsyntax/ext/expand.rs | 62 +-------------------------- 3 files changed, 78 insertions(+), 72 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fc6b1baca160b..bec8bf845a75a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,16 +17,14 @@ use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex} use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; use rustc::ty; -use std::cell::Cell; -use std::rc::Rc; use syntax::ast::{self, Name, Ident}; -use syntax::attr; +use syntax::attr::{self, HasAttrs}; use syntax::errors::DiagnosticBuilder; -use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; -use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension}; -use syntax::ext::base::MacroKind; -use syntax::ext::expand::Expansion; +use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator}; +use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver}; +use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc}; use syntax::ext::hygiene::Mark; +use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; use syntax::fold::{self, Folder}; @@ -35,6 +33,10 @@ use syntax::symbol::{Symbol, keywords}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; +use std::cell::Cell; +use std::mem; +use std::rc::Rc; + #[derive(Clone)] pub struct InvocationData<'a> { pub module: Cell>, @@ -235,8 +237,64 @@ impl<'a> base::Resolver for Resolver<'a> { None } - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, - force: bool) -> Result, Determinacy> { + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result>, Determinacy> { + let (attr, traits, item) = match invoc.kind { + InvocationKind::Attr { attr: None, .. } => return Ok(None), + InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), + InvocationKind::Bang { ref mac, .. } => { + return self.resolve_macro(scope, &mac.node.path, MacroKind::Bang, force).map(Some); + } + InvocationKind::Derive { name, span, .. } => { + let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); + return self.resolve_macro(scope, &path, MacroKind::Derive, force).map(Some); + } + }; + + let (attr_name, path) = { + let attr = attr.as_ref().unwrap(); + (attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name()))) + }; + + let mut determined = true; + match self.resolve_macro(scope, &path, MacroKind::Attr, force) { + Ok(ext) => return Ok(Some(ext)), + Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), + Err(Determinacy::Determined) => {} + } + + for &(name, span) in traits { + let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); + match self.resolve_macro(scope, &path, MacroKind::Derive, force) { + Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { + if inert_attrs.contains(&attr_name) { + // FIXME(jseyfried) Avoid `mem::replace` here. + let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) + .make_items().pop().unwrap(); + let dummy_item = Annotatable::Item(dummy_item); + *item = mem::replace(item, dummy_item).map_attrs(|mut attrs| { + let inert_attr = attr.take().unwrap(); + attr::mark_known(&inert_attr); + if self.proc_macro_enabled { + *attr = find_attr_invoc(&mut attrs); + } + attrs.push(inert_attr); + attrs + }); + } + return Err(Determinacy::Undetermined); + }, + Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Determined) => {} + } + } + + Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) + } + + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, Determinacy> { let ast::Path { ref segments, span } = *path; if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 39d919106147d..dc7e7673eb03c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,7 +15,7 @@ use attr::HasAttrs; use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::{DiagnosticBuilder, FatalError}; -use ext::expand::{self, Expansion}; +use ext::expand::{self, Expansion, Invocation}; use ext::hygiene::Mark; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; @@ -557,8 +557,10 @@ pub trait Resolver { fn resolve_imports(&mut self); // Resolves attribute and derive legacy macros from `#![plugin(..)]`. fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec) -> Option; - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, - force: bool) -> Result, Determinacy>; + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result>, Determinacy>; + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, Determinacy>; } #[derive(Copy, Clone, Debug)] @@ -580,6 +582,10 @@ impl Resolver for DummyResolver { fn resolve_imports(&mut self) {} fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } + fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool) + -> Result>, Determinacy> { + Err(Determinacy::Determined) + } fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _kind: MacroKind, _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8451414ec3d8a..a208986becf72 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -251,7 +251,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; - let ext = match self.resolve_invoc(&mut invoc, scope, force) { + let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) { Ok(ext) => Some(ext), Err(Determinacy::Determined) => None, Err(Determinacy::Undetermined) => { @@ -364,64 +364,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { result } - fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) - -> Result>, Determinacy> { - let (attr, traits, item) = match invoc.kind { - InvocationKind::Bang { ref mac, .. } => { - return self.cx.resolver.resolve_macro(scope, &mac.node.path, - MacroKind::Bang, force).map(Some); - } - InvocationKind::Attr { attr: None, .. } => return Ok(None), - InvocationKind::Derive { name, span, .. } => { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - return self.cx.resolver.resolve_macro(scope, &path, - MacroKind::Derive, force).map(Some) - } - InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), - }; - - let (attr_name, path) = { - let attr = attr.as_ref().unwrap(); - (attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name()))) - }; - - let mut determined = true; - match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Attr, force) { - Ok(ext) => return Ok(Some(ext)), - Err(Determinacy::Undetermined) => determined = false, - Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), - _ => {} - } - - for &(name, span) in traits { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Derive, force) { - Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { - if inert_attrs.contains(&attr_name) { - // FIXME(jseyfried) Avoid `mem::replace` here. - let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) - .make_items().pop().unwrap(); - *item = mem::replace(item, Annotatable::Item(dummy_item)) - .map_attrs(|mut attrs| { - let inert_attr = attr.take().unwrap(); - attr::mark_known(&inert_attr); - if self.cx.ecfg.proc_macro_enabled() { - *attr = find_attr_invoc(&mut attrs); - } - attrs.push(inert_attr); - attrs - }); - } - return Err(Determinacy::Undetermined); - }, - Err(Determinacy::Undetermined) => determined = false, - Err(Determinacy::Determined) => {} - } - } - - Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) - } - fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), @@ -802,7 +744,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } -fn find_attr_invoc(attrs: &mut Vec) -> Option { +pub fn find_attr_invoc(attrs: &mut Vec) -> Option { for i in 0 .. attrs.len() { if !attr::is_known(&attrs[i]) && !is_builtin_attr(&attrs[i]) { return Some(attrs.remove(i)); From 8c98996934658631308e8fb4069d2db68ff44927 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 1 Mar 2017 23:48:16 +0000 Subject: [PATCH 48/73] Avoid using `Mark` and `Invocation` for macro defs. --- src/librustc/hir/lowering.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 3 +- src/librustc_resolve/build_reduced_graph.rs | 19 ++--- src/librustc_resolve/lib.rs | 55 ++++++++------ src/librustc_resolve/macros.rs | 79 +++++++++++---------- src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/ast.rs | 4 +- src/libsyntax/ext/expand.rs | 10 +-- src/libsyntax/ext/hygiene.rs | 7 -- src/libsyntax/ext/tt/macro_rules.rs | 4 +- src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/parser.rs | 3 +- src/libsyntax/print/pprust.rs | 2 +- 13 files changed, 100 insertions(+), 93 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f9f63ccbfde7e..aa6614b0af4f7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1276,7 +1276,7 @@ impl<'a> LoweringContext<'a> { let mut name = i.ident.name; let attrs = self.lower_attrs(&i.attrs); let mut vis = self.lower_visibility(&i.vis); - if let ItemKind::MacroDef(ref tts, _) = i.node { + if let ItemKind::MacroDef(ref tts) = i.node { if i.attrs.iter().any(|attr| attr.name() == "macro_export") { self.exported_macros.push(hir::MacroDef { name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(), diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cfe67726ab228..2a67b79eaa52e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -34,7 +34,6 @@ use std::rc::Rc; use syntax::ast; use syntax::attr; -use syntax::ext::hygiene::Mark; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; use syntax_pos::{mk_sp, Span}; @@ -420,7 +419,7 @@ impl CrateStore for cstore::CStore { id: ast::DUMMY_NODE_ID, span: local_span, attrs: attrs, - node: ast::ItemKind::MacroDef(body.into(), Mark::fresh()), + node: ast::ItemKind::MacroDef(body.into()), vis: ast::Visibility::Inherited, }) } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 8b20c31be03b7..03c61067d64c2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -492,6 +492,16 @@ impl<'a> Resolver<'a> { }) } + pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> { + let def_id = self.macro_defs[&expansion]; + if let Some(id) = self.definitions.as_local_node_id(def_id) { + self.local_macro_def_scopes[&id] + } else { + let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); + self.get_extern_crate_root(module_def_id.krate) + } + } + pub fn get_macro(&mut self, def: Def) -> Rc { let def_id = match def { Def::Macro(def_id, ..) => def_id, @@ -506,15 +516,6 @@ impl<'a> Resolver<'a> { LoadedMacro::ProcMacro(ext) => return ext, }; - let invocation = self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(self.get_extern_crate_root(def_id.krate)), - // FIXME(jseyfried) the following are irrelevant - def_index: CRATE_DEF_INDEX, const_expr: false, - legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty), - }); - if let ast::ItemKind::MacroDef(_, mark) = macro_def.node { - self.invocations.insert(mark, invocation); - } let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 9ea129c2efbf6..0958748ed092f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -779,8 +779,8 @@ enum RibKind<'a> { // We passed through a module. ModuleRibKind(Module<'a>), - // We passed through a `macro_rules!` statement with the given expansion - MacroDefinition(Mark), + // We passed through a `macro_rules!` statement + MacroDefinition(DefId), // All bindings in this rib are type parameters that can't be used // from the default of a type parameter because they're not declared @@ -997,14 +997,18 @@ impl<'a> NameBinding<'a> { } } - fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc { + fn def_ignoring_ambiguity(&self) -> Def { match self.kind { - NameBindingKind::Import { binding, .. } => binding.get_macro(resolver), - NameBindingKind::Ambiguity { b1, .. } => b1.get_macro(resolver), - _ => resolver.get_macro(self.def()), + NameBindingKind::Import { binding, .. } => binding.def_ignoring_ambiguity(), + NameBindingKind::Ambiguity { b1, .. } => b1.def_ignoring_ambiguity(), + _ => self.def(), } } + fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc { + resolver.get_macro(self.def_ignoring_ambiguity()) + } + // We sometimes need to treat variants as `pub` for backwards compatibility fn pseudo_vis(&self) -> ty::Visibility { if self.is_variant() { ty::Visibility::Public } else { self.vis } @@ -1172,6 +1176,8 @@ pub struct Resolver<'a> { builtin_macros: FxHashMap>, lexical_macro_resolutions: Vec<(Name, &'a Cell>)>, macro_map: FxHashMap>, + macro_defs: FxHashMap, + local_macro_def_scopes: FxHashMap>, macro_exports: Vec, pub whitelisted_legacy_custom_derives: Vec, pub found_unresolved_macro: bool, @@ -1300,6 +1306,9 @@ impl<'a> Resolver<'a> { let features = session.features.borrow(); + let mut macro_defs = FxHashMap(); + macro_defs.insert(Mark::root(), root_def_id); + Resolver { session: session, @@ -1366,6 +1375,8 @@ impl<'a> Resolver<'a> { macro_map: FxHashMap(), macro_exports: Vec::new(), invocations: invocations, + macro_defs: macro_defs, + local_macro_def_scopes: FxHashMap(), name_already_seen: FxHashMap(), whitelisted_legacy_custom_derives: Vec::new(), proc_macro_enabled: features.proc_macro, @@ -1503,12 +1514,12 @@ impl<'a> Resolver<'a> { } } - if let MacroDefinition(mac) = self.ribs[ns][i].kind { + if let MacroDefinition(def) = self.ribs[ns][i].kind { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - let (source_ctxt, source_macro) = ident.ctxt.source(); - if source_macro == mac { - ident.ctxt = source_ctxt; + let ctxt_data = ident.ctxt.data(); + if def == self.macro_defs[&ctxt_data.outer_mark] { + ident.ctxt = ctxt_data.prev_ctxt; } } } @@ -1516,11 +1527,12 @@ impl<'a> Resolver<'a> { None } - fn resolve_crate_var(&mut self, mut crate_var_ctxt: SyntaxContext) -> Module<'a> { - while crate_var_ctxt.source().0 != SyntaxContext::empty() { - crate_var_ctxt = crate_var_ctxt.source().0; + fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext) -> Module<'a> { + let mut ctxt_data = crate_var_ctxt.data(); + while ctxt_data.prev_ctxt != SyntaxContext::empty() { + ctxt_data = ctxt_data.prev_ctxt.data(); } - let module = self.invocations[&crate_var_ctxt.source().1].module.get(); + let module = self.macro_def_scope(ctxt_data.outer_mark); if module.is_local() { self.graph_root } else { module } } @@ -1572,12 +1584,12 @@ impl<'a> Resolver<'a> { NormalRibKind => { // Continue } - MacroDefinition(mac) => { + MacroDefinition(def) => { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - let (source_ctxt, source_macro) = ident.ctxt.source(); - if source_macro == mac { - ident.ctxt = source_ctxt; + let ctxt_data = ident.ctxt.data(); + if def == self.macro_defs[&ctxt_data.outer_mark] { + ident.ctxt = ctxt_data.prev_ctxt; } } _ => { @@ -2025,10 +2037,11 @@ impl<'a> Resolver<'a> { // Descend into the block. for stmt in &block.stmts { if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::MacroDef(_, mark) = item.node { + if let ast::ItemKind::MacroDef(..) = item.node { num_macro_definition_ribs += 1; - self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark))); - self.label_ribs.push(Rib::new(MacroDefinition(mark))); + let def = self.definitions.local_def_id(item.id); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(def))); + self.label_ribs.push(Rib::new(MacroDefinition(def))); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index bec8bf845a75a..7ad122d1c31d8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -74,7 +74,7 @@ pub enum LegacyScope<'a> { pub struct LegacyBinding<'a> { pub parent: Cell>, pub name: ast::Name, - ext: Rc, + def_id: DefId, pub span: Span, } @@ -239,15 +239,34 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) -> Result>, Determinacy> { - let (attr, traits, item) = match invoc.kind { + let def = match invoc.kind { InvocationKind::Attr { attr: None, .. } => return Ok(None), + _ => match self.resolve_invoc_to_def(invoc, scope, force) { + Ok(def) => def, + Err(determinacy) => return Err(determinacy), + }, + }; + self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); + Ok(Some(self.get_macro(def))) + } + + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, Determinacy> { + self.resolve_macro_to_def(scope, path, kind, force).map(|def| self.get_macro(def)) + } +} + +impl<'a> Resolver<'a> { + fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result { + let (attr, traits, item) = match invoc.kind { InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), InvocationKind::Bang { ref mac, .. } => { - return self.resolve_macro(scope, &mac.node.path, MacroKind::Bang, force).map(Some); + return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force); } InvocationKind::Derive { name, span, .. } => { let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - return self.resolve_macro(scope, &path, MacroKind::Derive, force).map(Some); + return self.resolve_macro_to_def(scope, &path, MacroKind::Derive, force); } }; @@ -257,8 +276,8 @@ impl<'a> base::Resolver for Resolver<'a> { }; let mut determined = true; - match self.resolve_macro(scope, &path, MacroKind::Attr, force) { - Ok(ext) => return Ok(Some(ext)), + match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) { + Ok(def) => return Ok(def), Err(Determinacy::Undetermined) => determined = false, Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), Err(Determinacy::Determined) => {} @@ -293,8 +312,8 @@ impl<'a> base::Resolver for Resolver<'a> { Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) } - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) - -> Result, Determinacy> { + fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result { let ast::Path { ref segments, span } = *path; if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = @@ -317,10 +336,10 @@ impl<'a> base::Resolver for Resolver<'a> { return Err(Determinacy::Determined); } - let ext = match self.resolve_path(&path, Some(MacroNS), None) { + let def = match self.resolve_path(&path, Some(MacroNS), None) { PathResult::NonModule(path_res) => match path_res.base_def() { Def::Err => Err(Determinacy::Determined), - def @ _ => Ok(self.get_macro(def)), + def @ _ => Ok(def), }, PathResult::Module(..) => unreachable!(), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), @@ -331,15 +350,15 @@ impl<'a> base::Resolver for Resolver<'a> { }; self.current_module.macro_resolutions.borrow_mut() .push((path.into_boxed_slice(), span)); - return ext; + return def; } let name = path[0].name; let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { - Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), - Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)), + Some(MacroBinding::Legacy(binding)) => Ok(Def::Macro(binding.def_id, MacroKind::Bang)), + Some(MacroBinding::Modern(binding)) => Ok(binding.def_ignoring_ambiguity()), None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { - Ok(binding) => Ok(binding.get_macro(self)), + Ok(binding) => Ok(binding.def_ignoring_ambiguity()), Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), Err(_) => { @@ -354,9 +373,7 @@ impl<'a> base::Resolver for Resolver<'a> { result } -} -impl<'a> Resolver<'a> { // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`) pub fn resolve_lexical_macro_path_segment(&mut self, ident: Ident, @@ -597,33 +614,23 @@ impl<'a> Resolver<'a> { } pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) { - if item.ident.name == "macro_rules" { + self.local_macro_def_scopes.insert(item.id, self.current_module); + let ident = item.ident; + if ident.name == "macro_rules" { self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); } - let invocation = self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(self.current_module), - // FIXME(jseyfried) the following are irrelevant - def_index: CRATE_DEF_INDEX, const_integer: false, - legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty), - }); - if let ast::ItemKind::MacroDef(_, mark) = item.node { - self.invocations.insert(mark, invocation); - } - + let def_id = self.definitions.local_def_id(item.id); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, item)); + self.macro_map.insert(def_id, ext); *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { - parent: Cell::new(*legacy_scope), - name: item.ident.name, - ext: Rc::new(macro_rules::compile(&self.session.parse_sess, item)), - span: item.span, + parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span, })); - self.macro_names.insert(item.ident.name); + self.macro_names.insert(ident.name); if attr::contains_name(&item.attrs, "macro_export") { - self.macro_exports.push(Export { - name: item.ident.name, - def: Def::Macro(self.definitions.local_def_id(item.id), MacroKind::Bang), - }); + let def = Def::Macro(def_id, MacroKind::Bang); + self.macro_exports.push(Export { name: ident.name, def: def }); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 35d459422033f..b80de3cc50546 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -211,7 +211,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { LoadedMacro::ProcMacro(..) => continue, }; - let matchers = if let ast::ItemKind::MacroDef(ref tokens, _) = def.node { + let matchers = if let ast::ItemKind::MacroDef(ref tokens) = def.node { let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect(); tts.chunks(4).map(|arm| arm[0].span()).collect() } else { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a79cfc2bceb33..981667337d59a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -20,7 +20,7 @@ pub use util::ThinVec; use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId}; use codemap::{respan, Spanned}; use abi::Abi; -use ext::hygiene::{Mark, SyntaxContext}; +use ext::hygiene::SyntaxContext; use print::pprust; use ptr::P; use symbol::{Symbol, keywords}; @@ -1860,7 +1860,7 @@ pub enum ItemKind { Mac(Mac), /// A macro definition. - MacroDef(ThinTokenStream, Mark /* FIXME(jseyfried) remove this */), + MacroDef(ThinTokenStream), } impl ItemKind { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a208986becf72..96fcea7148bfa 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -154,7 +154,7 @@ impl ExpansionKind { pub struct Invocation { pub kind: InvocationKind, expansion_kind: ExpansionKind, - expansion_data: ExpansionData, + pub expansion_data: ExpansionData, } pub enum InvocationKind { @@ -432,7 +432,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let extname = path.segments.last().unwrap().identifier.name; let ident = ident.unwrap_or(keywords::Invalid.ident()); - let marked_tts = mark_tts(mac.node.stream(), mark); + let marked_tts = + noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { @@ -1094,8 +1095,3 @@ impl Folder for Marker { span } } - -// apply a given mark to the given token trees. Used prior to expansion of a macro. -pub fn mark_tts(tts: TokenStream, m: Mark) -> TokenStream { - noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None}) -} diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 83c51bb9d2fcf..57f5ab73d3706 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -118,13 +118,6 @@ impl SyntaxContext { }) }) } - - /// If `ident` is macro expanded, return the source ident from the macro definition - /// and the mark of the expansion that created the macro definition. - pub fn source(self) -> (Self /* source context */, Mark /* source macro */) { - let macro_def_ctxt = self.data().prev_ctxt.data(); - (macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark) - } } impl fmt::Debug for SyntaxContext { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 8ad679b853e85..7aa1230f9aeea 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -12,7 +12,7 @@ use {ast, attr}; use syntax_pos::{Span, DUMMY_SP}; use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; use ext::base::{NormalTT, TTMacroExpander}; -use ext::expand::{Expansion, ExpansionKind, mark_tts}; +use ext::expand::{Expansion, ExpansionKind}; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_failure_msg}; @@ -184,7 +184,7 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { // Parse the macro_rules! invocation let body = match def.node { - ast::ItemKind::MacroDef(ref body, mark) => mark_tts(body.clone().into(), mark), + ast::ItemKind::MacroDef(ref body) => body.clone().into(), _ => unreachable!(), }; let argument_map = match parse(sess, body, &argument_gram, None) { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d23f880bc7bac..fb4eb19be2b15 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -899,8 +899,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { items.move_flat_map(|item| folder.fold_trait_item(item)), ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), - ItemKind::MacroDef(tts, mark) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into(), - mark), + ItemKind::MacroDef(tts) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into()), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d81732489dd3d..6446d38e5ef70 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,7 +43,6 @@ use {ast, attr}; use codemap::{self, CodeMap, Spanned, spanned, respan}; use syntax_pos::{self, Span, Pos, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; -use ext::hygiene::Mark; use parse::{self, classify, token}; use parse::common::SeqSep; use parse::lexer::TokenAndSpan; @@ -3731,7 +3730,7 @@ impl<'a> Parser<'a> { } let hi = self.prev_span.hi; - let kind = ItemKind::MacroDef(tts, Mark::fresh()); + let kind = ItemKind::MacroDef(tts); Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 78212fb4b447c..3efadbd00d1e0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1328,7 +1328,7 @@ impl<'a> State<'a> { word(&mut self.s, ";")?; self.end()?; } - ast::ItemKind::MacroDef(ref tts, _) => { + ast::ItemKind::MacroDef(ref tts) => { word(&mut self.s, "macro_rules! ")?; self.print_ident(item.ident)?; self.cbox(INDENT_UNIT)?; From 4ca9c97ace17ca0232bf6f83c06a8a8245614de5 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Mar 2017 19:11:34 +0200 Subject: [PATCH 49/73] Remove ability for plugins to register a MIR pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In recent months there have been a few different people investigating how to make a plugin that registers a MIR-pass – one that isn’t intended to be eventually merged into rustc proper. The interface to register MIR passes was added primarily for miri (& later was found to make prototyping of rustc-proper MIR passes a tiny bit faster). Since miri does not use this interface anymore it seems like a good time to remove this "feature". For prototyping purposes a similar interface can be added by developers themselves in their custom rustc build. --- src/librustc_driver/driver.rs | 3 +- src/librustc_plugin/registry.rs | 11 ---- .../auxiliary/dummy_mir_pass.rs | 55 ------------------- src/test/run-pass-fulldeps/mir-pass.rs | 23 -------- 4 files changed, 1 insertion(+), 91 deletions(-) delete mode 100644 src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs delete mode 100644 src/test/run-pass-fulldeps/mir-pass.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..dda118fb4408e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -604,7 +604,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives(); let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, - llvm_passes, attributes, mir_passes, .. } = registry; + llvm_passes, attributes, .. } = registry; sess.track_errors(|| { let mut ls = sess.lint_store.borrow_mut(); @@ -620,7 +620,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, } *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; - sess.mir_passes.borrow_mut().extend(mir_passes); *sess.plugin_attributes.borrow_mut() = attributes.clone(); })?; diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 3700d0295e963..cdde56f5f634b 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -13,8 +13,6 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use rustc::session::Session; -use rustc::mir::transform::MirMapPass; - use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT}; use syntax::ext::base::MacroExpanderFn; use syntax::symbol::Symbol; @@ -53,9 +51,6 @@ pub struct Registry<'a> { #[doc(hidden)] pub late_lint_passes: Vec, - #[doc(hidden)] - pub mir_passes: Vec MirMapPass<'pcx>>>, - #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, @@ -81,7 +76,6 @@ impl<'a> Registry<'a> { lint_groups: HashMap::new(), llvm_passes: vec![], attributes: vec![], - mir_passes: Vec::new(), whitelisted_custom_derives: Vec::new(), } } @@ -157,11 +151,6 @@ impl<'a> Registry<'a> { self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect()); } - /// Register a MIR pass - pub fn register_mir_pass(&mut self, pass: Box MirMapPass<'pcx>>) { - self.mir_passes.push(pass); - } - /// Register an LLVM pass. /// /// Registration with LLVM itself is handled through static C++ objects with diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs deleted file mode 100644 index 3bc4a40a39c99..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// force-host - -#![feature(plugin_registrar, rustc_private)] -#![feature(box_syntax)] - -#[macro_use] extern crate rustc; -extern crate rustc_plugin; -extern crate rustc_const_math; -extern crate syntax; - -use rustc::mir::transform::{self, MirPass, MirSource}; -use rustc::mir::{Mir, Literal, Location}; -use rustc::mir::visit::MutVisitor; -use rustc::ty::TyCtxt; -use rustc::middle::const_val::ConstVal; -use rustc_const_math::ConstInt; -use rustc_plugin::Registry; - -struct Pass; - -impl transform::Pass for Pass {} - -impl<'tcx> MirPass<'tcx> for Pass { - fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, mir: &mut Mir<'tcx>) { - Visitor.visit_mir(mir) - } -} - -struct Visitor; - -impl<'tcx> MutVisitor<'tcx> for Visitor { - fn visit_literal(&mut self, literal: &mut Literal<'tcx>, _: Location) { - if let Literal::Value { ref mut value } = *literal { - if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value { - *i = 42; - } - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_mir_pass(box Pass); -} diff --git a/src/test/run-pass-fulldeps/mir-pass.rs b/src/test/run-pass-fulldeps/mir-pass.rs deleted file mode 100644 index 8ac4bf9733757..0000000000000 --- a/src/test/run-pass-fulldeps/mir-pass.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:dummy_mir_pass.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(dummy_mir_pass)] - -fn math() -> i32 { - 11 -} - -pub fn main() { - assert_eq!(math(), 42); -} From 1c5584d1068f29fd2987fd7d513c02e013caa8c6 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Sat, 4 Mar 2017 14:03:46 +0300 Subject: [PATCH 50/73] LLVM: Update submodule to include SRet support patch for MSP430. --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index 50ab09fb43f03..859fb26936462 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 50ab09fb43f038e4f824eea6cb278f560d3e8621 +Subproject commit 859fb269364623b17e092efaba3f94e70ce97c5e diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 57f37ea050c1b..e30ad63d52f87 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-03-02 +2017-03-04 From 0a55c8e659f0fc540b740101f7a02ab28e300aa4 Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Mon, 6 Mar 2017 21:42:55 +0100 Subject: [PATCH 51/73] Support armhf abi on 64-bit ARM cpus They report their `uname -m` as armv8l rather than aarch64. Patch originally by Matthias Klose --- configure | 2 +- src/bootstrap/bootstrap.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index be8628de62832..d8861dacafac1 100755 --- a/configure +++ b/configure @@ -512,7 +512,7 @@ case $CFG_CPUTYPE in CFG_OSTYPE="${CFG_OSTYPE}eabihf" ;; - armv7l) + armv7l | armv8l) CFG_CPUTYPE=armv7 CFG_OSTYPE="${CFG_OSTYPE}eabihf" ;; diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 7dd53f41a214a..4f41d337592b3 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -465,7 +465,7 @@ def build_triple(self): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype == 'armv7l': + elif cputype in {'armv7l', 'armv8l'}: cputype = 'arm' ostype += 'eabihf' elif cputype == 'aarch64': From 7b0dd7bdb80768684195f0175d2feecaefd1f2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 5 Mar 2017 23:51:46 -0300 Subject: [PATCH 52/73] Fix incorrect span label formatting --- src/librustc_errors/emitter.rs | 62 ++++++++++++++++------------- src/test/ui/span/issue-40157.rs | 13 ++++++ src/test/ui/span/issue-40157.stderr | 14 +++++++ 3 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/span/issue-40157.rs create mode 100644 src/test/ui/span/issue-40157.stderr diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 0b0a9e51cacb0..431edb3c9bc4d 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -358,39 +358,45 @@ impl EmitterWriter { let mut annotations_position = vec![]; let mut line_len = 0; let mut p = 0; - let mut ann_iter = annotations.iter().peekable(); - while let Some(annotation) = ann_iter.next() { - let peek = ann_iter.peek(); - if let Some(next) = peek { - if overlaps(next, annotation) && !annotation.is_line() && !next.is_line() + for (i, annotation) in annotations.iter().enumerate() { + for (j, next) in annotations.iter().enumerate() { + if overlaps(next, annotation, 0) // This label overlaps with another one and both + && !annotation.is_line() // take space (they have text and are not + && !next.is_line() // multiline lines). && annotation.has_label() + && j > i + && p == 0 // We're currently on the first line, move the label one line down { // This annotation needs a new line in the output. p += 1; + break; } } annotations_position.push((p, annotation)); - if let Some(next) = peek { - let l = if let Some(ref label) = next.label { - label.len() + 2 - } else { - 0 - }; - if (overlaps(next, annotation) // Do not allow two labels to be in the same line - || next.end_col + l > annotation.start_col) // if they overlap including - // padding, to avoid situations like: - // - // fn foo(x: u32) { - // -------^------ - // | | - // fn_spanx_span - // - && !annotation.is_line() // Do not add a new line if this annotation or the - && !next.is_line() // next are vertical line placeholders. - && annotation.has_label() // Both labels must have some text, otherwise - && next.has_label() // they are not overlapping. - { - p += 1; + for (j, next) in annotations.iter().enumerate() { + if j > i { + let l = if let Some(ref label) = next.label { + label.len() + 2 + } else { + 0 + }; + if overlaps(next, annotation, l) // Do not allow two labels to be in the same + // line if they overlap including padding, to + // avoid situations like: + // + // fn foo(x: u32) { + // -------^------ + // | | + // fn_spanx_span + // + && !annotation.is_line() // Do not add a new line if this annotation + && !next.is_line() // or the next are vertical line placeholders. + && annotation.has_label() // Both labels must have some text, otherwise + && next.has_label() // they are not overlapping. + { + p += 1; + break; + } } } if line_len < p { @@ -1088,8 +1094,8 @@ fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclus (b_start..b_end + extra).contains(a_start) || (a_start..a_end + extra).contains(b_start) } -fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { - num_overlap(a1.start_col, a1.end_col, a2.start_col, a2.end_col, false) +fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool { + num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false) } fn emit_to_destination(rendered_buffer: &Vec>, diff --git a/src/test/ui/span/issue-40157.rs b/src/test/ui/span/issue-40157.rs new file mode 100644 index 0000000000000..8f3a7ae341736 --- /dev/null +++ b/src/test/ui/span/issue-40157.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} +} diff --git a/src/test/ui/span/issue-40157.stderr b/src/test/ui/span/issue-40157.stderr new file mode 100644 index 0000000000000..ad1c149d2e56f --- /dev/null +++ b/src/test/ui/span/issue-40157.stderr @@ -0,0 +1,14 @@ +error: `foo` does not live long enough + --> $DIR/issue-40157.rs:12:64 + | +12 | {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} + | ----------------------------------------------------------^------------- + | | | | + | | | `foo` dropped here while still borrowed + | | borrow occurs here + | borrowed value needs to live until here + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + From 4b6b544d6512bfac7c926b3d93246fd14a56eb1d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 Mar 2017 15:35:34 -0500 Subject: [PATCH 53/73] isolate dep-graph tasks A task function is now given as a `fn` pointer to ensure that it carries no state. Each fn can take two arguments, because that worked out to be convenient -- these two arguments must be of some type that is `DepGraphSafe`, a new trait that is intended to prevent "leaking" information into the task that was derived from tracked state. This intentionally leaves `DepGraph::in_task()`, the more common form, alone. Eventually all uses of `DepGraph::in_task()` should be ported to `with_task()`, but I wanted to start with a smaller subset. Originally I wanted to use closures bound by an auto trait, but that approach has some limitations: - the trait cannot have a `read()` method; since the current method is unused, that may not be a problem. - more importantly, we would want the auto trait to be "undefined" for all types *by default* -- that is, this use case doesn't really fit the typical auto trait scenario. For example, imagine that there is a `u32` loaded out of a `hir::Node` -- we don't really want to be passing that `u32` into the task! --- src/librustc/dep_graph/graph.rs | 9 ++- src/librustc/dep_graph/mod.rs | 4 ++ src/librustc/dep_graph/safe.rs | 70 ++++++++++++++++++++++++ src/librustc/lib.rs | 1 + src/librustc_borrowck/borrowck/mod.rs | 13 +++-- src/librustc_incremental/persist/load.rs | 6 +- src/librustc_mir/mir_map.rs | 6 +- src/librustc_trans/base.rs | 39 +++++++++---- src/librustc_trans/context.rs | 8 ++- src/librustc_typeck/check/mod.rs | 14 +++-- src/librustc_typeck/collect.rs | 33 +++++------ 11 files changed, 155 insertions(+), 48 deletions(-) create mode 100644 src/librustc/dep_graph/safe.rs diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index e6736ccafbad9..e22f56d278d55 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use super::dep_node::{DepNode, WorkProductId}; use super::query::DepGraphQuery; use super::raii; +use super::safe::DepGraphSafe; use super::thread::{DepGraphThreadData, DepMessage}; #[derive(Clone)] @@ -76,11 +77,13 @@ impl DepGraph { op() } - pub fn with_task(&self, key: DepNode, op: OP) -> R - where OP: FnOnce() -> R + pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R + where C: DepGraphSafe, A: DepGraphSafe { let _task = self.in_task(key); - op() + cx.read(self); + arg.read(self); + task(cx, arg) } pub fn read(&self, v: DepNode) { diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 7331756f35b8e..496375b129167 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -15,6 +15,8 @@ mod edges; mod graph; mod query; mod raii; +#[macro_use] +mod safe; mod shadow; mod thread; mod visit; @@ -25,6 +27,8 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; +pub use self::safe::AssertDepGraphSafe; +pub use self::safe::DepGraphSafe; 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/safe.rs b/src/librustc/dep_graph/safe.rs new file mode 100644 index 0000000000000..9c5b110929e22 --- /dev/null +++ b/src/librustc/dep_graph/safe.rs @@ -0,0 +1,70 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir::BodyId; +use hir::def_id::DefId; +use syntax::ast::NodeId; +use ty::TyCtxt; + +use super::graph::DepGraph; + +/// The `DepGraphSafe` auto trait is used to specify what kinds of +/// values are safe to "leak" into a task. The idea is that this +/// should be only be implemented for things like the tcx, which will +/// create reads in the dep-graph whenever the trait loads anything +/// that might depend on the input program. +pub trait DepGraphSafe { + fn read(&self, graph: &DepGraph); +} + +impl DepGraphSafe for BodyId { + fn read(&self, _graph: &DepGraph) { + // a BodyId on its own doesn't give access to any particular state + } +} + +impl DepGraphSafe for NodeId { + fn read(&self, _graph: &DepGraph) { + // a DefId doesn't give any particular state + } +} + +impl DepGraphSafe for DefId { + fn read(&self, _graph: &DepGraph) { + // a DefId doesn't give any particular state + } +} + +impl<'a, 'gcx, 'tcx> DepGraphSafe for TyCtxt<'a, 'gcx, 'tcx> { + fn read(&self, _graph: &DepGraph) { + } +} + +impl DepGraphSafe for (A, B) + where A: DepGraphSafe, B: DepGraphSafe +{ + fn read(&self, graph: &DepGraph) { + self.0.read(graph); + self.1.read(graph); + } +} + +impl DepGraphSafe for () { + fn read(&self, _graph: &DepGraph) { + } +} + +/// A convenient override. We should phase out usage of this over +/// time. +pub struct AssertDepGraphSafe(pub T); +impl DepGraphSafe for AssertDepGraphSafe { + fn read(&self, _graph: &DepGraph) { + } +} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c4fccdcb9eb62..2ba4054ef3f6d 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -70,6 +70,7 @@ mod macros; pub mod diagnostics; pub mod cfg; +#[macro_use] pub mod dep_graph; pub mod hir; pub mod infer; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 47b614a81ae25..b441a231874a6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -61,13 +61,16 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || { + tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task); + + fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { 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); - }); + tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), + tcx, + body_id, + borrowck_fn); }); - }); + } } /// Collection of conclusions determined via borrow checker analyses. diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 03411e01a5798..2789250649674 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -192,7 +192,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, clean_work_products.insert(wp.clone()); } - tcx.dep_graph.with_task(n, || ()); // create the node with no inputs + tcx.dep_graph.with_task(n, (), (), create_node); + + fn create_node((): (), (): ()) { + // just create the node with no inputs + } } } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index a41489ff89ff4..58f23a5c81bd7 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -38,11 +38,13 @@ use std::cell::RefCell; use std::mem; pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::MirKrate, || { + tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task); + + fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { tcx.item_mir(body_owner_def_id); }); - }); + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 36f6fa7643909..1b43491e73c8f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -41,7 +41,7 @@ use rustc::mir::tcx::LvalueTy; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::dep_graph::{DepNode, WorkProduct}; +use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; use session::config::{self, NoDebugInfo}; @@ -1211,21 +1211,40 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Instantiate translation items without filling out definitions yet... for ccx in crate_context_list.iter_need_trans() { - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - - tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + trans_decl_task); + + fn trans_decl_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for (trans_item, linkage) in trans_items { trans_item.predefine(&ccx, linkage); } - }); + } } // ... and now that we have everything pre-defined, fill out those definitions. for ccx in crate_context_list.iter_need_trans() { - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + trans_def_task); + + fn trans_def_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for (trans_item, _) in trans_items { trans_item.define(&ccx); } @@ -1247,7 +1266,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); } - }); + } } symbol_names_test::report_symbol_names(&shared_ccx); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d5f7549ece07b..f3aa3c67831ed 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,8 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; +use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, + DepTrackingMapConfig, WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir; use rustc::hir::def::ExportMap; @@ -274,6 +275,11 @@ pub struct CrateContext<'a, 'tcx: 'a> { index: usize, } +impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> { + fn read(&self, _graph: &DepGraph) { + } +} + pub struct CrateContextIterator<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, local_ccxs: &'a [LocalCrateContext<'tcx>], diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2b9ccf6d3e246..5a582a523ea1c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -539,13 +539,15 @@ pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult } pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { - tcx.sess.track_errors(|| { - tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, || { - tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { - tcx.item_tables(body_owner_def_id); - }); + return tcx.sess.track_errors(|| { + tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, tcx, (), check_item_bodies_task); + }); + + fn check_item_bodies_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { + tcx.item_tables(body_owner_def_id); }); - }) + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index db7cf3c000ba4..2417745571910 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -165,15 +165,10 @@ impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> { /// 4. This is added by the code in `visit_expr` when we write to `item_types`. /// 5. This is added by the code in `convert_item` when we write to `item_types`; /// note that this write occurs inside the `CollectItemSig` task. - /// 6. Added by explicit `read` below - fn with_collect_item_sig(&self, id: ast::NodeId, op: OP) - where OP: FnOnce() - { + /// 6. Added by reads from within `op`. + fn with_collect_item_sig(&self, id: ast::NodeId, op: fn(TyCtxt<'a, 'tcx, 'tcx>, ast::NodeId)) { let def_id = self.tcx.hir.local_def_id(id); - self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || { - self.tcx.hir.read(id); - op(); - }); + self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), self.tcx, id, op); } } @@ -183,7 +178,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - self.with_collect_item_sig(item.id, || convert_item(self.tcx, item)); + self.with_collect_item_sig(item.id, convert_item); intravisit::walk_item(self, item); } @@ -216,16 +211,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.with_collect_item_sig(trait_item.id, || { - convert_trait_item(self.tcx, trait_item) - }); + self.with_collect_item_sig(trait_item.id, convert_trait_item); intravisit::walk_trait_item(self, trait_item); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.with_collect_item_sig(impl_item.id, || { - convert_impl_item(self.tcx, impl_item) - }); + self.with_collect_item_sig(impl_item.id, convert_impl_item); intravisit::walk_impl_item(self, impl_item); } } @@ -493,9 +484,10 @@ fn ensure_no_ty_param_bounds(tcx: TyCtxt, } } -fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { +fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { + let it = tcx.hir.expect_item(item_id); debug!("convert: item {} with id {}", it.name, it.id); - let def_id = tcx.hir.local_def_id(it.id); + let def_id = tcx.hir.local_def_id(item_id); match it.node { // These don't define types. hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { @@ -560,7 +552,8 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { } } -fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) { +fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: ast::NodeId) { + let trait_item = tcx.hir.expect_trait_item(trait_item_id); let def_id = tcx.hir.local_def_id(trait_item.id); tcx.item_generics(def_id); @@ -577,8 +570,8 @@ fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::T tcx.item_predicates(def_id); } -fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) { - let def_id = tcx.hir.local_def_id(impl_item.id); +fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: ast::NodeId) { + let def_id = tcx.hir.local_def_id(impl_item_id); tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); From 4d5441fe3dc0869b3f6637e6320c9091b8d9efa0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Mar 2017 09:14:27 -0500 Subject: [PATCH 54/73] add comments and remove unused code paths --- src/librustc/dep_graph/graph.rs | 29 +++++++++++++++++-- src/librustc/dep_graph/mod.rs | 1 - src/librustc/dep_graph/safe.rs | 51 ++++++++++++++------------------- src/librustc/lib.rs | 1 - src/librustc_trans/context.rs | 2 -- 5 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index e22f56d278d55..8be5d4327e72e 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -77,12 +77,37 @@ impl DepGraph { op() } + /// Starts a new dep-graph task. Dep-graph tasks are specified + /// using a free function (`task`) and **not** a closure -- this + /// is intentional because we want to exercise tight control over + /// what state they have access to. In particular, we want to + /// prevent implicit 'leaks' of tracked state into the task (which + /// could then be read without generating correct edges in the + /// dep-graph -- see the [README] for more details on the + /// dep-graph). To this end, the task function gets exactly two + /// pieces of state: the context `cx` and an argument `arg`. Both + /// of these bits of state must be of some type that implements + /// `DepGraphSafe` and hence does not leak. + /// + /// The choice of two arguments is not fundamental. One argument + /// would work just as well, since multiple values can be + /// collected using tuples. However, using two arguments works out + /// to be quite convenient, since it is common to need a context + /// (`cx`) and some argument (e.g., a `DefId` identifying what + /// item to process). + /// + /// For cases where you need some other number of arguments: + /// + /// - If you only need one argument, just use `()` for the `arg` + /// parameter. + /// - If you need 3+ arguments, use a tuple for the + /// `arg` parameter. + /// + /// [README]: README.md pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R where C: DepGraphSafe, A: DepGraphSafe { let _task = self.in_task(key); - cx.read(self); - arg.read(self); task(cx, arg) } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 496375b129167..a9f0a44e4208c 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -15,7 +15,6 @@ mod edges; mod graph; mod query; mod raii; -#[macro_use] mod safe; mod shadow; mod thread; diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs index 9c5b110929e22..f85f0338ed997 100644 --- a/src/librustc/dep_graph/safe.rs +++ b/src/librustc/dep_graph/safe.rs @@ -13,58 +13,51 @@ use hir::def_id::DefId; use syntax::ast::NodeId; use ty::TyCtxt; -use super::graph::DepGraph; - -/// The `DepGraphSafe` auto trait is used to specify what kinds of -/// values are safe to "leak" into a task. The idea is that this -/// should be only be implemented for things like the tcx, which will -/// create reads in the dep-graph whenever the trait loads anything -/// that might depend on the input program. +/// The `DepGraphSafe` trait is used to specify what kinds of values +/// are safe to "leak" into a task. The idea is that this should be +/// only be implemented for things like the tcx as well as various id +/// types, which will create reads in the dep-graph whenever the trait +/// loads anything that might depend on the input program. pub trait DepGraphSafe { - fn read(&self, graph: &DepGraph); } +/// A `BodyId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. impl DepGraphSafe for BodyId { - fn read(&self, _graph: &DepGraph) { - // a BodyId on its own doesn't give access to any particular state - } } +/// A `NodeId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. impl DepGraphSafe for NodeId { - fn read(&self, _graph: &DepGraph) { - // a DefId doesn't give any particular state - } } +/// A `DefId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. impl DepGraphSafe for DefId { - fn read(&self, _graph: &DepGraph) { - // a DefId doesn't give any particular state - } } +/// The type context itself can be used to access all kinds of tracked +/// state, but those accesses should always generate read events. impl<'a, 'gcx, 'tcx> DepGraphSafe for TyCtxt<'a, 'gcx, 'tcx> { - fn read(&self, _graph: &DepGraph) { - } } +/// Tuples make it easy to build up state. impl DepGraphSafe for (A, B) where A: DepGraphSafe, B: DepGraphSafe { - fn read(&self, graph: &DepGraph) { - self.0.read(graph); - self.1.read(graph); - } } +/// No data here! :) impl DepGraphSafe for () { - fn read(&self, _graph: &DepGraph) { - } } -/// A convenient override. We should phase out usage of this over -/// time. +/// A convenient override that lets you pass arbitrary state into a +/// task. Every use should be accompanied by a comment explaining why +/// it makes sense (or how it could be refactored away in the future). pub struct AssertDepGraphSafe(pub T); + impl DepGraphSafe for AssertDepGraphSafe { - fn read(&self, _graph: &DepGraph) { - } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 2ba4054ef3f6d..c4fccdcb9eb62 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -70,7 +70,6 @@ mod macros; pub mod diagnostics; pub mod cfg; -#[macro_use] pub mod dep_graph; pub mod hir; pub mod infer; diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index f3aa3c67831ed..52851ea995d4b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -276,8 +276,6 @@ pub struct CrateContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> { - fn read(&self, _graph: &DepGraph) { - } } pub struct CrateContextIterator<'a, 'tcx: 'a> { From 5afe784daae5782389b97f0ec1317193433ba9a2 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 7 Mar 2017 17:37:45 +1300 Subject: [PATCH 55/73] Expect macro defs in save-analysis and add expn info to spans for attr proc macros --- src/librustc_save_analysis/dump_visitor.rs | 4 +++- src/libsyntax/ext/expand.rs | 14 +++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3c275e0996dac..33d5c17a41921 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -327,6 +327,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: scope }.lower(self.tcx)); } + // With macros 2.0, we can legitimately get a ref to a macro, but + // we don't handle it properly for now (FIXME). + Def::Macro(..) => {} Def::Local(..) | Def::Upvar(..) | Def::SelfTy(..) | @@ -336,7 +339,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | - Def::Macro(..) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f1662284a8820..f7dcd00e40976 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -464,8 +464,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let attr_toks = stream_for_attr_args(&attr, &self.cx.parse_sess); let item_toks = stream_for_item(&item, &self.cx.parse_sess); + let span = Span { + expn_id: self.cx.codemap().record_expansion(ExpnInfo { + call_site: attr.span, + callee: NameAndSpan { + format: MacroAttribute(name), + span: None, + allow_internal_unstable: false, + }, + }), + ..attr.span + }; + let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); - self.parse_expansion(tok_result, kind, name, attr.span) + self.parse_expansion(tok_result, kind, name, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name)); From 0d1343eefa8c1081bb8cecc978c9391d3e2599f0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 7 Mar 2017 23:20:39 +0300 Subject: [PATCH 56/73] rustbuild: Add option for enabling partial LLVM rebuilds --- appveyor.yml | 8 +++---- src/bootstrap/config.rs | 4 ++++ src/bootstrap/config.toml.example | 7 ++++++ src/bootstrap/native.rs | 23 ++++++++----------- ...uto-clean-trigger => llvm-rebuild-trigger} | 2 +- 5 files changed, 26 insertions(+), 18 deletions(-) rename src/rustllvm/{llvm-auto-clean-trigger => llvm-rebuild-trigger} (66%) diff --git a/appveyor.yml b/appveyor.yml index 9a0a4d81f9b1e..7409f83d967b0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -137,10 +137,10 @@ test_script: - sh src/ci/run.sh cache: - - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" branches: only: diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 438ce6103d624..0b36166cc794c 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -59,6 +59,7 @@ pub struct Config { pub llvm_static_stdcpp: bool, pub llvm_link_shared: bool, pub llvm_targets: Option, + pub llvm_clean_rebuild: bool, // rust codegen options pub rust_optimize: bool, @@ -179,6 +180,7 @@ struct Llvm { version_check: Option, static_libstdcpp: Option, targets: Option, + clean_rebuild: Option, } #[derive(RustcDecodable, Default, Clone)] @@ -239,6 +241,7 @@ impl Config { pub fn parse(build: &str, file: Option) -> Config { let mut config = Config::default(); config.llvm_optimize = true; + config.llvm_clean_rebuild = true; config.use_jemalloc = true; config.backtrace = true; config.rust_optimize = true; @@ -332,6 +335,7 @@ impl Config { set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo); set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); + set(&mut config.llvm_clean_rebuild, llvm.clean_rebuild); config.llvm_targets = llvm.targets.clone(); } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 30763e38a336f..f13ba076d2bdf 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -53,6 +53,13 @@ # Rust team and file an issue if you need assistance in porting! #targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" +# Delete LLVM build directory on LLVM rebuild. +# This option's default (`true`) is optimized for CI needs, and CI wants to +# perform clean full builds only (possibly accelerated by (s)ccache). +# You may want to override this option for local builds to enable partial LLVM +# rebuilds. +#clean-rebuild = true + # ============================================================================= # General build configuration options # ============================================================================= diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 483f45fdd6218..2534e020af276 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -41,9 +41,9 @@ pub fn llvm(build: &Build, target: &str) { } } - let clean_trigger = build.src.join("src/rustllvm/llvm-auto-clean-trigger"); - let mut clean_trigger_contents = String::new(); - t!(t!(File::open(&clean_trigger)).read_to_string(&mut clean_trigger_contents)); + let rebuild_trigger = build.src.join("src/rustllvm/llvm-rebuild-trigger"); + let mut rebuild_trigger_contents = String::new(); + t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents)); let out_dir = build.llvm_out(target); let done_stamp = out_dir.join("llvm-finished-building"); @@ -51,18 +51,15 @@ pub fn llvm(build: &Build, target: &str) { let mut done_contents = String::new(); t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents)); - // LLVM was already built previously. - // We don't track changes in LLVM sources, so we need to choose between reusing - // what was built previously, or cleaning the directory and doing a fresh build. - // The choice depends on contents of the clean-trigger file. - // If the contents are the same as during the previous build, then no action is required. - // If the contents differ from the previous build, then cleaning is triggered. - if done_contents == clean_trigger_contents { + // If LLVM was already built previously and contents of the rebuild-trigger file + // didn't change from the previous build, then no action is required. + if done_contents == rebuild_trigger_contents { return - } else { - t!(fs::remove_dir_all(&out_dir)); } } + if build.config.llvm_clean_rebuild { + t!(fs::remove_dir_all(&out_dir)); + } println!("Building LLVM for {}", target); let _time = util::timeit(); @@ -148,7 +145,7 @@ pub fn llvm(build: &Build, target: &str) { // tools and libs on all platforms. cfg.build(); - t!(t!(File::create(&done_stamp)).write_all(clean_trigger_contents.as_bytes())); + t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes())); } fn check_llvm_version(build: &Build, llvm_config: &Path) { diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-rebuild-trigger similarity index 66% rename from src/rustllvm/llvm-auto-clean-trigger rename to src/rustllvm/llvm-rebuild-trigger index 57f37ea050c1b..e796e187c2117 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ -# If this file is modified, then llvm will be forcibly cleaned and then rebuilt. +# If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. 2017-03-02 From c4b92843c34d8eb2dab387976009f9ad78aebfd0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 16:22:08 +0300 Subject: [PATCH 57/73] Default llvm.clean-rebuild to false --- configure | 1 + src/bootstrap/config.rs | 2 +- src/bootstrap/config.toml.example | 8 +++----- src/ci/run.sh | 1 + 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/configure b/configure index be8628de62832..0737c3dbd1cac 100755 --- a/configure +++ b/configure @@ -638,6 +638,7 @@ opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt llvm-link-shared 0 "prefer shared linking to LLVM (llvm-config --link-shared)" +opt llvm-clean-rebuild 0 "delete LLVM build directory on rebuild" opt rpath 1 "build rpaths into rustc itself" opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0" # This is used by the automation to produce single-target nightlies diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 0b36166cc794c..75176d8cccd79 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -241,7 +241,6 @@ impl Config { pub fn parse(build: &str, file: Option) -> Config { let mut config = Config::default(); config.llvm_optimize = true; - config.llvm_clean_rebuild = true; config.use_jemalloc = true; config.backtrace = true; config.rust_optimize = true; @@ -440,6 +439,7 @@ impl Config { ("LLVM_VERSION_CHECK", self.llvm_version_check), ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp), ("LLVM_LINK_SHARED", self.llvm_link_shared), + ("LLVM_CLEAN_REBUILD", self.llvm_clean_rebuild), ("OPTIMIZE", self.rust_optimize), ("DEBUG_ASSERTIONS", self.rust_debug_assertions), ("DEBUGINFO", self.rust_debuginfo), diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index f13ba076d2bdf..bca640e061e72 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -54,11 +54,9 @@ #targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" # Delete LLVM build directory on LLVM rebuild. -# This option's default (`true`) is optimized for CI needs, and CI wants to -# perform clean full builds only (possibly accelerated by (s)ccache). -# You may want to override this option for local builds to enable partial LLVM -# rebuilds. -#clean-rebuild = true +# This option defaults to `false` for local development, but CI may want to +# always perform clean full builds (possibly accelerated by (s)ccache). +#clean-rebuild = false # ============================================================================= # General build configuration options diff --git a/src/ci/run.sh b/src/ci/run.sh index 4c4836d7ca230..19bea9ced0642 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -28,6 +28,7 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-openssl-static" +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-clean-rebuild" if [ "$DIST_SRC" = "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src" From 5c8aa74d26ba1dd4439d6d273ea32daa11f28851 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Mar 2017 15:15:55 -0800 Subject: [PATCH 58/73] rustc: Exit quickly on only `--emit dep-info` This commit alters the compiler to exit quickly if the only output being emitted is `dep-info`, which doesn't need a lot of other information to generate. Closes #40328 --- src/librustc_driver/driver.rs | 4 ++++ .../run-make/dep-info-doesnt-run-much/Makefile | 4 ++++ src/test/run-make/dep-info-doesnt-run-much/foo.rs | 15 +++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 src/test/run-make/dep-info-doesnt-run-much/Makefile create mode 100644 src/test/run-make/dep-info-doesnt-run-much/foo.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..82a8d88452673 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -125,6 +125,10 @@ pub fn compile_input(sess: &Session, }; write_out_deps(sess, &outputs, &crate_name); + if sess.opts.output_types.contains_key(&OutputType::DepInfo) && + sess.opts.output_types.keys().count() == 1 { + return Ok(()) + } let arena = DroplessArena::new(); let arenas = GlobalArenas::new(); diff --git a/src/test/run-make/dep-info-doesnt-run-much/Makefile b/src/test/run-make/dep-info-doesnt-run-much/Makefile new file mode 100644 index 0000000000000..2fd84639f2190 --- /dev/null +++ b/src/test/run-make/dep-info-doesnt-run-much/Makefile @@ -0,0 +1,4 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs --emit dep-info diff --git a/src/test/run-make/dep-info-doesnt-run-much/foo.rs b/src/test/run-make/dep-info-doesnt-run-much/foo.rs new file mode 100644 index 0000000000000..3591182104498 --- /dev/null +++ b/src/test/run-make/dep-info-doesnt-run-much/foo.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// We're only emitting dep info, so we shouldn't be running static analysis to +// figure out that this program is erroneous. +fn main() { + let a: u8 = "a"; +} From 880262a2bcd6b3756a6ebd8438a87e26b64c6927 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 02:50:13 +0300 Subject: [PATCH 59/73] Update syntax for `pub(restricted)` --- src/libsyntax/parse/parser.rs | 72 ++++++++++--------- .../auxiliary/pub_and_stability.rs | 8 +-- .../restricted/lookup-ignores-private.rs | 4 +- .../restricted/struct-literal-field.rs | 2 +- .../compile-fail/privacy/restricted/test.rs | 4 +- .../privacy/restricted/ty-params.rs | 7 +- .../compile-fail/resolve-bad-visibility.rs | 10 +-- .../resolve/auxiliary/privacy-struct-ctor.rs | 2 +- src/test/ui/resolve/privacy-struct-ctor.rs | 2 +- 9 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..12e3c2ff95b7d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4605,7 +4605,7 @@ impl<'a> Parser<'a> { let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let vis = self.parse_visibility()?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4936,7 +4936,7 @@ impl<'a> Parser<'a> { |p| { let attrs = p.parse_outer_attributes()?; let lo = p.span.lo; - let mut vis = p.parse_visibility(false)?; + let mut vis = p.parse_visibility()?; let ty_is_interpolated = p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); let mut ty = p.parse_ty()?; @@ -4993,38 +4993,46 @@ impl<'a> Parser<'a> { fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let vis = self.parse_visibility()?; self.parse_single_struct_field(lo, vis, attrs) } - // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`) - fn parse_visibility(&mut self, allow_path: bool) -> PResult<'a, Visibility> { - let pub_crate = |this: &mut Self| { - let span = this.prev_span; - this.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Crate(span)) - }; - + // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts + // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. + fn parse_visibility(&mut self) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { - Ok(Visibility::Inherited) - } else if !allow_path { - // Look ahead to avoid eating the `(` in `pub(path)` while still parsing `pub(crate)` - if self.token == token::OpenDelim(token::Paren) && - self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { - self.bump(); self.bump(); - pub_crate(self) - } else { - Ok(Visibility::Public) - } - } else if !self.eat(&token::OpenDelim(token::Paren)) { - Ok(Visibility::Public) - } else if self.eat_keyword(keywords::Crate) { - pub_crate(self) - } else { - let path = self.parse_path(PathStyle::Mod)?.default_to_global(); - self.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }) - } + return Ok(Visibility::Inherited) + } + + if self.check(&token::OpenDelim(token::Paren)) { + if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { + // `pub(crate)` + self.bump(); // `(` + self.bump(); // `crate` + let vis = Visibility::Crate(self.prev_span); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) { + // `pub(in path)` + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `path` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && + self.look_ahead(1, |t| t.is_keyword(keywords::Super) || + t.is_keyword(keywords::SelfValue)) { + // `pub(self)` or `pub(super)` + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } + } + + Ok(Visibility::Public) } /// Parse defaultness: DEFAULT or nothing @@ -5499,7 +5507,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility()?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5774,7 +5782,7 @@ impl<'a> Parser<'a> { fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility()?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM diff --git a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs index 9dc4cf1252ec3..6f458da9b527b 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs @@ -55,7 +55,7 @@ mod m { #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY pub(crate) b_crate: i32, #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY - pub(m) c_mod: i32, + pub(in m) c_mod: i32, #[stable(feature = "unit_test", since = "0.0.0")] // SILLY d_priv: i32 } @@ -71,7 +71,7 @@ mod m { pub i32, pub(crate) i32, - pub(m) i32, + pub(in m) i32, i32); impl Record { @@ -124,7 +124,7 @@ mod m { #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY pub(crate) fn pub_crate(&self) -> i32 { self.d_priv } #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY - pub(m) fn pub_mod(&self) -> i32 { self.d_priv } + pub(in m) fn pub_mod(&self) -> i32 { self.d_priv } #[stable(feature = "unit_test", since = "0.0.0")] // SILLY fn private(&self) -> i32 { self.d_priv } } @@ -138,7 +138,7 @@ mod m { pub fn stable(&self) -> i32 { self.0 } pub(crate) fn pub_crate(&self) -> i32 { self.0 } - pub(m) fn pub_mod(&self) -> i32 { self.0 } + pub(in m) fn pub_mod(&self) -> i32 { self.0 } fn private(&self) -> i32 { self.0 } } } diff --git a/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs b/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs index 4e2a69cb79e19..2d4b5545544c6 100644 --- a/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs +++ b/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs @@ -16,10 +16,10 @@ mod foo { mod bar { #[derive(Default)] pub struct S { - pub(foo) x: i32, + pub(in foo) x: i32, } impl S { - pub(foo) fn f(&self) -> i32 { 0 } + pub(in foo) fn f(&self) -> i32 { 0 } } pub struct S2 { diff --git a/src/test/compile-fail/privacy/restricted/struct-literal-field.rs b/src/test/compile-fail/privacy/restricted/struct-literal-field.rs index e254e005656c1..53786d45c73ee 100644 --- a/src/test/compile-fail/privacy/restricted/struct-literal-field.rs +++ b/src/test/compile-fail/privacy/restricted/struct-literal-field.rs @@ -15,7 +15,7 @@ mod foo { pub mod bar { pub struct S { - pub(foo) x: i32, + pub(in foo) x: i32, } } diff --git a/src/test/compile-fail/privacy/restricted/test.rs b/src/test/compile-fail/privacy/restricted/test.rs index 01e2c6cd7e828..d55ee8221cd73 100644 --- a/src/test/compile-fail/privacy/restricted/test.rs +++ b/src/test/compile-fail/privacy/restricted/test.rs @@ -57,6 +57,6 @@ fn main() { } mod pathological { - pub(bad::path) mod m1 {} //~ ERROR failed to resolve. Maybe a missing `extern crate bad;`? - pub(foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules + pub(in bad::path) mod m1 {} //~ ERROR failed to resolve. Maybe a missing `extern crate bad;`? + pub(in foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules } diff --git a/src/test/compile-fail/privacy/restricted/ty-params.rs b/src/test/compile-fail/privacy/restricted/ty-params.rs index da7086cf554c3..cd0edc8fe7c44 100644 --- a/src/test/compile-fail/privacy/restricted/ty-params.rs +++ b/src/test/compile-fail/privacy/restricted/ty-params.rs @@ -11,16 +11,11 @@ #![feature(pub_restricted)] macro_rules! m { - ($p: path) => (pub($p) struct Z;) + ($p: path) => (pub(in $p) struct Z;) } struct S(T); m!{ S } //~ ERROR type or lifetime parameters in visibility path //~^ ERROR expected module, found struct `S` -mod foo { - struct S(pub(foo) ()); //~ ERROR type or lifetime parameters in visibility path - //~^ ERROR cannot find type `T` in this scope -} - fn main() {} diff --git a/src/test/compile-fail/resolve-bad-visibility.rs b/src/test/compile-fail/resolve-bad-visibility.rs index 6b5cd4dce265a..20878a91ede99 100644 --- a/src/test/compile-fail/resolve-bad-visibility.rs +++ b/src/test/compile-fail/resolve-bad-visibility.rs @@ -13,11 +13,11 @@ enum E {} trait Tr {} -pub(E) struct S; //~ ERROR expected module, found enum `E` -pub(Tr) struct Z; //~ ERROR expected module, found trait `Tr` -pub(std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules -pub(nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root -pub(too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root +pub(in E) struct S; //~ ERROR expected module, found enum `E` +pub(in Tr) struct Z; //~ ERROR expected module, found trait `Tr` +pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules +pub(in nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root +pub(in too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root // Visibilities are resolved eagerly without waiting for modules becoming fully populated. // Visibilities can only use ancestor modules legally which are always available in time, diff --git a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs index f190f5dd0534d..383224b2f9273 100644 --- a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs @@ -14,7 +14,7 @@ pub mod m { pub struct S(u8); pub mod n { - pub(m) struct Z(pub(m::n) u8); + pub(in m) struct Z(pub(in m::n) u8); } } diff --git a/src/test/ui/resolve/privacy-struct-ctor.rs b/src/test/ui/resolve/privacy-struct-ctor.rs index 3d0c76c740ad6..68bd74719f55c 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/privacy-struct-ctor.rs @@ -18,7 +18,7 @@ mod m { pub struct S(u8); pub mod n { - pub(m) struct Z(pub(m::n) u8); + pub(in m) struct Z(pub(in m::n) u8); } use m::n::Z; // OK, only the type is imported From e5d1b9ca3927ea5cdfadd43c86a9f5d24671fb93 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Mar 2017 15:06:53 +1300 Subject: [PATCH 60/73] save-analysis: cope with lack of method data after a type error Fixes #39957 --- src/librustc_save_analysis/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b1e435dcc751c..4298024e12d7e 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -387,7 +387,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } None => { - span_bug!(span, "Could not find container for method {}", id); + debug!("Could not find container for method {} at {:?}", id, span); + // This is not necessarily a bug, if there was a compilation error, the tables + // we need might not exist. + return None; } }, }; From c9b63183abe51eed85fe297cb8f825791cc9a9d6 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 20:03:04 +0200 Subject: [PATCH 61/73] rustc_trans: don't emit ZST allocas that are only assigned to. --- src/librustc_trans/mir/analyze.rs | 3 +- src/librustc_trans/mir/mod.rs | 21 +++---------- src/librustc_trans/mir/operand.rs | 18 +++++++++++- src/librustc_trans/mir/rvalue.rs | 49 +++++++++++++++++-------------- 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 2c3b479c7dd0f..6f0f9cabef345 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -18,7 +18,6 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common; use super::MirContext; -use super::rvalue; pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector { let mir = mircx.mir; @@ -92,7 +91,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { if let mir::Lvalue::Local(index) = *lvalue { self.mark_assigned(index); - if !rvalue::rvalue_creates_operand(rvalue) { + if !self.cx.rvalue_creates_operand(rvalue) { self.mark_as_lvalue(index); } } else { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 6419f41f86b6d..eaedabc1f54c9 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,20 +11,18 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty::{self, layout}; +use rustc::ty::{self, layout, Ty, TypeFoldable}; use rustc::mir::{self, Mir}; use rustc::mir::tcx::LvalueTy; use rustc::ty::subst::Substs; use rustc::infer::TransNormalize; -use rustc::ty::TypeFoldable; use session::config::FullDebugInfo; use base; use builder::Builder; -use common::{self, CrateContext, C_null, Funclet}; +use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::{self, Instance}; use abi::FnType; -use type_of; use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span}; use syntax::symbol::keywords; @@ -176,23 +174,12 @@ enum LocalRef<'tcx> { impl<'tcx> LocalRef<'tcx> { fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>, - ty: ty::Ty<'tcx>) -> LocalRef<'tcx> { + ty: Ty<'tcx>) -> LocalRef<'tcx> { if common::type_is_zero_size(ccx, ty) { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - let llty = type_of::type_of(ccx, ty); - let val = if common::type_is_imm_pair(ccx, ty) { - let fields = llty.field_types(); - OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) - } else { - OperandValue::Immediate(C_null(llty)) - }; - let op = OperandRef { - val: val, - ty: ty - }; - LocalRef::Operand(Some(op)) + LocalRef::Operand(Some(OperandRef::new_zst(ccx, ty))) } else { LocalRef::Operand(None) } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index cb77fcbbff85d..df6667afd442e 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -15,7 +15,7 @@ use rustc::mir; use rustc_data_structures::indexed_vec::Idx; use base; -use common; +use common::{self, CrateContext, C_null}; use builder::Builder; use value::Value; use type_of; @@ -77,6 +77,22 @@ impl<'tcx> fmt::Debug for OperandRef<'tcx> { } impl<'a, 'tcx> OperandRef<'tcx> { + pub fn new_zst(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) -> OperandRef<'tcx> { + assert!(common::type_is_zero_size(ccx, ty)); + let llty = type_of::type_of(ccx, ty); + let val = if common::type_is_imm_pair(ccx, ty) { + let fields = llty.field_types(); + OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) + } else { + OperandValue::Immediate(C_null(llty)) + }; + OperandRef { + val: val, + ty: ty + } + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> ValueRef { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b6af4e52e820b..4328f2516970e 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -157,7 +157,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } _ => { - assert!(rvalue_creates_operand(rvalue)); + assert!(self.rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp); bcx @@ -170,7 +170,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { rvalue: &mir::Rvalue<'tcx>) -> (Builder<'a, 'tcx>, OperandRef<'tcx>) { - assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { @@ -478,8 +478,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - bug!("cannot generate operand from rvalue {:?}", rvalue); - + // According to `rvalue_creates_operand`, only ZST + // aggregate rvalues are allowed to be operands. + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + (bcx, OperandRef::new_zst(self.ccx, self.monomorphize(&ty))) } } } @@ -662,26 +664,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { OperandValue::Pair(val, of) } -} -pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { - match *rvalue { - mir::Rvalue::Ref(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::CheckedBinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | - mir::Rvalue::Box(..) | - mir::Rvalue::Use(..) => - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => - false, - } + pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { + match *rvalue { + mir::Rvalue::Ref(..) | + mir::Rvalue::Len(..) | + mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::BinaryOp(..) | + mir::Rvalue::CheckedBinaryOp(..) | + mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Discriminant(..) | + mir::Rvalue::Box(..) | + mir::Rvalue::Use(..) => + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) => { + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + let ty = self.monomorphize(&ty); + common::type_is_zero_size(self.ccx, ty) + } + } - // (*) this is only true if the type is suitable + // (*) this is only true if the type is suitable + } } #[derive(Copy, Clone)] From d8ca08406afb7cff7e4e5b746e10beb2eacfd3a7 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 20:08:09 +0200 Subject: [PATCH 62/73] rustc_trans: avoid a separate entry BB if START_BLOCK has no backedges. --- src/librustc_trans/mir/mod.rs | 17 ++++++----- src/test/codegen/naked-functions.rs | 47 +++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index eaedabc1f54c9..3bcb6e78dce9f 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -199,15 +199,17 @@ pub fn trans_mir<'a, 'tcx: 'a>( debug!("fn_ty: {:?}", fn_ty); let debug_context = debuginfo::create_function_debug_context(ccx, instance, sig, llfn, mir); - let bcx = Builder::new_block(ccx, llfn, "entry-block"); + let bcx = Builder::new_block(ccx, llfn, "start"); let cleanup_kinds = analyze::cleanup_kinds(&mir); - // Allocate a `Block` for every basic block + // Allocate a `Block` for every basic block, except + // the start block, if nothing loops back to it. + let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty(); let block_bcxs: IndexVec = mir.basic_blocks().indices().map(|bb| { - if bb == mir::START_BLOCK { - bcx.build_sibling_block("start").llbb() + if bb == mir::START_BLOCK && !reentrant_start_block { + bcx.llbb() } else { bcx.build_sibling_block(&format!("{:?}", bb)).llbb() } @@ -294,9 +296,10 @@ pub fn trans_mir<'a, 'tcx: 'a>( .collect() }; - // Branch to the START block - let start_bcx = mircx.blocks[mir::START_BLOCK]; - bcx.br(start_bcx); + // Branch to the START block, if it's not the entry block. + if reentrant_start_block { + bcx.br(mircx.blocks[mir::START_BLOCK]); + } // Up until here, IR instructions for this function have explicitly not been annotated with // source code location, so we don't step into call setup code. From here on, source location diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 9de74f72005e3..9883ca6b35d04 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -20,7 +20,8 @@ #[no_mangle] #[naked] fn naked_empty() { - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret void } // CHECK: Function Attrs: naked uwtable @@ -28,9 +29,10 @@ fn naked_empty() { #[naked] // CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}}) fn naked_with_args(a: isize) { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret void } // CHECK: Function Attrs: naked uwtable @@ -38,7 +40,8 @@ fn naked_with_args(a: isize) { #[no_mangle] #[naked] fn naked_with_return() -> isize { - // CHECK: ret i{{[0-9]+}} 0 + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret i{{[0-9]+}} 0 0 } @@ -47,9 +50,10 @@ fn naked_with_return() -> isize { #[no_mangle] #[naked] fn naked_with_args_and_return(a: isize) -> isize { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} a } @@ -58,14 +62,37 @@ fn naked_with_args_and_return(a: isize) -> isize { #[no_mangle] #[naked] fn naked_recursive() { - // CHECK: call void @naked_empty() + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: call void @naked_empty() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb1 + // CHECK: bb1: + naked_empty(); - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb2 + // CHECK: bb2: + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb3 + // CHECK: bb3: + + // CHECK-NEXT: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb4 + // CHECK: bb4: + naked_with_args( - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) naked_with_args_and_return( - // CHECK: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) naked_with_return() ) ); + // CHECK-NEXT: ret void } From 32575a0487a2086ca7b15a0ca2565efc60bdc0c3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 20:30:06 +0300 Subject: [PATCH 63/73] Give spans to individual path segments in AST --- src/librustc_resolve/lib.rs | 7 +++---- src/librustc_resolve/macros.rs | 5 ++++- src/libsyntax/ast.rs | 14 +++++++------- src/libsyntax/ext/build.rs | 19 ++++++++++++------- src/libsyntax/fold.rs | 3 ++- src/libsyntax/parse/mod.rs | 18 +++++++++++------- src/libsyntax/parse/parser.rs | 29 ++++++++++++++++++----------- src/libsyntax/std_inject.rs | 2 +- src/libsyntax/test.rs | 2 +- src/libsyntax_ext/concat_idents.rs | 2 +- 10 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d51ec268ec217..105af23d05c05 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3124,11 +3124,10 @@ impl<'a> Resolver<'a> { if ident.name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path - let span = name_binding.span; let mut segms = path_segments.clone(); - segms.push(ident.into()); + segms.push(ast::PathSegment::from_ident(ident, name_binding.span)); let path = Path { - span: span, + span: name_binding.span, segments: segms, }; // the entity is accessible in the following cases: @@ -3148,7 +3147,7 @@ impl<'a> Resolver<'a> { if let Some(module) = name_binding.module() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ident.into()); + path_segments.push(ast::PathSegment::from_ident(ident, name_binding.span)); if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { // add the module to the lookup diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 720d616e007d2..d81bdf17034e6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -110,8 +110,11 @@ impl<'a> base::Resolver for Resolver<'a> { path.segments[0].identifier.name = keywords::CrateRoot.name(); let module = self.0.resolve_crate_var(ident.ctxt); if !module.is_local() { + let span = path.segments[0].span; path.segments.insert(1, match module.kind { - ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name).into(), + ModuleKind::Def(_, name) => ast::PathSegment::from_ident( + ast::Ident::with_empty_ctxt(name), span + ), _ => unreachable!(), }) } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9cc754cbf4d19..adb7e8d101fd1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -134,7 +134,7 @@ impl Path { pub fn from_ident(s: Span, identifier: Ident) -> Path { Path { span: s, - segments: vec![identifier.into()], + segments: vec![PathSegment::from_ident(identifier, s)], } } @@ -159,6 +159,8 @@ impl Path { pub struct PathSegment { /// The identifier portion of this path segment. pub identifier: Ident, + /// Span of the segment identifier. + pub span: Span, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that @@ -170,16 +172,14 @@ pub struct PathSegment { pub parameters: Option>, } -impl From for PathSegment { - fn from(id: Ident) -> Self { - PathSegment { identifier: id, parameters: None } - } -} - impl PathSegment { + pub fn from_ident(ident: Ident, span: Span) -> Self { + PathSegment { identifier: ident, span: span, parameters: None } + } pub fn crate_root() -> Self { PathSegment { identifier: keywords::CrateRoot.ident(), + span: DUMMY_SP, parameters: None, } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index f8d4eff80b2d1..e0fb46ff5eb09 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -38,11 +38,11 @@ pub trait AstBuilder { fn qpath(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident) + ident: ast::SpannedIdent) -> (ast::QSelf, ast::Path); fn qpath_all(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident, + ident: ast::SpannedIdent, lifetimes: Vec, types: Vec>, bindings: Vec) @@ -323,7 +323,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { segments.push(ast::PathSegment::crate_root()); } - segments.extend(idents.into_iter().map(Into::into)); + segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, sp))); let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() { None } else { @@ -333,7 +333,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: bindings, }))) }; - segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters }); + segments.push(ast::PathSegment { + identifier: last_identifier, + span: sp, + parameters: parameters + }); ast::Path { span: sp, segments: segments, @@ -346,7 +350,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn qpath(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident) + ident: ast::SpannedIdent) -> (ast::QSelf, ast::Path) { self.qpath_all(self_type, trait_path, ident, vec![], vec![], vec![]) } @@ -357,7 +361,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn qpath_all(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident, + ident: ast::SpannedIdent, lifetimes: Vec, types: Vec>, bindings: Vec) @@ -369,7 +373,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: bindings, }; path.segments.push(ast::PathSegment { - identifier: ident, + identifier: ident.node, + span: ident.span, parameters: Some(P(ast::PathParameters::AngleBracketed(parameters))), }); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4242b0f8b9803..665f48ab45679 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -434,8 +434,9 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { pub fn noop_fold_path(Path { segments, span }: Path, fld: &mut T) -> Path { Path { - segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { + segments: segments.move_map(|PathSegment {identifier, span, parameters}| PathSegment { identifier: fld.fold_ident(identifier), + span: fld.new_span(span), parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))), }), span: fld.new_span(span) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c00d2952b3b42..88535f91379f7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -617,13 +617,17 @@ mod tests { Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION} } + fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment { + ast::PathSegment::from_ident(Ident::from_str(s), sp(lo, hi)) + } + #[test] fn path_exprs_1() { assert!(string_to_expr("a".to_string()) == P(ast::Expr{ id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), - segments: vec![Ident::from_str("a").into()], + segments: vec![str2seg("a", 0, 1)], }), span: sp(0, 1), attrs: ThinVec::new(), @@ -637,8 +641,8 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), segments: vec![ast::PathSegment::crate_root(), - Ident::from_str("a").into(), - Ident::from_str("b").into()] + str2seg("a", 2, 3), + str2seg("b", 5, 6)] }), span: sp(0, 6), attrs: ThinVec::new(), @@ -744,7 +748,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), - segments: vec![Ident::from_str("d").into()], + segments: vec![str2seg("d", 7, 8)], }), span:sp(7,8), attrs: ThinVec::new(), @@ -761,7 +765,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 0, 1)], }), span: sp(0,1), attrs: ThinVec::new()})), @@ -802,7 +806,7 @@ mod tests { ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), - segments: vec![Ident::from_str("i32").into()], + segments: vec![str2seg("i32", 10, 13)], }), span:sp(10,13) }), @@ -844,7 +848,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 17, 18)], }), span: sp(17,18), attrs: ThinVec::new()})), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..002f1359b6fa5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,7 +27,7 @@ use ast::Local; use ast::MacStmtStyle; use ast::Mac_; use ast::{MutTy, Mutability}; -use ast::{Pat, PatKind}; +use ast::{Pat, PatKind, PathSegment}; use ast::{PolyTraitRef, QSelf}; use ast::{Stmt, StmtKind}; use ast::{VariantData, StructField}; @@ -1811,7 +1811,7 @@ impl<'a> Parser<'a> { }; if is_global { - segments.insert(0, ast::PathSegment::crate_root()); + segments.insert(0, PathSegment::crate_root()); } // Assemble the span. @@ -1829,11 +1829,12 @@ impl<'a> Parser<'a> { /// - `a::b::c` /// - `a::b::c(V) -> W` /// - `a::b::c(V)` - pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + let ident_span = self.prev_span; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { self.bump(); @@ -1881,7 +1882,11 @@ impl<'a> Parser<'a> { }; // Assemble and push the result. - segments.push(ast::PathSegment { identifier: identifier, parameters: parameters }); + segments.push(PathSegment { + identifier: identifier, + span: ident_span, + parameters: parameters + }); // Continue only if we see a `::` if !self.eat(&token::ModSep) { @@ -1892,15 +1897,16 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::::c` - pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + let ident_span = self.prev_span; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); return Ok(segments); } @@ -1909,8 +1915,9 @@ impl<'a> Parser<'a> { // Consumed `a::b::<`, go look for types let (lifetimes, types, bindings) = self.parse_generic_args()?; self.expect_gt()?; - segments.push(ast::PathSegment { + segments.push(PathSegment { identifier: identifier, + span: ident_span, parameters: ast::AngleBracketedParameterData { lifetimes: lifetimes, types: types, @@ -1924,7 +1931,7 @@ impl<'a> Parser<'a> { } } else { // Consumed `a::`, go look for `b` - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); } } } @@ -1932,14 +1939,14 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::c` pub fn parse_path_segments_without_types(&mut self) - -> PResult<'a, Vec> { + -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, self.prev_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -5902,7 +5909,7 @@ impl<'a> Parser<'a> { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { - segments: vec![ast::PathSegment::crate_root()], + segments: vec![PathSegment::crate_root()], span: mk_sp(lo, self.span.hi), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 4a2dfaf61247c..2192d203cdc23 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -82,7 +82,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, vis: ast::Visibility::Inherited, node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path { segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| { - ast::Ident::from_str(name).into() + ast::PathSegment::from_ident(ast::Ident::from_str(name), DUMMY_SP) }).collect(), span: span, })))), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index dd2756cd2b22c..e052d2cda3a42 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -580,7 +580,7 @@ fn nospan(t: T) -> codemap::Spanned { fn path_node(ids: Vec) -> ast::Path { ast::Path { span: DUMMY_SP, - segments: ids.into_iter().map(Into::into).collect(), + segments: ids.into_iter().map(|id| ast::PathSegment::from_ident(id, DUMMY_SP)).collect(), } } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 1fc1bdff593c2..dc4b8eb24cd0a 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -61,7 +61,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, fn path(&self) -> ast::Path { ast::Path { span: self.span, - segments: vec![self.ident.into()], + segments: vec![ast::PathSegment::from_ident(self.ident, self.span)], } } } From ffdcf7486656119328c3c6c1efef408abba3139f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 22:15:12 +0300 Subject: [PATCH 64/73] resolve: Use path segment spans in smart_resolve_path --- src/librustc_resolve/lib.rs | 50 +++++++++---------- src/librustc_resolve/macros.rs | 1 - .../ui/resolve/enums-are-namespaced-xc.stderr | 12 ++--- src/test/ui/resolve/levenshtein.stderr | 10 ++-- ...uggest-path-instead-of-mod-dot-item.stderr | 36 +++++++++---- ...xed-closure-sugar-nonexistent-trait.stderr | 2 +- 6 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 105af23d05c05..99061747832ec 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -407,7 +407,7 @@ enum PathSource<'a> { // Trait paths in bounds or impls. Trait, // Expression paths `path`, with optional parent context. - Expr(Option<&'a ExprKind>), + Expr(Option<&'a Expr>), // Paths in path patterns `Path`. Pat, // Paths in struct expressions and patterns `Path { .. }`. @@ -464,7 +464,7 @@ impl<'a> PathSource<'a> { ValueNS => "method or associated constant", MacroNS => bug!("associated macro"), }, - PathSource::Expr(parent) => match parent { + PathSource::Expr(parent) => match parent.map(|p| &p.node) { // "function" here means "anything callable" rather than `Def::Fn`, // this is not precise but usually more helpful than just "value". Some(&ExprKind::Call(..)) => "function", @@ -2194,7 +2194,8 @@ impl<'a> Resolver<'a> { source: PathSource) -> PathResolution { let segments = &path.segments.iter().map(|seg| seg.identifier).collect::>(); - self.smart_resolve_path_fragment(id, qself, segments, path.span, source) + let ident_span = path.segments.last().map_or(path.span, |seg| seg.span); + self.smart_resolve_path_fragment(id, qself, segments, path.span, ident_span, source) } fn smart_resolve_path_fragment(&mut self, @@ -2202,6 +2203,7 @@ impl<'a> Resolver<'a> { qself: Option<&QSelf>, path: &[Ident], span: Span, + ident_span: Span, source: PathSource) -> PathResolution { let ns = source.namespace(); @@ -2213,9 +2215,9 @@ impl<'a> Resolver<'a> { let expected = source.descr_expected(); let path_str = names_to_string(path); let code = source.error_code(def.is_some()); - let (base_msg, fallback_label) = if let Some(def) = def { + let (base_msg, fallback_label, base_span) = if let Some(def) = def { (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), - format!("not a {}", expected)) + format!("not a {}", expected), span) } else { let item_str = path[path.len() - 1]; let (mod_prefix, mod_str) = if path.len() == 1 { @@ -2231,9 +2233,9 @@ impl<'a> Resolver<'a> { (mod_prefix, format!("`{}`", names_to_string(mod_path))) }; (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str)) + format!("not found in {}", mod_str), ident_span) }; - let mut err = this.session.struct_span_err_with_code(span, &base_msg, code); + let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code); // Emit special messages for unresolved `Self` and `self`. if is_self_type(path, ns) { @@ -2291,15 +2293,15 @@ impl<'a> Resolver<'a> { err.span_label(span, &format!("type aliases cannot be used for traits")); return err; } - (Def::Mod(..), PathSource::Expr(Some(parent))) => match *parent { + (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node { ExprKind::Field(_, ident) => { - err.span_label(span, &format!("did you mean `{}::{}`?", - path_str, ident.node)); + err.span_label(parent.span, &format!("did you mean `{}::{}`?", + path_str, ident.node)); return err; } ExprKind::MethodCall(ident, ..) => { - err.span_label(span, &format!("did you mean `{}::{}(...)`?", - path_str, ident.node)); + err.span_label(parent.span, &format!("did you mean `{}::{}(...)`?", + path_str, ident.node)); return err; } _ => {} @@ -2324,12 +2326,12 @@ impl<'a> Resolver<'a> { // Try Levenshtein if nothing else worked. if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) { - err.span_label(span, &format!("did you mean `{}`?", candidate)); + err.span_label(ident_span, &format!("did you mean `{}`?", candidate)); return err; } // Fallback label. - err.span_label(span, &fallback_label); + err.span_label(base_span, &fallback_label); err }; let report_errors = |this: &mut Self, def: Option| { @@ -2449,7 +2451,7 @@ impl<'a> Resolver<'a> { // Make sure `A::B` in `::B::C` is a trait item. let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; let res = self.smart_resolve_path_fragment(id, None, &path[..qself.position + 1], - span, PathSource::TraitItem(ns)); + span, span, PathSource::TraitItem(ns)); return Some(PathResolution::with_unresolved_segments( res.base_def(), res.unresolved_segments() + path.len() - qself.position - 1 )); @@ -2807,7 +2809,7 @@ impl<'a> Resolver<'a> { path: &[Ident], ns: Namespace, filter_fn: FilterFn) - -> Option + -> Option where FilterFn: Fn(Def) -> bool { let add_module_candidates = |module: Module, names: &mut Vec| { @@ -2821,7 +2823,7 @@ impl<'a> Resolver<'a> { }; let mut names = Vec::new(); - let prefix_str = if path.len() == 1 { + if path.len() == 1 { // Search in lexical scope. // Walk backwards up the ribs in scope and collect candidates. for rib in self.ribs[ns].iter().rev() { @@ -2855,21 +2857,19 @@ impl<'a> Resolver<'a> { names.push(*name); } } - String::new() } else { // Search in module. let mod_path = &path[..path.len() - 1]; if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), None) { add_module_candidates(module, &mut names); } - names_to_string(mod_path) + "::" - }; + } let name = path[path.len() - 1].name; // Make sure error reporting is deterministic. names.sort_by_key(|name| name.as_str()); match find_best_match_for_name(names.iter(), &name.as_str(), None) { - Some(found) if found != name => Some(format!("{}{}", prefix_str, found)), + Some(found) if found != name => Some(found), _ => None, } } @@ -2892,7 +2892,7 @@ impl<'a> Resolver<'a> { self.with_resolved_label(label, id, |this| this.visit_block(block)); } - fn resolve_expr(&mut self, expr: &Expr, parent: Option<&ExprKind>) { + fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) { // First, record candidate traits for this expression if it could // result in the invocation of a method call. @@ -2973,11 +2973,11 @@ impl<'a> Resolver<'a> { // Equivalent to `visit::walk_expr` + passing some context to children. ExprKind::Field(ref subexpression, _) => { - self.resolve_expr(subexpression, Some(&expr.node)); + self.resolve_expr(subexpression, Some(expr)); } ExprKind::MethodCall(_, ref types, ref arguments) => { let mut arguments = arguments.iter(); - self.resolve_expr(arguments.next().unwrap(), Some(&expr.node)); + self.resolve_expr(arguments.next().unwrap(), Some(expr)); for argument in arguments { self.resolve_expr(argument, None); } @@ -2993,7 +2993,7 @@ impl<'a> Resolver<'a> { }); } ExprKind::Call(ref callee, ref arguments) => { - self.resolve_expr(callee, Some(&expr.node)); + self.resolve_expr(callee, Some(expr)); for argument in arguments { self.resolve_expr(argument, None); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index d81bdf17034e6..9d4779a06baf6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -502,7 +502,6 @@ impl<'a> Resolver<'a> { }; let ident = Ident::from_str(name); self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro) - .as_ref().map(|s| Symbol::intern(s)) }); if let Some(suggestion) = suggestion { diff --git a/src/test/ui/resolve/enums-are-namespaced-xc.stderr b/src/test/ui/resolve/enums-are-namespaced-xc.stderr index d541aa599a48b..dd04c5ce356c6 100644 --- a/src/test/ui/resolve/enums-are-namespaced-xc.stderr +++ b/src/test/ui/resolve/enums-are-namespaced-xc.stderr @@ -1,26 +1,26 @@ error[E0425]: cannot find value `A` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:15:13 + --> $DIR/enums-are-namespaced-xc.rs:15:31 | 15 | let _ = namespaced_enums::A; - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::A;` error[E0425]: cannot find function `B` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:18:13 + --> $DIR/enums-are-namespaced-xc.rs:18:31 | 18 | let _ = namespaced_enums::B(10); - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::B;` error[E0422]: cannot find struct, variant or union type `C` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:21:13 + --> $DIR/enums-are-namespaced-xc.rs:21:31 | 21 | let _ = namespaced_enums::C { a: 10 }; - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::C;` diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr index c7c42bcf23940..4dff2620319e4 100644 --- a/src/test/ui/resolve/levenshtein.stderr +++ b/src/test/ui/resolve/levenshtein.stderr @@ -14,7 +14,7 @@ error[E0412]: cannot find type `Opiton` in this scope --> $DIR/levenshtein.rs:20:10 | 20 | type B = Opiton; // Misspelled type name from the prelude. - | ^^^^^^^^^^ did you mean `Option`? + | ^^^^^^ did you mean `Option`? error[E0412]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:23:14 @@ -35,16 +35,16 @@ error[E0425]: cannot find function `foobar` in this scope | ^^^^^^ did you mean `foo_bar`? error[E0412]: cannot find type `first` in module `m` - --> $DIR/levenshtein.rs:32:12 + --> $DIR/levenshtein.rs:32:15 | 32 | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^^^ did you mean `m::First`? + | ^^^^^ did you mean `First`? error[E0425]: cannot find value `second` in module `m` - --> $DIR/levenshtein.rs:32:23 + --> $DIR/levenshtein.rs:32:26 | 32 | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^^^^ did you mean `m::Second`? + | ^^^^^^ did you mean `Second`? error: aborting due to 8 previous errors diff --git a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr index 57c0ecc813505..85fb1777dea23 100644 --- a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr +++ b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr @@ -2,55 +2,73 @@ error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:27:5 | 27 | a.I - | ^ did you mean `a::I`? + | ^-- + | | + | did you mean `a::I`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:33:5 | 33 | a.g() - | ^ did you mean `a::g(...)`? + | ^---- + | | + | did you mean `a::g(...)`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:39:5 | 39 | a.b.J - | ^ did you mean `a::b`? + | ^-- + | | + | did you mean `a::b`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:45:5 | 45 | a::b.J - | ^^^^ did you mean `a::b::J`? + | ^^^^-- + | | + | did you mean `a::b::J`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:51:5 | 51 | a.b.f(); - | ^ did you mean `a::b`? + | ^-- + | | + | did you mean `a::b`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:55:12 | 55 | v.push(a::b); - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:61:5 | 61 | a::b.f() - | ^^^^ did you mean `a::b::f(...)`? + | ^^^^---- + | | + | did you mean `a::b::f(...)`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:67:5 | 67 | a::b - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error[E0423]: expected function, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:73:5 | 73 | a::b() - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error: main function not found diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr index f0d363f7335f7..015dbfc3dc775 100644 --- a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr +++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr @@ -2,7 +2,7 @@ error[E0405]: cannot find trait `Nonexist` in this scope --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:11:8 | 11 | fn f isize>(x: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^ not found in this scope error[E0404]: expected trait, found type alias `Typedef` --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:17:8 From b959d13648f9f5bed6edb62f5f175d10aba6555b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Mar 2017 12:51:09 +0100 Subject: [PATCH 65/73] Allow lints to check Bodys directly --- src/librustc/lint/context.rs | 6 ++++++ src/librustc/lint/mod.rs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 32bc81e947037..9279f24a57ab3 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -806,6 +806,12 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { self.tables = old_tables; } + fn visit_body(&mut self, body: &'tcx hir::Body) { + run_lints!(self, check_body, late_passes, body); + hir_visit::walk_body(self, body); + run_lints!(self, check_body_post, late_passes, body); + } + fn visit_item(&mut self, it: &'tcx hir::Item) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_item, late_passes, it); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e9f603db15d62..e81d09773701c 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -133,6 +133,8 @@ pub trait LintPass { // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. pub trait LateLintPass<'a, 'tcx>: LintPass { + fn check_body(&mut self, _: &LateContext, _: &'tcx hir::Body) { } + fn check_body_post(&mut self, _: &LateContext, _: &'tcx hir::Body) { } fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } From 9a8461104e1520c7194f8b4589262c9e292c6988 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Thu, 16 Feb 2017 20:54:24 -0800 Subject: [PATCH 66/73] travis: Fuchsia builder This change introduces a Dockerfile and script which builds a complete Fuchsia toolchain which can be used to build Rust distribution for Fuchsia. We only support cross-compiling at the moment, hence only setting the target. --- .travis.yml | 1 + src/ci/docker/dist-fuchsia/Dockerfile | 47 +++++++ src/ci/docker/dist-fuchsia/build-toolchain.sh | 116 ++++++++++++++++++ src/ci/docker/dist-fuchsia/shared.sh | 25 ++++ src/libstd/sys_common/gnu/libbacktrace.rs | 3 - src/tools/build-manifest/src/main.rs | 2 + 6 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 src/ci/docker/dist-fuchsia/Dockerfile create mode 100755 src/ci/docker/dist-fuchsia/build-toolchain.sh create mode 100644 src/ci/docker/dist-fuchsia/shared.sh diff --git a/.travis.yml b/.travis.yml index fa6c9cf074864..7fcf128ff0b03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ matrix: - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1 - env: IMAGE=dist-freebsd DEPLOY=1 - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-fuchsia DEPLOY=1 - env: IMAGE=dist-mips-linux DEPLOY=1 - env: IMAGE=dist-mips64-linux DEPLOY=1 - env: IMAGE=dist-powerpc-linux DEPLOY=1 diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile new file mode 100644 index 0000000000000..25a47c5be1cb3 --- /dev/null +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -0,0 +1,47 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python2.7-dev \ + git \ + sudo \ + bzip2 \ + xz-utils \ + swig \ + libedit-dev \ + libncurses5-dev + +RUN curl -L https://cmake.org/files/v3.8/cmake-3.8.0-rc1-Linux-x86_64.tar.gz | \ + tar xzf - -C /usr/local --strip-components=1 + +WORKDIR /tmp +COPY shared.sh build-toolchain.sh /tmp/ +RUN /tmp/build-toolchain.sh + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \ + CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \ + CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \ + AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \ + CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \ + CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ + +ENV TARGETS=x86_64-unknown-fuchsia +ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia + +ENV RUST_CONFIGURE_ARGS --target=$TARGETS +ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-fuchsia/build-toolchain.sh b/src/ci/docker/dist-fuchsia/build-toolchain.sh new file mode 100755 index 0000000000000..cad73eee1e013 --- /dev/null +++ b/src/ci/docker/dist-fuchsia/build-toolchain.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +# Download sources +SRCS=( + "https://fuchsia.googlesource.com/magenta magenta ac69119" + "https://fuchsia.googlesource.com/third_party/llvm llvm 5463083" + "https://fuchsia.googlesource.com/third_party/clang llvm/tools/clang 4ff7b4b" + "https://fuchsia.googlesource.com/third_party/lld llvm/tools/lld fd465a3" + "https://fuchsia.googlesource.com/third_party/lldb llvm/tools/lldb 6bb11f8" + "https://fuchsia.googlesource.com/third_party/compiler-rt llvm/runtimes/compiler-rt 52d4ecc" + "https://fuchsia.googlesource.com/third_party/libcxx llvm/runtimes/libcxx e891cc8" + "https://fuchsia.googlesource.com/third_party/libcxxabi llvm/runtimes/libcxxabi f0f0257" + "https://fuchsia.googlesource.com/third_party/libunwind llvm/runtimes/libunwind 50bddc1" +) + +fetch() { + mkdir -p $2 + pushd $2 > /dev/null + curl -sL $1/+archive/$3.tar.gz | tar xzf - + popd > /dev/null +} + +for i in "${SRCS[@]}"; do + fetch $i +done + +# Build toolchain +cd llvm +mkdir build +cd build +hide_output cmake -GNinja \ + -DFUCHSIA_SYSROOT=${PWD}/../../magenta/third_party/ulib/musl \ + -DLLVM_ENABLE_LTO=OFF \ + -DCLANG_BOOTSTRAP_PASSTHROUGH=LLVM_ENABLE_LTO \ + -C ../tools/clang/cmake/caches/Fuchsia.cmake \ + .. +hide_output ninja stage2-distribution +hide_output ninja stage2-install-distribution +cd ../.. + +# Build sysroot +rm -rf llvm/runtimes/compiler-rt +./magenta/scripts/download-toolchain + +build_sysroot() { + local arch="$1" + + case "${arch}" in + x86_64) tgt="magenta-pc-x86-64" ;; + aarch64) tgt="magenta-qemu-arm64" ;; + esac + + hide_output make -C magenta -j$(getconf _NPROCESSORS_ONLN) $tgt + dst=/usr/local/${arch}-unknown-fuchsia + mkdir -p $dst + cp -r magenta/build-${tgt}/sysroot/include $dst/ + cp -r magenta/build-${tgt}/sysroot/lib $dst/ + + cd llvm + mkdir build-runtimes-${arch} + cd build-runtimes-${arch} + hide_output cmake -GNinja \ + -DCMAKE_C_COMPILER=clang \ + -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_AR=/usr/local/bin/llvm-ar \ + -DCMAKE_RANLIB=/usr/local/bin/llvm-ranlib \ + -DCMAKE_INSTALL_PREFIX= \ + -DLLVM_MAIN_SRC_DIR=${PWD}/.. \ + -DLLVM_BINARY_DIR=${PWD}/../build \ + -DLLVM_ENABLE_WERROR=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_INCLUDE_TESTS=ON \ + -DCMAKE_SYSTEM_NAME=Fuchsia \ + -DCMAKE_C_COMPILER_TARGET=${arch}-fuchsia \ + -DCMAKE_CXX_COMPILER_TARGET=${arch}-fuchsia \ + -DUNIX=1 \ + -DLIBCXX_HAS_MUSL_LIBC=ON \ + -DLIBCXXABI_USE_LLVM_UNWINDER=ON \ + -DCMAKE_SYSROOT=${dst} \ + -DCMAKE_C_COMPILER_FORCED=TRUE \ + -DCMAKE_CXX_COMPILER_FORCED=TRUE \ + -DLLVM_ENABLE_LIBCXX=ON \ + -DCMAKE_EXE_LINKER_FLAGS="-nodefaultlibs -lc" \ + -DCMAKE_SHARED_LINKER_FLAGS="$(clang --target=${arch}-fuchsia -print-libgcc-file-name)" \ + ../runtimes + hide_output env DESTDIR="${dst}" ninja install + cd ../.. +} + +build_sysroot "x86_64" +build_sysroot "aarch64" + +rm -rf magenta llvm + +for arch in x86_64 aarch64; do + for tool in clang clang++; do + cat >/usr/local/bin/${arch}-unknown-fuchsia-${tool} < or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + "$@" &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs index 1ea5cca44c7e4..14c0e8699bc06 100644 --- a/src/libstd/sys_common/gnu/libbacktrace.rs +++ b/src/libstd/sys_common/gnu/libbacktrace.rs @@ -105,9 +105,6 @@ extern "C" fn(data: *mut libc::c_void, msg: *const libc::c_char, errnum: libc::c_int); enum backtrace_state {} -#[link(name = "backtrace", kind = "static")] -#[cfg(all(not(test), not(cargobuild)))] -extern {} extern { fn backtrace_create_state(filename: *const libc::c_char, diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index ceefcc9e0ec46..9449fac2197df 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -45,6 +45,7 @@ static HOSTS: &'static [&'static str] = &[ static TARGETS: &'static [&'static str] = &[ "aarch64-apple-ios", + "aarch64-unknown-fuchsia", "aarch64-linux-android", "aarch64-unknown-linux-gnu", "arm-linux-androideabi", @@ -86,6 +87,7 @@ static TARGETS: &'static [&'static str] = &[ "x86_64-pc-windows-msvc", "x86_64-rumprun-netbsd", "x86_64-unknown-freebsd", + "x86_64-unknown-fuchsia", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-unknown-netbsd", From 993eae1816525e5cf855e448363098edd5935276 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 10 Mar 2017 09:04:27 -0800 Subject: [PATCH 67/73] rustc: Support auto-retry linking on a segfault This is a last-ditch attempt to help our pain with dealing with #38878 on the bots. A new environment variable is added to the compiler, `RUSTC_RETRY_LINKER_ON_SEGFAULT`, which will instruct the compiler to automatically retry the final linker invocation if it looks like the linker segfaulted (up to 2 extra times). Unfortunately there have been no successful attempts to debug #38878. The only information seems to be that the linker (e.g. `ld` on OSX) is segfaulting somewhere in some thread pool implementation. This appears to be spurious as failed PRs will later merge. The hope is that this helps the queue keep moving without clogging and delaying PRs due to #38878. --- .travis.yml | 5 ++++ src/librustc_trans/back/link.rs | 48 ++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fa6c9cf074864..42684d70d36a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,7 @@ matrix: RUST_CHECK_TARGET=check RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin SRC=. + RUSTC_RETRY_LINKER_ON_SEGFAULT=1 os: osx osx_image: xcode8.2 install: &osx_install_sccache > @@ -53,6 +54,7 @@ matrix: RUST_CHECK_TARGET=check RUST_CONFIGURE_ARGS=--build=i686-apple-darwin SRC=. + RUSTC_RETRY_LINKER_ON_SEGFAULT=1 os: osx osx_image: xcode8.2 install: *osx_install_sccache @@ -62,6 +64,7 @@ matrix: RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended" SRC=. DEPLOY=1 + RUSTC_RETRY_LINKER_ON_SEGFAULT=1 os: osx osx_image: xcode8.2 install: > @@ -74,6 +77,7 @@ matrix: RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended" SRC=. DEPLOY=1 + RUSTC_RETRY_LINKER_ON_SEGFAULT=1 os: osx osx_image: xcode8.2 install: *osx_install_sccache @@ -88,6 +92,7 @@ matrix: RUST_CONFIGURE_ARGS="--enable-extended" SRC=. DEPLOY_ALT=1 + RUSTC_RETRY_LINKER_ON_SEGFAULT=1 os: osx osx_image: xcode8.2 install: *osx_install_sccache diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b58f96033bf5b..a1703b1c155eb 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -752,8 +752,54 @@ fn link_natively(sess: &Session, sess.abort_if_errors(); // Invoke the system linker + // + // Note that there's a terribly awful hack that really shouldn't be present + // in any compiler. Here an environment variable is supported to + // automatically retry the linker invocation if the linker looks like it + // segfaulted. + // + // Gee that seems odd, normally segfaults are things we want to know about! + // Unfortunately though in rust-lang/rust#38878 we're experiencing the + // linker segfaulting on Travis quite a bit which is causing quite a bit of + // pain to land PRs when they spuriously fail due to a segfault. + // + // The issue #38878 has some more debugging information on it as well, but + // this unfortunately looks like it's just a race condition in OSX's linker + // with some thread pool working in the background. It seems that no one + // currently knows a fix for this so in the meantime we're left with this... info!("{:?}", &cmd); - let prog = time(sess.time_passes(), "running linker", || cmd.output()); + let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); + let mut prog; + let mut i = 0; + loop { + i += 1; + prog = time(sess.time_passes(), "running linker", || cmd.output()); + if !retry_on_segfault || i > 3 { + break + } + let output = match prog { + Ok(ref output) => output, + Err(_) => break, + }; + if output.status.success() { + break + } + let mut out = output.stderr.clone(); + out.extend(&output.stdout); + let out = String::from_utf8_lossy(&out); + let msg = "clang: error: unable to execute command: \ + Segmentation fault: 11"; + if !out.contains(msg) { + break + } + + sess.struct_warn("looks like the linker segfaulted when we tried to \ + call it, automatically retrying again") + .note(&format!("{:?}", cmd)) + .note(&out) + .emit(); + } + match prog { Ok(prog) => { fn escape_string(s: &[u8]) -> String { From 83814fd8ab30e2744d2fb17bdcf5b59840673863 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Fri, 10 Mar 2017 00:23:54 -0500 Subject: [PATCH 68/73] OsString::shrink_to_fit. --- src/libstd/ffi/os_str.rs | 6 ++++++ src/libstd/sys/redox/os_str.rs | 5 +++++ src/libstd/sys/unix/os_str.rs | 5 +++++ src/libstd/sys/windows/os_str.rs | 4 ++++ src/libstd/sys_common/wtf8.rs | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 7b8bf42e0a74a..41bdd9c51d458 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -205,6 +205,12 @@ impl OsString { self.inner.reserve_exact(additional) } + /// Shrinks the capacity of the `OsString` to match its length. + #[unstable(feature = "osstring_shrink_to_fit", issue = "40421")] + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + /// Converts this `OsString` into a boxed `OsStr`. #[unstable(feature = "into_boxed_os_str", issue = "0")] pub fn into_boxed_os_str(self) -> Box { diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index 0f967863899cb..474d59eed83d1 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -83,6 +83,11 @@ impl Buf { self.inner.reserve_exact(additional) } + #[inline] + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index 938bcfc6d162e..c27599ec0206f 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -83,6 +83,11 @@ impl Buf { self.inner.reserve_exact(additional) } + #[inline] + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 04e45dcf54963..b02b06e1ef2e1 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -89,6 +89,10 @@ impl Buf { self.inner.reserve_exact(additional) } + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + #[inline] pub fn into_box(self) -> Box { unsafe { mem::transmute(self.inner.into_box()) } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 1d61181a4ee0f..b486d4ffda3fd 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -236,6 +236,11 @@ impl Wtf8Buf { self.bytes.reserve_exact(additional) } + #[inline] + pub fn shrink_to_fit(&mut self) { + self.bytes.shrink_to_fit() + } + /// Returns the number of bytes that this string buffer can hold without reallocating. #[inline] pub fn capacity(&self) -> usize { From 992d99b4776bf7cbe69c49a7ea54275fbf89fc46 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 10 Mar 2017 07:21:28 -0800 Subject: [PATCH 69/73] Test fixes and rebase conflicts --- src/bootstrap/bootstrap.py | 2 +- src/bootstrap/doc.rs | 5 ++++- src/bootstrap/native.rs | 2 +- src/ci/docker/run.sh | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index b15bc77ec1365..b326f95e505fb 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -296,7 +296,7 @@ def get_toml(self, key): def get_mk(self, key): for line in iter(self.config_mk.splitlines()): - if line.startswith(key + ' :='): + if line.startswith(key + ' '): var = line[line.find(':=') + 2:].strip() if var != '': return var diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 9c3f0ce62f349..146f6ec7f1375 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -279,7 +279,10 @@ fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> { if m.file_type().is_dir() { try!(fs::remove_dir_all(dst)); } else { - try!(fs::remove_file(dst)); + // handle directory junctions on windows + try!(fs::remove_file(dst).or_else(|_| { + fs::remove_dir(dst) + })); } } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a7754f2669ef0..6cc1ca8d02ed0 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -58,7 +58,7 @@ pub fn llvm(build: &Build, target: &str) { } } if build.config.llvm_clean_rebuild { - t!(fs::remove_dir_all(&out_dir)); + drop(fs::remove_dir_all(&out_dir)); } println!("Building LLVM for {}", target); diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 437041e0292ca..b5a713dc38259 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -58,6 +58,7 @@ exec docker \ --env DEPLOY_ALT=$DEPLOY_ALT \ --env LOCAL_USER_ID=`id -u` \ --volume "$HOME/.cargo:/cargo" \ + --privileged \ --rm \ rust-ci \ /checkout/src/ci/run.sh From 384ee48a1a362a3886300f974739e5579ac998cd Mon Sep 17 00:00:00 2001 From: Geoff Yoerger Date: Fri, 10 Mar 2017 12:11:13 -0600 Subject: [PATCH 70/73] Clarify docs in `VecDeque::resize` --- src/libcollections/vec_deque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 8d42045ff1637..48a6c66db97eb 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1766,7 +1766,7 @@ impl VecDeque { impl VecDeque { /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len, - /// either by removing excess elements or by appending copies of a value to the back. + /// either by removing excess elements or by appending clones of `value` to the back. /// /// # Examples /// From dcfc7ee85319cc25638d20a938acaa6fe99a4073 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 10 Mar 2017 10:25:16 -0800 Subject: [PATCH 71/73] travis: Remove compiling OpenSSL through homebrew I don't believe that we need this any more now that `cargo-vendor` isn't installed to create a source tarball (that only happens on Linux) --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index fa6c9cf074864..04dc547d42f95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,9 +66,7 @@ matrix: osx_image: xcode8.2 install: > travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin && - chmod +x /usr/local/bin/sccache && - brew uninstall --ignore-dependencies openssl && - brew install openssl --universal --without-test + chmod +x /usr/local/bin/sccache - env: > RUST_CHECK_TARGET=dist RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended" From d854915fcef5ede86b96eefbf3bff18171763ef6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 10 Mar 2017 11:22:58 -0800 Subject: [PATCH 72/73] More test fixes and rebase conflicts --- src/bootstrap/config.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5e9ff98c4f25b..dcd49c51e3a99 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -469,12 +469,11 @@ impl Config { match key { "CFG_BUILD" if value.len() > 0 => self.build = value.to_string(), "CFG_HOST" if value.len() > 0 => { - self.host = value.split(" ").map(|s| s.to_string()) - .collect(); + self.host.extend(value.split(" ").map(|s| s.to_string())); + } "CFG_TARGET" if value.len() > 0 => { - self.target = value.split(" ").map(|s| s.to_string()) - .collect(); + self.target.extend(value.split(" ").map(|s| s.to_string())); } "CFG_MUSL_ROOT" if value.len() > 0 => { self.musl_root = Some(parse_configure_path(value)); From fdf48cd1f6e2fcbee710bd01a0898d27f292c957 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 10 Mar 2017 14:50:27 -0500 Subject: [PATCH 73/73] Update mdbook to new version This brings back playpen integration for the books. --- src/Cargo.lock | 6 +++--- src/tools/rustbook/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index f4174693a5771..b01831b6ba54e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -539,7 +539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.0.17" +version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -852,7 +852,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1603,7 +1603,7 @@ dependencies = [ "checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" "checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" -"checksum mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dbba458ca886cb082d026afd704eeeeb0531f7e4ffd6c619f72dc309c1c18fe4" +"checksum mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "06a68e8738e42b38a02755d3ce5fa12d559e17acb238e4326cbc3cc056e65280" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 40318141e04fa..d5b95c08306b2 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -8,5 +8,5 @@ license = "MIT/Apache-2.0" clap = "2.19.3" [dependencies.mdbook] -version = "0.0.17" +version = "0.0.18" default-features = false